Fetch & merge or rebase

A git pull defaults to git fetch followed by git merge origin/main (assuming that we are working on branch main and the remote is called origin). The following example compares this fetch-merge strategy vs. a fetch-rebase strategy.

Initial state

Elena and Marina collaborate on a project (hosted on GitHub). Elena has already pushed three commits (A, B and C). Marina has pulled them and pushed two commits of her own (D and E). Meanwhile Elena has committed F and G locally and has executed a git fetch. The state of the three repositories (on Elena’s and Marina’s local machines as well as the one on GitHub) at this point is depicted in the three tabs below. Note that, when visualizing Elena’s repository, we passed -R ..@{u} [1] to git dag which marks the commits reachable from origin/main but not from main.

Elena has to decide what to do about the diverging histories. Git provides two standard mechanisms to combine them: a merge and a rebase.

Visualize DAG
git dag -m 1 -l -r -H -u
Visualize DAG
git dag -m 1 -l -r -H -u
Visualize DAG
git dag -m 1 -l -r -H -u -R ..@{u}

Elena merges

If first Elena performs a merge (git merge origin/main) followed by a git push and then Marina executes git pull, the state of the three repositories would be as depicted below. Since a fast-forward merge is not possible (due to the diverging histories), a true merge is performed – it creates a new “merge-commit” m. Having such a merge-commit can be avoided if Elena rebases her work.

Visualize DAG
git dag -m 1 -l -r -H -u
Visualize DAG
git dag -m 1 -l -r -H -u
Visualize DAG
git dag -m 1 -l -r -H -u

Elena rebases

If, instead of a merge, Elena first performs a rebase (git rebase origin/main), the linear history of the repository would be preserved (for the current setup, this would be the preferred approach most of the time). Note how the rebase operation recreated Elena’s G and F commits (and preserved their messages) on top of Marina’s commit E. The original G and F commits are unreachable and can be found only on Elena’s machine. Comparing the tooltips of e.g., the two F commits we see that they have different “committer” dates and the same author date.

The fetch-rebase strategy can be enforced using git pull --rebase.

Visualize DAG
git dag -m 1 -l -r -H -u
Visualize DAG
git dag -m 1 -l -r -H -u
Visualize DAG
git dag -m 1 -l -r -H -u