gitrebasegit-rebasegit-history-graph

Git Rebase creating not linear history


The Git repository have only master and everyone is working on it (don't judge me, is a small thing so far) with the Rebase by default enabled. AFAIK git-rebase rewrite the history applying the commits one by one based on date and getting in MERGING state when needed during this process. But one thing is annoying me and the team, the history sometimes is not linear, follow some examples:

enter image description here enter image description here enter image description here

What would happening here? Or I misunderstand how git-rebase works?


Solution

  • The history is not based around dates, it is based around the underlying graph Git is based on. For example, your history could look like this:

                      branchA
                        ↓
    * -- * -- * -- * -- *
          \
           * -- * -- *
                     ↑
                  branchB
    

    Each of those * represents a commit in your history, but the actual date is completely irrelevant to the location in the graph. Let’s replace the stars with numbers to show the relative time they were created (larger numbers are created later):

                      branchA
                        ↓
    1 -- 2 -- 4 -- 5 -- 8
          \
           3 -- 6 -- 7
                     ↑
                  branchB
    

    This is a perfectly fine and “linear” (in terms of time) history on each branch. If you log the history for branchA, you get 8, 5, 4, 2, 1; for branchB you would get 7, 6, 3, 2, 1.

    Now, if you rebase branchB onto branchA, Git would rewrite those commits on branchB and apply them onto branchA. While rewriting, Git by default keeps the authoring time intact (but resets the commit time to the current time). So you would get the following result:

                      branchA
                        ↓
    1 -- 2 -- 4 -- 5 -- 8 -- 3' -- 6' -- 7'
                                         ↑
                                      branchB
    

    (The ' here denotes that they are actually different commits from the original ones, but they do have the same content and author time).

    If you now look at the log for branchB, you would get the following: 7', 6', 3', 8, 5, 4, 2, 1. And that’s exactly where the “time paradox” comes from: You do have a perfectly linear history (the graph is linear for this section); but the commits are not necessarily in the order they were originally authored.

    That’s perfectly fine and totally by design: Rebasing should not reset the commits completely, so the original author information (who did it, and when did they do it) is still there.