Merging is the process of combining different branches into a single branch. Merging is used when a developer is done working on a feature on some other branch and is ready to add that change to the project. The whole point of branching was to work on something in an independent environment but that work won't add any value to our project if we don’t merge it with the rest of the project.
What is Merge?
As discussed above, merging is the process of integrating multiple branches into a single one.
This is done to make sure that different branches that may have different features for the project are present on a single series of snapshots i.e. a single master branch.
Merge is also internally used by the Git Pull command that first fetches the remote repository and then merges it with the current.
How Merge Works?
Merge combines two separate branches into a single one but it uses two different strategies to do so based on the structure of the branches. Git automatically chooses the best strategy according to the situation. Let's take a look at these techniques.
Fast Forward Merge
This type of merge strategy is used when the two branches are on the same linear path. For a fast forward merge to work the two branches must not diverge from a single point. The branch from which a new branch was created should not have added any new commits. In this type of merge Git simply takes the branch which is lagging in the linear path and sets it equal to the reference of the leading branch. It is also sometimes called the Two Way Merge as it only involves two commits - the most recent ones from each branch.
Consider the following scenario in which we have two branches master and new_feature. We can see that there is a clear linear path between them.
Now when we merge the new_feature branch into the master branch, then the master branch reference will point to the new_feature reference.
Git uses this strategy when the two branches have diverged from a common ancestor. Both branches may have added some commits after splitting from that ancestor, so a linear path does not exist between them. Git performs this merge by first finding the common ancestor of both the branches and it then combines their individual commits into a single Merge Commit. This merge commit will have two parents, one for each branch. This helps in reverting back to any commit point of any one of the two branches. This method is called Three-Way Merge as it involves three commit points - the two most recent commits from the two branches and also an additional merge commit that is created.
Consider the scenario where we have two branches originating from the common ancestor B. We can see that there is no linear path between the branches.
When git merges these branches, it will create a new merge commit that will have the two branches' tips as its parents.
Conflict is a situation that arises when two developers have changed the same line of code in the same file or if one developer has deleted a file on which some other developer is working.
In the above cases, a merge is started by Git but the merge will fail during the execution. Git does not know which version to keep and which version to discard. So it stops the merge and leaves it up to the developers to manually resolve the conflict and decide which version of the file to keep.
Conflicts may also arise when there are pending changes in either the working directory or the staging area in a branch that we are trying to merge. In such cases, Git won’t be able to start the merge at all as merging may override the unsaved changes.
This is the reason why developers prefer to work in isolated branches and then merge the changes to the master branch instead of directly adding commits to the master branch. This is the best way to avoid conflicts in the first place.
The best way to resolve such conflicts is to communicate with the developers and decide on which version of the file they want to keep and alter the file accordingly.
After resolving the conflict, we need to add the file to the staging area and commit it.
Git also provides us some insight into these conflicts by altering the file which leads to the conflict. Git adds special characters <<<<<<<, =======, >>>>>>> to indicate the part of the file where conflict occurs.
Consider the following example to better understand merge conflict.
We created a file in the master branch with three lines and added a commit.
Then we created a new branch and changed the middle line in that file and added a commit.
Next, we went back to master and again changed the middle line and committed.
Now when we merge these two branches a merge conflict will occur.
All the content between <<<<<<< HEAD and ======= shows the changed content of the file in the current working branch. All the content between ======= and >>>>>>> newBranch shows the changed content of the file in the new branch that we created.
Git Merge Command
Git Merge command can be used with several other options to accomplish different tasks related to merging. Let's take a look at some of them.
To merge a branch into our current working branch simply pass the name of the branch to the Git Merge command.
$ git merge <branch-name>
We can also merge just a single commit to our working branch by using the Git Merge command. We need to pass the commit hash of the commit that we want to merge.
$ git merge <commit-hash>
We can use the --no-ff flag to tell Git to not use the fast forward merge technique even where it is possible. This will create a new merge commit.
$ git merge --no-ff <branch-name>
When a merge conflict occurs, we can use the --abort flag to stop the merge and restore the repository the way it was before the merge.
We can use the --squash flag if we don’t want the individual commits of the other branch to appear in the commit history of our current working branch(where we are merging changes). This combines all the commit points of the other branch into a single commit and adds it as a single commit to the history of commits of our current branch. We must use Git Commit for this commit to take place.
$ git merge --squash <branch-name>
$ git commit
The following image shows a squashed commit.
Merging is something that we will often do because merging is what helps us to add changes to our projects after working on the changes in other branches. There are two techniques through which branches are merged in Git. One is by Fast Forwarding in which we just update the lagging branch reference to point to the same commit as the leading branch. The other method, called the Three-Way Merge, is used when the branches are diverged and not linear. This method creates a new Merge Commit. We also learned how the merging of branches can sometimes lead to conflicts. The best way to resolve a conflict is by communicating with other team members to decide upon which version of the file to keep. I hope this tutorial was helpful and you learned something new.