Song of the Week
Introduction
Last week I briefly covered git merge
as part of a general overview of common git commands. This week I wanted to go into more depth on merge since it can be a little tricky. Hopefully I can help you avoid some of the confusion I've experienced in the past.
Topics Covered:
- Preparing for the Merge
- Fast-Forward
- 3-way Merge
- Merge Conflicts
- Deleting Branches
Preparing for the Merge
Before you execute a merge it's important to take a few steps to prepare.
- Step 1: Make sure your on the branch you want to merge into. If you're not sure which branch you're on, run
git status
. If you're on the wrong branch, rungit checkout <branch-name>
to switch to the correct branch. - Step 2: Make sure the branches you're merging are up-to-date with the latest remote commits. To do this, run
git pull
once you're on the branch you want to update. This is especially important if you're merging into a branch that you share with other developers.
Fast-Forward
There are two types of merges that Git will execute depending on the situation. The simplest is called “fast-forward.” A fast-forward is when Git just moves the tip of the receiving branch to point to the same commit as the tip of the merging branch. This happens when the tip of the branch you're merging into is a direct ancestor of the branch you're merging in. Let’s look at an example!
Diagram 1: Commit history before the fast-forward.
Let’s say we’re working with a simply git history like the one in the diagram above. In this example you have a master branch, and a feature branch that branched off at commit #3. We can see that even thought we’ve made two commits on our feature branch, no new commits have been made to the master branch. This means that the tip of the master branch is a direct ancestor of our feature branch. So, when we run git merge feature
, the commit history will look like this:
Diagram 2: Commit history after the fast-forward.
Notice that the tip of the master branch now points to the same commit as the feature branch. The fast-forward just moved the tip of the master branch up the linear commit history to point to the most recent commit.
3-way Merge
Often the commit history is not simple enough for Git to do a fast-forward. This is especially true when you are work on the same code base with multiple developers.
This is where the 3-way merge comes into play. Git performs a 3-way merge when the tip of the branch you’re merging into is not a direct ancestor of the branch you’re merging in. A 3-way merge is when Git creates a new snapshot of the code using the commits that the two branch tips point to and the common ancestor commit, and then creates a merge commit with the result. Again let’s look at an example to better understand what’s happening.
Diagram 3: Commit history before the 3-way merge.
In this example, the feature branch also branches off at commit #3, but this time the master branch tip is not pointing to a commit that is a direct ancestor of the feature branch. This can happen if you or someone else merged a commit into master after your feature branch was created.
To merge these branches we should have already switched to the master branch in the prepare step, so we can just run git merge feature
. Notice that is the same Git command, but this time a 3-way merge will result. Git will automatically perform a fast-forward or a 3-way merge depending on the state of the commit history.
After the 3-way merge the commit history will look like this:
Diagram 4: Commit history after the 3-way merge.
Take note of the fact that unlike a fast-forward, the master and feature branch tips do not point to the same commit after a 3-way merge. Master is now pointing to a merge commit that is a combination of the two branch tips and the common ancestor.
One last thing that should be said if it wasn’t clear. Merges don’t always have to go from a feature branch into the master branch. You can merge any branch into another other branch. So you could merge master into your feature branch, or feature_1 branch into feature_2. branch.
Merge Conflicts
Usually Git will automatically merge the files from both branches together. However, if the same part of a file has been changed in different ways on the two branches being merged, Git won't be able to merge them. In this case, Git will label the trouble spot as a conflict and will wait for you to resolve it. To see which files have conflicts you can run git status
. Then open those files in VS Code or whichever text editor you prefer. In the files you will see something like this:
<<<<<<<<HEAD:app.js
if (a < 0) {
b = 5;
}
==============
if (a < 0) {
c = 5;
}
>>>>>>>>feature:app.js
Above I created a hypothetical conflict that may have come up in the 3-way merge example we looked at before. The less than signs (<<<<<<<<
) mean that everything between them and the equal signs (=========
) is the code from the current branch (aka the branch you're merging into). On the bottom, the greater than signs (>>>>>>>>
) mean that the code between them and the equal signs (========
) is from the branch that you're merging in.
Once you decide which version to keep, or create a mix of the two, save the file. Once all the conflicts are resolved and saved, run git add <file-name>
on each file with a conflict. Or you can run git add .
, which will git add
all the modified files at once. Then just run git commit -m <type a message here>
with your commit message and your merge is done.
Deleting Branches
Now that your feature branch is merged into master you can delete it since it's changes have been incorporated into master. To delete a branch run git branch -d <branch-name>
.
So in the case of our examples, after the merge we would run git branch -d feature
.
Takeaways
-
Prepare for the Merge
- Make sure you're on the branch you want to merge into by running
git status
and runninggit checkout <branch-name>
if you need to switch to the correct branch. - Make sure the branches you're merging are up-to-date with the latest remote commits. To do this, run
git pull
.
- Make sure you're on the branch you want to merge into by running
-
Two Types of Merges can result from
git merge <branch-name>
- Fast-Forward: When Git just moves the tip of the receiving branch forward to point to the tip of the merging branch. This happens when the the tip of receiving branch is a direct ancestor of the merging branch.
- 3-way Merge: When the tip of the receiving branch is not a direct ancestor of the merging branch Git creates a new snapshot of the code using the commits that the two branch tips point to, and the common ancestor commit, and then creates a merge commit with the result.
-
Merge Conflicts
- If the same part of a file has been changed in different ways on the two branches being merged, Git won't be able to merge them and will label them as a conflict.
-
<<<<<<<<
: Everything between these less than signs and the equal signs (=========
) is the code from the current branch (aka the branch you're merging into) -
=========
: Separates the code from the receiving and the merging branches that is in conflict. -
>>>>>>>>
: Everything between these greater than signs and the equal signs (========
) is the code from the branch that you're merging in. - Once the conflicts are resolved in a text editor, run
git add .
andgit commit -m <type a message here>
.
-
Delete Branch
- To delete a branch run
git branch -d <branch-name>
.
- To delete a branch run
References
Basic Branching and Merging - Git Docs
Git Merge - Git Docs
Git Merge - Atlassian Git Tutorial
Git Pull - Atlassian Git Tutorial
Git Branch - Git Docs
Top comments (1)
Helpful, thanks ! ♥