Search code examples
gitgitlabversion-controlbitbucketrebase

How does a git pull --rebase work and what will show up in remote commit history?


I am working on a project. Suppose I clone a repository "my_repo" that has A->B->C commits. Locally I do a commit D on day 1 but do not push. Someone does a commit E on day 2 and pushes it making the commit history as A->B->C->E in the repo. When I do a git pull --rebase on day 3 my local commit history becomes A->B->C->E->D inspite of the fact that D was comitted two days earlier. I was expecting it to be in chronological order A->B->C->D->E. If I now push my changes to the remote branch, how will the commit history look like? Can anyone help with this.


Solution

  • git pull --rebase works by first running git fetch, then running git rebase to get your local commits on top of the newly fetched commits (simplified; it involves some reflog magic to find out which local commits need to be rebased).

    Initial history:

    A-B-C        < main, origin/main
    

    After local commit:

    A-B-C        < origin/main
         `-D     < main
    

    After fetch:

    A-B-C--E     < origin/main
         `-D     < main
    

    Rebasing will take your local commits that are not reachable from upstream and replay them on top of upstream. The only commit not reachable from upstream, but from your local branch is commit D. The latest commit in upstream is E. In other words: Git will replay the commit range E..D; which contains only D.

    After rebase:

    A-B-C-E      < origin/main
           `-D'  < main
    

    After push:

    A-B-C-E-D'   < main, origin/main
    

    Moving D before E means that you need to make Git forget about the original E, recreate D as D' on top of C and then create a new E' on top of D'. Then you need to tell everybody else who's working on the project to forget about the original E in their local clones and to get the new, rewritten commits instead.