Git Merge - how to use it and how to understand it conceptually

Let us say that you are working on an application that is similar to Reddit, but specifically for code snippets. In such an application, you would likely have a master branch which contains all the released features, a dev branch which might contain features that have been coded, but not implemented yet. Every developer in the team will create his own branches off the dev branch for individual features. The repository structure would look something like this:

                                  --- Commit 3 --------- dev branch 
 --- Commit 1 ---- Commit 2 ---------------------------- master branch

If you decided to merge the 3rd commit (Commit 3) into the master branch from the dev branch, then it would be as simple as running a git merge command because the dev branch is up-to-date with the master branch: all of the commits in the master branch exist in the dev branch. You can merge the branches by running the following commands:

git checkout dev
git merge master

The result would be something like this:

                                               --------- dev branch 
 --- Commit 1 ---- Commit 2 ---- Commit 3 -------------- master branch

Now you decide to work on the authentication feature. To work on the authentication feature, you create another branch based on the dev branch and decide to call it auth. This is what the repo structure looks like:

                                                  ------ auth branch
                                               --------- dev branch 
 --- Commit 1 ---- Commit 2 ---- Commit 3 -------------- master branch

If you were to commit any changes to the auth branch, merging them with the dev branch would be trivial because it is up-to-date with the dev branch. Now while you were working away on the authentication feature, one of the developers finished coding the syntax-highlighting feature, and decided to merge it with the dev branch. The repo looks like this now:

                                                  --- Commit 5 --- auth branch
                                               --- Commit 4 ------ dev branch 
 --- Commit 1 ---- Commit 2 ---- Commit 3 ------------------------ master branch

Your branch, in Git terminology, is now a commit behind the dev branch. This means that you cannot simply merge the two branches: you must bring your auth branch up-to-date with the dev branch. This can be done with git merge!

Merging the auth branch with the dev branch, or the dev branch with the master branch is straightforward and does what you expect, but merging the other way around has its own idiosyncrasies that are not intuitive at first blush. I can babble about it, or I can show you another great diagram of what would happen if you merged the dev branch with the auth branch at this moment:

                                                  --- Commit 5 ----------- auth branch
                                                /               /
                                               --- Commit 4 -------------- dev branch 
 --- Commit 1 ---- Commit 2 ---- Commit 3 -------------------------------- master branch

See what I did there? Look at the diagram for a second and try to understand what is happening here before you move on. You essentially made another commit to the auth branch with the commits in the dev branch included. But that’s all right, right? After all, at the end of the day I wanted to bring my auth branch up-to-date with the dev branch, and now it is up-to-date? Yep. But let me show you a diagram to explicitly illustrate what the other diagram implies: Your auth branch now looks like this:

    --- Commit 5 ------- Commit 4 ------- auth branch
  /                /
------ Commit 4 --- --------------------- dev branch

See it now? You copied the commit over. If you were to merge to the dev branch now, it would look something like this:

    --- Commit 5 ------- Commit 4 -------------------------------------- auth branch
  /                /                  \
------- Commit 4 ----------------------- Commit 5 ---- Commit 4 -------- dev branch

You merged the same commit twice! This will of course have no repercussions for your code itself, but if you one fine day decide to look at your git logs, you will immediately realize how dirty your git history is, with some commits being made over and over. If you wanted to revert to a commit, it would be very difficult to decide which commit to revert to.

Git Merge

The git merge command will merge any changes that were made to the code base on a separate branch to your current branch.

The command syntax is as follows:

git merge BRANCH-NAME

For example, if you are currently working in a branch named dev and would like to merge any new changes that were made in a branch named new-features , you would issue the following command:

git merge new-features

Please Note: If there are any uncommitted changes on your current branch, Git will not allow you to merge until all changes in your current branch have been committed. To handle those changes, you can either:

  • Create a new branch and commit the changes
git checkout -b new-branch-name
git add .
git commit -m "<your commit message>"
  • Stash them
git stash               # add them to the stash
git merge new-features  # do your merge
git stash pop           # get the changes back into your working tree
  • Abandon it all
git reset --hard        # removes all pending changes

Merge Conflict

A merge conflict is when you make commits on separate branches that alter the same line in conflicting ways. Therefore Git will not know which version of the file to keep

resulting in the error message:

CONFLICT (content): Merge conflict in resumé.txt Automatic merge failed; fix conflicts and then commit the result.

In the code editor Git uses markings to indicate the HEAD (master) version of the file and the other version of the file.

<<<<<<< HEAD

>>>>>>> OTHER

From the code editor delete/update to resolve conflict and remove the special markings including the HEAD and OTHER file names, reload your file, then re add and recommit your changes.

Points to Note

Whenever a merge is done, an extra merge commit is created. Whenever you are working in your local repository, having too many merge commits can make the commit history look confusing. One way to avoid the merge commit is to use git rebase instead. Git rebase is covered in the git-rebase section.

Rebase is a great functionality but it has some issues as well. Rebase basically alters the commit history. So if rebase is used in the remote repository then it can create a lot of confusion. As much as possible, run rebase only on a local repository.

Both git merge and git rebase are very useful commands and one is not better than the other.