DEV Community

Kenichiro Nakamura
Kenichiro Nakamura

Posted on • Edited on

git deep dive part 5: Merge branches

In the previous article, I explain how to reset to specific commit and how to recover branches. In this article, I explain how git merge works.

What is merge

Merge means take all changes from another branch to current branch. My current git log looks like this.

* 867d90c (HEAD -> dev) update hello.txt
* 367c2d0 Update news
* 2adbcac (test, master) Add doc folder and files
* 16f1fa8 commit hello.txt
Enter fullscreen mode Exit fullscreen mode

If I draw diagram, it should look like below.
Alt Text
Let's say I want to merge dev branch to master. This means I want to take commit 367c2d0 and 867d90c in master branch.

Fast forward merge

As I didn't add any change to master branch after dev branch is created, I can simply update master to point to latest dev commit 867d90c. git does this by default.

The merge results says "Fast-forward" as I expected.

gitDeepDive> git switch master
Switched to branch 'master'
gitDeepDive> git merge dev
Updating 2adbcac..867d90c
Fast-forward
 docs/news.txt | 1 +
 hello.txt     | 2 ++
 2 files changed, 3 insertions(+)
Enter fullscreen mode Exit fullscreen mode

When I check commit log, I see master simply points to the last commit of dev branch. So no additional commit was created.

gitDeepDive> git log --oneline --graph
* 867d90c (HEAD -> master, dev) update hello.txt
* 367c2d0 Update news
* 2adbcac (test) Add doc folder and files
* 16f1fa8 commit hello.txt
Enter fullscreen mode Exit fullscreen mode

Recursive Merge

Now, let's go back to original commit and add new commit.

git reset --hard 2adbcac
echo "welcome">welcome.txt
git add welcome.txt
git commit -m "Add welcome"
Enter fullscreen mode Exit fullscreen mode

Log shows I have new commit now.

gitDeepDive> git log --oneline --graph
* 7dce564 (HEAD -> master) Add welcome
* 2adbcac (test) Add doc folder and files
* 16f1fa8 commit hello.txt
Enter fullscreen mode Exit fullscreen mode

I updated the diagram. It's obvious that I cannot do fast forward merge anymore.
Alt Text

Let's see how git handles this. git does recursive merge, which create new commit and merge all three commits. As there are no conflict of the files, it was straight forward.

gitDeepDive> git merge dev
Merge made by the 'recursive' strategy.
 docs/news.txt | 1 +
 hello.txt     | 2 ++
 2 files changed, 3 insertions(+)
gitDeepDive> git log --oneline --graph
*   b7a0c29 (HEAD -> master) Merge branch 'dev'
|\
| * 867d90c (dev) update hello.txt
| * 367c2d0 Update news
* | 7dce564 Add welcome
|/
* 2adbcac (test) Add doc folder and files
* 16f1fa8 commit hello.txt
Enter fullscreen mode Exit fullscreen mode

Alt Text

When I see the last commit, it has two parents which makes sense.

gitDeepDive> git cat-file commit b7a0c29
tree 88344b6b3d368bb76a7eee38623d4d7c7373b1b6
parent 7dce564c4836680b13a2489ca542b95a3a9fbfc1
parent 867d90cd40fa498bb171e9c785f21fadd8d64754
author Kenichiro Nakamura <kenakamu@microsoft.com> 1588863956 +0900
committer Kenichiro Nakamura <kenakamu@microsoft.com> 1588863956 +0900

Merge branch 'dev'
Enter fullscreen mode Exit fullscreen mode

Conflict when merge

Let's simulate conflict situation. I update hello.txt and news.txt.

git reset --hard 2adbcac
echo "good morning" >> hello.txt
echo "additioal info for news" >> docs\news.txt
git commit -am "update docs"
Enter fullscreen mode Exit fullscreen mode

It creates new commit.

gitDeepDive> git log --oneline --graph
* c36490a (HEAD -> master) update docs
* 2adbcac (test) Add doc folder and files
* 16f1fa8 commit hello.txt
Enter fullscreen mode Exit fullscreen mode

Now I do git merge dev and it shows conflict.

gitDeepDive> git merge dev
Auto-merging hello.txt
CONFLICT (content): Merge conflict in hello.txt
Auto-merging docs/news.txt
CONFLICT (content): Merge conflict in docs/news.txt
Automatic merge failed; fix conflicts and then commit the result.
Enter fullscreen mode Exit fullscreen mode

I need to solve the conflicts. The easiest way for me to resolve the conflict is to use mergetool. I can specify any tool I want in config. I use Visual Studio code to resolve the conflict.

git mergetool
Enter fullscreen mode Exit fullscreen mode

When I run the command, Visual Studio Code runs automatically and asked me to resolve news.txt first.
Alt Text

I take all the changes and close VSCode, then another window opens for hello.txt.
Alt Text

After I resolve all conflict, then I can complete the merge.

git merge --continue
Enter fullscreen mode Exit fullscreen mode

I can edit the commit comment, but I just go ahead to close the editor. Now I see new commit added as expected.

gitDeepDive> git log --oneline --graph
*   a3d0879 (HEAD -> master) Merge branch 'dev'
|\
| * 867d90c (dev) update hello.txt
| * 367c2d0 Update news
* | c36490a update docs
|/
* 2adbcac (test) Add doc folder and files
* 16f1fa8 commit hello.txt
Enter fullscreen mode Exit fullscreen mode

Summary

The word "merge" sounds like it overwrite some files, but git won't. Git never change snapshot items, therefore, it simply creates new commit with merged blob. I will explain rebase, which is another merging technic in the next article.

Go to next article

Top comments (0)