When I learned about Git branching, all of the explanations involved graphics like this one from Git Branching – Basic Branching and Merging
Unfortunately, this is not how my brain visualizes Git.
Under the hood, Git uses a Directed Acyclic Graph (DAG) to relate commits to one another and the branches they belong to. These diagrams are a faithful representation of a DAG. Unfortunately, this is not how my brain visualizes Git.
Fortunately, I found that I could instead visualize Git commits and branches as stacks of building blocks.
Each Commit is a Block
Instead of visualizing each commit as a node in a DAG, I can visual each commit as a building block.
A Stack of Blocks Represents a Branch
When you are on a branch, you can type git log --oneline
to see the commits in that branch (see Improve Git Log to setup the alias git lg
to save yourself some typing). These commits are stacked one of top of another, like a stack of blocks. When a new commit is added, it appears at the top of the stack of blocks.
Examples of Branches as Stacks of Blocks
Here are two branches main
and feat/c
. Notice in both branches the first two commits are the same (with feat/c
having one additional commit, C
).
(main) (feat/c)
C
B B
A A
If we switch to the feat/c
branch and run git log --oneline
We can see that our branch feat/c
contains all of the commits of the branch main
. Git even labels where the main
branch ends within our branch.
Merging Branches
Using git merge
we can merge the commits from one branch into our current branch.
Let’s assume we are on the main
branch (we’ll indicate this with a *
)
(main*) (feat/c)
C
B B
A A
and we run git merge feat/c
. This will copy the commit(s) from feat/c
into our current branch (main
), in this case only C
needs to be copied over.
(main*) (feat/c)
C C
B B
A A
Fast-Forward Merge
Since all the commits from our main
branch already appeared inside our feat/c
branch, it was easy for Git to add the new commit(s) from feat/c
to the top of main
. This is the simplest type of merge, know as a fast-forward merge.
When Merging Gets Complicated
Unfortunately, things are seldom this simple. Perhaps while you were busy adding feature C
, someone else went ahead and introduced feature D
.
(main*) (feat/c)
D C
B B
A A
Because main
now contains a commit that does NOT appear in feat/c
we say the branches have diverged and we can NOT perform a fast-forward merge.
In this situation, if we switch to branch feat/c
and run git log --oneline
, we’ll see that our branch no longer contains all of the commits from main
(the branch label main
no longer appears in our output).
Dealing with Diverged Branches
When faced with two branches that have diverged (preventing you from performing a fast-forward merge) you have two options:
- Perform a Git Rebase
or - Create a Merge Commit
Leave a Reply