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
If I draw diagram, it should look like below.
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(+)
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
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"
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
I updated the diagram. It's obvious that I cannot do fast forward merge anymore.
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
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'
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"
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
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.
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
When I run the command, Visual Studio Code runs automatically and asked me to resolve news.txt first.
I take all the changes and close VSCode, then another window opens for hello.txt.
After I resolve all conflict, then I can complete the merge.
git merge --continue
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
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.
Top comments (0)