Working with Git and Visual Studio – Understand Git Merging and Merging changes

This post is part of the series of posts on the Git and Visual Studio where we are discussing in detail on meaning of basic git operations, how to do them in Git and Visual Studio both and understand the difference of both tools. You can find the previous blog post here.

In this blog post, we’ll learn what is merging, types of merge and how to do the same from git command line.

What is Git Merge

Git merging is way of combining the commits made in separate git branches. It is used by git pull command as well to incorporate committed changes from one branch to another branch. 

Do note that merging happens to the currently checked out branch or simply current branch. After merge, the current branch will be updated to reflect the merge, but the source branch will remain completely unaffected. Also this means that first we need to checkout the receiving branch and make it a current branch.

How Git Merge Works

When we try to merge two branches in Git, first thing it does it to find last common commit between two branches. Once it does that, it determines the merging algorithm that’s best suited to current merge scenario and finally makes the merge commit. Merge commits are unique against other commits in the fact that they have two parent commits.

If Git encounters a file that is changed in both branches, it will be unable to automatically combine them and therefore needs user intervention, which we would see how to resolve later.

Precautions before merge

Below guidelines are generally required to be done before doing merge:

  1. Commit your changes in the source branch or the provider branch. Git merge only brings committed changes to receiving branch.
  2. Checkout the receiving branch. Also use git status to make sure head is correctly pointing to receiving branch. Also make sure there are no uncommitted changes in the receiving branch.
  3. Get latest from git remote, if any. Execute git fetch followed by git pull or do git pull directly.

Fast-forward merge

A fast-forward merge can occur when there is a linear path from the current branch tip to the target branch. Instead of “actually” merging the branches, all Git has to do to integrate the histories is move (i.e., “fast forward”) the current branch tip up to the target branch tip. This effectively combines the histories, since all of the commits reachable from the target branch are now available through the current one.

For example, moving back to our ConsoleApp02 Project, consider below git log history:

git history before merging
git history before merging

We can see that HEAD is pointing to a branch named newQuickFix branch (so it’s the current branch) and it basically contains two commits bbaad7b and 5bec225. In this case, these two commits are on the top of the master branch commit 42b9d40. So it’s easier for git to just move the HEAD pointer to the latest commit in case of merge.

Perform fast-forward Merge

Continuing above example, let’s say we need to bring changes made to the newQuickFix branch to the master branch. First, let’s make sure that there are no uncommitted changes to current branch newQuickFix:

check status of newquickfix branch

Checkout the receiving branch (master branch in this case):

checkout master branch (receiving branch in this case)

Let’s verify that HEAD is now pointing to master branch and there are no uncommitted changes in master branch as well:

check status of master branch

Finally, perform the fast forward merge:

perform fast forward merge

Note the output highlighted in above pic. It is clearly mentioning the type of merge used by Git. Now, let’s review git log to check our commit history:

reviewing git log history after ff merge
reviewing git log history after ff merge

Note that we lost the commit history from the newQuickFix branch and we cannot tell what changes were incorporated from newQuickFix branch.

Track commits incorporated during merge

To keep track of incorporated changes during merge for record keeping purposes, we need to specify that we do not want fast forward merge by using –no-ff flag. In this case, merge is performed using recursive strategy.

For example, reviewing above case, let’s merge change using below command:

merge commits using recursive strategy
merge commits using recursive strategy

If we now see git log history, we can see there is an extra ‘merge’ commit made as 9f75e8f:

reviewing git log history after recursive merge

Again, we seem to have lost the changes being incorporated. However, that’s not the case. To see that, we need to issue git log command with –graph flag:

reviewing git log history after recursive merge - 2

In above output, we can clearly see that we brought two commits from the newQuickFix branch.

3-way Merge

Most of the time what happens when multiple developers are working on the same project, before you can merge your code to master branch, it has already moved forward containing work of other developers. Note that it’s impossible for Git to perform a fast-forward merge in this scenario.

For example, moving back to our ConsoleApp02 Project, consider below git commit history from master branch:

git commit history before 3-way merge

In this case, we have added a Class07.cs file in the commit 2a262f9 in master branch.

Perform 3-way merge

Again, as specified above, since both of our branches i.e. newQuickFix branch and master branch have moved ahead, there is no way for git to perform fast forward merge. So by default it will merge using recursive strategy only:

merge commits using 3-way merge
merge commits using 3-way merge

Note the git commit history as below:

reviewing git log history after 3 way merge

In above output, we can clearly see that we brought two commits from the newQuickFix branch. Along with that, it also made 2a262f9 a part of merge commit.

What are Merge Conflicts

Occasionally, this process doesn’t go smoothly. If you changed the same part of the same file differently in the two branches you’re merging together, Git won’t be able to merge them cleanly. At this point, Git will no longer perform auto merging.

To reproduce above scenario, we’ll add a file named Class06.cs to master branch and commit our changes. Note from our previous blog posts that we have also modified this file in the newQuickFix branch. Let’s review the commit history of both branches.

From newQuickFix branch:

git history before merging
git history before merging

And from master branch:

git history for master branch before merge conflict

Let’s try to merge and observe conflict:

Observing git merge conflict
Observing git merge conflict

Git hasn’t automatically created a new merge commit. It has paused the process while user needs to resolve the conflict. If we want to see which files are causing issue, we can run git status:

view files causing the merge conflict

Resolve Merge Conflicts

When Git encounters a conflict during a merge, It will edit the content of the affected files with visual indicators that mark both sides of the conflicted content. These visual markers are: <<<<<<<, =======, and >>>>>>>. Its helpful to search a project for these indicators during a merge to find where conflicts need to be resolved.

For example, in our case it would be like this:

view content of file causing merge conflict

Generally the content before the ======= marker is the receiving branch and the part after is the merging branch.

Now knowing this info, we can go in and fix up the merge to our liking. To finish the merge once we are done changing file, all we have to do is run git add on the conflicted file(s) to tell Git they’re resolved. Finally, we can do simple git commit to complete merge:

resolve merge conflict and view git history
resolve merge conflict and view git history

In next blog post in this series, we’ll learn how to merge commits inside Visual Studio.

One thought on “Working with Git and Visual Studio – Understand Git Merging and Merging changes

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s