gitgit-mergegit-rebasefast-forward

Git Merge Fast-Forward vs Git Rebase


What is the difference between a fast-forwarded git merge and a git rebase? Don't both accomplish keeping history linear and no merge commits? If so, why would one use one over the other? If not, which is what I think is true, what is the whole story that I'm not seeing?

Thanks!


Solution

  • When you are ahead of main, both do the same thing.

    If you're ahead and behind main, then a fast-forward merge isn't possible, since there are newer commits on master. But in that case, you can rebase, creating new commits based on the commits that are ahead of main.

    When you're ahead of main:

                *E-*F-*G-*H-*I    BRANCH
               /
    *A-*B-*C-*D                   MAIN
    

    When you do a fast forward merge the main pointer is moved forward to the tip of the branch. When you rebase each commit of the branch is moved after the head of MAIN. The end result is the same:

    *A-*B-*C-*D-*E-*F-*G-*H-*I MAIN | BRANCH
    

    When you are ahead as well as behind of MAIN:

                *E-*F-*G-*H-*I    BRANCH
               /
    *A-*B-*C-*D-*J-*K             MAIN
    

    Then you can't fast-forward merge E..I into main, since J..K are in the way. So fast-forward isn't possible in this case.

    But you can rebase E..I onto K:

    *A-*B-*C-*D-*J-*K-*E'-*F'-*G'-*H'-*I'             MAIN | BRANCH
    

    But what happens is that a new commit is made containing the changes of E and appended to main, then a new commit is made with the changes of F and appended to main... etc etc until all commits from the branch have been "moved"/"replayed" on the other branch. The result is again a single line of history with no branches and merges.

    Because the commits had to be re-applied and conflicts potentially resolved, the actual commits will change, a new commit-id generated etc.