A simple explanation of git-rebase

 Posted by on December 2, 2011  General  Add comments  Tagged with: ,
Dec 022011
 

Using git-rebase without actually understanding what it does can cause headaches for you and the developers you’re working with. I don’t like headaches, so let’s take a minute to review what exactly git-rebase does.

Let’s say master is at commit C, and you create a branch feature/my-topic. So you have two branches pointed at the same commit like this:

           feature/my-topic
         / 
A---B---C master

Next, you make two commits D and E in feature/my-topic and push it to your origin (we’ll say GitHub):

           D---E feature/my-topic
         / 
A---B---C master

Meanwhile, let’s say master also gets two commits, D' and E':

           D---E feature/my-topic
         / 
A---B---C---D'---E' master

So now you want to rebase your feature/my-topic branch onto master, so you run git rebase master. The result is this:

                    F---G feature/my-topic
                  / 
A---B---C---D'---E' master

The key here is to recognize that commits D and E from feature/my-topic no longer exist, and have been re-written as F and G respectively, with master’s HEAD (E') as the new base. This means that some history has been re-written. Because of this, if you were to try running git push origin feature/my-topic, you would be greeted with a non-fast-forward error. Instead, if you really need to push the rebased branch up to your origin, you’ll need to run git push -f (see note below).

DO NOT PULL, MERGE, OR REBASE FROM origin/feature/my-topic AT THIS POINT!!!

Why not? Because Git simply thinks, “Oh look, origin/feature/my-topic has two commits (D and E) that we don’t have here locally in feature/my-topic. Let’s merge them in!”… That’s a problem though, because we do have those commits, but their hashes were re-written to F and G when we ran git rebase.

So what would happen if you actually did merge? Your history would look something like this mess:

                    D---E---X---F--G feature/my-topic
                  / 
A---B---C---D'---E' master

In the above result, D is a duplicate of F, E is a duplicate of G, and X is a useless merge commit gluing the whole mess together. Using git-rebase may avoid the merge commit, but you’ll still have those pesky duplicates, so you’re no better off.

NOTE: If there are other developers deriving work from your feature/my-topic branch that is pushed; you must be careful about performing a git push -f, as it can cause problems for those other developers. Also, git push -f can be a somewhat destructive operation if used carelessly. In the context I described, it should be pretty safe, but unless you have a specific reason, it’s generally better to just leave it to the person merging your pull request to perform the rebase locally on their end. This results in master being able to simply fast-forward to the new commit (guaranteed no merge conflicts when merging into master) and no re-written history is forcefully pushed to any public repositories.

  4 Responses to “A simple explanation of git-rebase”

  1. this explains git rebase a bit more but does not tell me what commands to follow, it seems I am now more doubtful about how to do things right when working on a PR etc

    • Yeah, this post was mostly meant to help you feel confident that you really understand what it is that git-rebase is doing, why git-push won’t work properly after a rebase if you’ve already pushed any of the rebased commits, and most importantly, how to avoid one of the most common problems I’ve seen with people using git-rebase (the duplicate commit problem). In part 2 of my Keeping a clean GitHub fork series, I will be covering a workflow for using git-rebase successfully when working on a branch that is destined for a pull request, which sounds like what you’re looking for.

  2. Thanks for this post.

    Regarding forced pushes, I wrote a blog post few months ago explaining why is “push -f” default behavior dangerous and how to make it safer: http://www.dinduks.com/git-more-control-over-git-push/

  3. ニクソン 5130 ニクソン 新作 http://www.do06.com/

 Leave a Reply

(required)

(required)

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre user="" computer="" color="" escaped="">