Let’s look at how to resolve two Git branches that have diverged by creating a Git merge commit (your other option in this situation is to perform a git rebase).
As discussed in Visualizing Git Branching with Blocks, we can’t do a fast-forward merge when the most recent commit on the receiving branch (e.g. commit C on main) does not appear in the branch we are merging in (e.g. branch feat/d).
(main*) (feat/d)
C D
B B
A A

A Commit with Two Parents
As discussed in What is a Git Commit?, a commit includes a bunch of information including the commit hash that came directly before it (the parent commit).
Typically, a commit has exactly one parent. In the case of a merge commit, there are multiple parents.
After running git merge feat/d to merge feat/d into main, Git will create commit (MERGE) which has both C and D as parents).
(main*) (feat/d)
MERGE
C D D
B B
A A
This allows us to merge these branches that have diverged without rewriting either of their history.

Git Log Display Merge Commits
To get a clearer picture of the situation we add --graph to our git log --oneline command
git log --oneline --graph
* 154382e (HEAD -> main) Merge branch 'feat/d' into main
|\
| * 163fe29 (feat/d) D
* | 5d408f9 (feat/c) C
|/
* 2b3a38b B
* ec6a2c7 A
Here we can see our merge commit (154382e) has two parents 5d408f9 (from feat/c) and 163fe29 (from feat/d).
Tracing back through this graph we can see the branches diverged after commit B (2b4a38b).
Spacers in the Git Log Graph
Even though commits C and D are adjacent to each other in Git, they are not displayed that way with git log --oneline --graph. Spacers (|) are included in the output while the commit is noted with an asterisk (*). While visualizing this with blocks, I like to think of transparent blocks for the spacers.

View the Parent Commits
We can see the under the hood details of our merge commit (154382e) with
git cat-file -p 154382e
tree 62feee95ffe3c1d6a738d35dac3da1d27a68abe9
parent 5d408f929e4c596d007532725abfd592b293dfb3
parent 163fe29d91b2ff43d4c724934836617ca619fa25
author Sal Ferrarello <sal@example.com> 1613264290 -0500
committer Sal Ferrarello <sal@example.com> 1613264290 -0500
Merge branch 'feat/d' into main
In the above output, we can see there are two parent commits. The first is 5d408f9 and the second 163fe29. These values match those that we see when we run git log --oneline --graph.
Merge Conflicts
Since our branches have diverged, it is possible we will have a merge conflict when we create our merge commit. To resolve our merge conflict we find the locations in our code with merge conflict markers (<<<<<<< and >>>>>>>) and correct this code.
After the code is corrected, we stage our changes with git add and then complete the merge with
git merge --continue
History is not Rewritten
The biggest advantage of using a merge commit (over a rebase) is it does not rewrite your history. You can now push your changes to a server without overwriting history.

Leave a Reply