Other consequences of `git push –force`?

To complement torek’s excellent answer:

A force-push can cause problems with later merges.

The problem:

If you force-push a branch A, you are removing some existing commits from that branch (otherwise you would not need to force). If (as described in torek’s answer) these commits are also referenced from another branch B, then they will remain in that branch. If you later later merge the two branches A and B, A will contain the “new” (forced) commits, and B “old” commits.

In this situation git merge will probably not do what you want. In the best case, you will get merge conflicts. Worst case, you will not but the result will still be wrong. For example, if you removed a commit c1 from A using git rebase -i, if c1 is also in B it will be re-introduced if you merge A and B. That might silently re-introduce a bug :-(.

So if you force-push, make sure the commits you remove are not referenced from other branches / tags (or force-push these branches/tags as well).

Illustration of a deleted commit “returning”

Run the bash script below. The script creates a git repository, and branches master, branch1 with the following commits:

  • good commit (branch1)
  • bad commit (master)
  • Initial

Then it:

  • uses git reset --hard to discard “bad commit” from master
  • merges branch1 into master

Output from the script:

Initialized empty Git repository in ....
[... creating commits ...]
### Bad commit in history:
* 7549dcc (HEAD, master) bad commit
* 31afec8 Initial
### Removing bad commit:
HEAD is now at 31afec8 Initial
### Bad commit no longer in history:
31afec8 (HEAD, master) Initial
### Merging branch1:
Updating 31afec8..be801e5
 0 files changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 b
 create mode 100644 c
### Bad commit is back!
be801e5 (HEAD, master, branch1) good commit
7549dcc bad commit
31afec8 Initial

As you can see, “bad commit” is removed from master using git reset --hard. However, “bad commit” is still contained in branch1, so when branch1 is merged into master, “bad commit” returns.

Note: This example does not actually force-push, but if you worked with an upstream repo, you would have to force-push after removing the bad commit – the result would be the same.

The script:

set -e
if [ -e gitrepo ]; then echo "Please remove gitrepo"; exit 1; fi

git init gitrepo; cd gitrepo; git config core.pager cat
touch a; git add a; git commit -m Initial
touch b; git add b; git commit -m "bad commit"
git checkout -b branch1; touch c; git add c; git commit -m "good commit"
git checkout master

echo "### Bad commit in history: "
git log --oneline --decorate

echo "### Removing bad commit: "
git reset --hard HEAD~1

echo "### Bad commit no longer in history: "
git log --oneline --decorate

echo "### Merging branch1: "
git merge branch1

echo "### Bad commit is back!"
git log --oneline --decorate

Leave a Comment