Friday, August 28, 2009

git rebase for the Impatient

Let's say you created a branch from the commit foo, and then committed the change bar:

While you were working on that somebody committed baz and pushed it to the upstream master:

Here is the graph of the divergence:

You now have two choices.

If you use git pull that will automatically merge master into your branch:

If you use git pull --rebase that apply your bar commit on top of the upstream, avoiding the extra merge commit and creating a linear history:

If you're used to subversion, this is very similar to what running svn up before svn commit does.

At this point you can push your work, and no evil manage will "break" your branch. Using git pull --rebase is a safe and natural fit when using a shared git repository.

Note that rebase will recreate those commits, there are two commits called bar, one whose parent baz, and one whose parent is foo which is still available in git reflog branch:

The above images are screenshots from the lovely GitX. They are actually lies, I created branches called rebase, merge and ancestor for clarity. gitk and git log --decorate both provide similar visualizations with decreasing levels of shiny.

You can read more on why I think rebase is awesome or make git pull use --rebase by default.

Lastly, if you want to learn more, try reading Git from the bottom Up, Git for Computer Scientists, and the Pro Git book's chapter on rebasing amongst other things.


Anonymous said...

I'm deeply sorry about that spurious MXRP merge commit. I walked away from my computer before you urged me to quickly fix it.

nothingmuch said...


Ian Monroe said...

If you are working on a published feature branch, then git pull --rebase (and certainly git pull --rebase by default) is a bad idea, because then you must do git push -f to publish the branch and anyone else with unpushed code to the branch will be screwed.

So git pull --rebase works in the simple "work on some commits, and then push to master" case, but its not so hard for things to become more complicated.

So people should use git pull --rebase, but they certainly shouldn't do it by default.

nothingmuch said...

no, git pull --rebase doesn't require push --force.

if you always rebase against the upstream (since this is a tracking branch) the only commits that are being rebased are those that haven't been published.

after pull --rebase the push will always be a fast forward.

nothingmuch said...

to clarify, note that the 'baz' commit is never altered by pull --rebase, only the 'bar' commit, which is unpublished is replicated.