When should I force push after rebasing?

tl;dr: assuming it’s your own branch, immediately.

On the last few projects I have been a part of, I have been the defacto Git problem solver.

XKCD Git Comic
(obligatory xkcd)

On more than one occasion, I was presented with something like the following:

$ git l master
* 232e985 (origin/master, origin/HEAD, master) Feature 4
* 94989d0 Feature 3
* 296d0b3 Feature 2
* 4b856cd Feature 1

$ git l feature-5
* 5c31f6d (HEAD -> feature-5) Feature 4
* 420f83b Feature 3
* 724236a (origin/feature-5) Feature 5
* 296d0b3 Feature 2
* 4b856cd Feature 1

In the above, the commits adding features 3 and 4 on each branch are logically the same, but on the feature-5 branch they’ve somehow ended up after the commit adding feature 5.

The team was using feature branches, and the author of feature 5 above was trying to rebase their changes onto master, but somehow ended up inserting their commit between commits on master. At this stage, you’re in a pretty bad place, as you’ve diverged from master.

How did this happen? I’m guessing it was the following series of events:

  • Developer branches from master to create feature-5
  • Features 3 & 4 are pushed to master
  • Feature 5 is committed to the feature-5 branch
  • Developer runs git pull --rebase origin master or similar
  • … some time passes …
  • Developer runs git pull --rebase without really thinking about it

After the first few steps above, we have something like the following:

Commits after creating feature branch

So far, so good. We want to rebase our changes onto master, so that we can test and push our code. After git pull --rebase origin master:

Commits after rebasing onto master

Still looking good. At this stage, we could git push --force origin feature-5 and all would be well in the world.

But what happens if we go for a tea and forget what we were doing (or we use an overzealous git GUI tool), and we try to rebase onto origin/feature-5?

Commits after rebasing from our remote branch - shows duplicate commits

What we see above is the result of Git rebasing commits 94989d0, 232e985 and 44e1c44 on top of origin/feature-5. As the commit ID is computed by hashing of the contents of a commit and its parent, the same logical commits from master now exist on our branch with different IDs.

This could have been avoided if we followed this rule of thumb:

If you’re working on your own branch, always push immediately after rebasing.

Some people on the team were seeing a message like the following:

Your branch and 'origin/feature-5' have diverged,
and have 3 and 1 different commits each, respectively.
  (use "git pull" to merge the remote branch into yours)

and assuming that they should git pull --rebase, which in this case is exactly what you don’t want.

If you’re looking for further reading Getting Started - Git Basics covers the fundamentals and LearnGitBranching is a great interactive tool.

Diagrams were created using Gitgraph.js, and this script creates an example repository.