Git
git merge

git merge command: conflict resolve, rebase squash differences, merge strategies

In this article we'll cover the git merge method. From how to merge to resolving conflicts, merge commit features, merge strategies, differences from rebase and squash, and other options for the git merge command.

1. How to merge a branch

The git merge command is used to merge one branch into another.

In the git branch post I mentioned that the branch name is the last commit on that branch. By the same token, merging branches ends up creating a new commit that has all the changes from the last commit of both branches, You can also think of it as a new commit to the working branch where you ran the git merge command.

The git merge command always performs the merge commit in the branch where it is created. For example, if you were merging the feature-a branch from the main branch, you would use a command like this

$ git switch main
switched to branch 'main'
 
$ git merge feature-a
Merge made by the 'ort' strategy

In the example above, you can see that we used the merge-ort strategy, which is Git's latest default merge strategy, changed in 2022.

1.1. ort strategy

Before moving on to the next section, let's take a quick look at Git's newest merge algorithm, the ort strategy.

The ort stands for "Ostensibly Recursive's Twin", meaning that it was created to replace the old default algorithm, the recursive strategy. Compared to the recursive strategy, it is said to reduce conflicts and take care of renamed files.

It is basically based on the 3-way merge algorithm, which compares changes from three sources: the same ancestor commit from both branches, the most recent commit from both branches, and the most recent commit from both branches, and then performs a merge. When merging two branches, we will mainly use the ort strategy, because it performs better than the previously used resolve and recursive strategies.

Other strategies worth knowing are the octopus strategy for merging two or more branches, or the subtree strategy for merging into a subdirectory. For now, let's just get familiar with the names.

These strategies can be specified with the -s or --strategy option, as follows.

$ git merge -s recursive feature-a

2. How to resolve a merge conflict

A merge conflict occurs when the same line in the same file on two different branches has different content. To preserve data, Git will never arbitrarily delete something unless you give it an option in the strategy. Instead, it will pause the merge and give us a choice.

Let's see this in action.

First, we modified the 1.md file with different content in the main and develop branches. Then, when we go to the main branch and try to merge the develop branch, we get a merge conflict.

Create merge conflict

If you're new to the -a option of the git commit command, see git commit post.

At this point, Git will add symbols like <<<<<<< HEAD, =======, >>>>>>> branch-name to the contents of the conflicting files to let you know exactly what needs to be fixed. Let's open the 1.md file.

merge conflict situation

This is the 1.md file opened in the Neovim editor. We just need to keep what we want in this part, remove the symbols Git added, and proceed with the commit.

Merging is even easier in an editor that supports Git, like VSCode. The highlighting is intuitive, and pressing the button for the four sentences above <<<<<<< HEAD will automatically remove the excluded content and Git's symbols.

vscode merge conflict situation

After modifying the content, complete the merge with the git commit command like a normal commit.

git merge conflict resolved

3. Difference from rebase

The git merge and git rebase commands have something in common: they are both ways of merging two branches and resolving merge conflicts. However, there are differences in the way they work, and it's important to understand them so you can choose the right one for your needs.

The git merge command creates a new merge commit with the last commit of the two branches as its parent, as shown above. As a result, there are commits in the commit history that correspond to two branches together. The feature-a, feature-b, etc. paths come and go on the main path, called the main branch.

The git rebase command merges the two branches so that there are no dead ends in the commit history. How this works is easier than you might think. Let's take a look at the image below.

git rebase explained

Assuming you want to merge the feature-a branch into the main branch, which diverged from a common ancestor commit A, the git rebase command creates a new commit with the same changes as the commit in feature-a. In the figure, these are commits C and D.

These two commits are then appended to B, the last commit on the main branch. This creates a single commit history, but with the result that all changes in the feature-a branch can be merged into the main branch. The history is also simpler, since we don't have to create a new merge commit.

However, it's not easy to tell at a glance whether commits C and D are merged commits from different branches, or commits that were previously in the main branch. So from a history perspective, you're losing information.

For this reason, you should use merge and rebase in appropriate situations, depending on the direction your team is taking. For more information on the git rebase command, see this post.

4. Difference from squash

Squash is a concept in Git that compresses multiple commits into one. It does not exist as a separate command, but can be used as an option to the merge or rebase commands. When the git merge command is used with the --squash option, it is called a squash merge.

Let's look at the image below to understand squash merge.

Understanding squash merge

In the current commit 8c12, the main and develop branches are split. I tried a squash merge on the main branch, and it went through without a hitch.

The result of the git status command below shows that all commits from the develop branch have been staged on the main branch.

git squash merge execution result

If you check the history since the commit, you'll see that the develop branch remains unmerged, but its changes have been registered as new commits in main. This is what a squash merge does.

The squash option can also be used during the rebase process, with the difference that the history of the develop branch is not left as above. We'll cover this again in the rebase post.

5. Final thoughts

I think merge conflicts are one of the first things Git beginners get stuck on. However, merging and merge conflict resolution are at the core of Git collaboration, so it's important to understand and master them. I hope this post helps you get started.

copyright for git merge

© 2023 All rights reserved.