Git tries really hard to not overwrite any of your changes, so in your day-to-day routine, if you attempt to push to a remote repository whose HEAD reference differs from your local HEAD reference, Git will pitch a fit about it.
When you use --force
, Git takes the training wheels off and assumes that you know what you're doing, even if you don't fully understand or appreciate the ramifications of your actions.
To illustrate your example, this is what your remote repository has on it:
<-- [] <-- [] <-- [HEAD]
...and this is your local after you've pushed, but before you discovered your mistake:
<-- [] <-- [] <-- [HEAD]
When you went to correct the mistake by using --amend
, Git actually has two commits that refer to the previous one, but only one of them refers to the canonical HEAD reference.
<-- [] <-- [] <-- [HEAD]
\
\<-- [(old HEAD)]
The SHA of your new HEAD reference doesn't match what's on your remote repository, so Git will refuse to push since it thinks you're going to lose data.
When you force it, though, Git trusts you and takes the new HEAD as the canonical reference. Through this, the reference to the old HEAD commit is lost.
<-- [] <-- [] <-- [HEAD]
This is dangerous since:
You could have lost data; the likelihood is that you didn't if it's a simple --amend
, but it's still possible
Anyone else that's based their work off of the old HEAD reference now has to rebase their work, which can make for a lot of undue heartburn.
Communication can mitigate the second piece, but the first piece requires a bit more caution when force-pushing. Only force-push if you're absolutely certain that what you're pushing won't cause a loss in data or information.