A merge in Git is a way to bring a forked commit history back together. git merge
command is used to combine the branch you created with the git branch
command and the content independently developed on this branch into one branch.
Please note that all commands below will merge other branches into the current working branch. The contents of the current working branch will be updated due to the merge operation, but the target branch will not be affected at all. Again, this means that git merge
is commonly used with several other git commands, including the git checkout
command to select the current working branch, and the git branch -d
command to delete an obsolete branch that has already been merged.
how it works
git merge
will merge multiple commit sequences into a unified commit history. In the most common usage scenario, git merge
is used to merge two branches. In the rest of this document, we'll focus on this merging scenario. In this scenario, git merge
takes two commit pointers, usually the top commit of both branches, and then works backwards to the nearest common commit of the two branches. Once this common commit is found, Git creates a new "merge commit" that merges the respective commit sequences on the two branches.
Say we have a feature branch that was forked from the main
branch, and now we want to merge this feature branch back into the main
branch.
Executing the merge command will merge the specified branch into the current working branch, we assume the current working branch is main
. Git decides its own algorithm for merging commits based on the two branches (discussed in detail below).
A merge commit is not the same as a normal commit because a merge commit has two parent commits. Git will try to automatically merge two separate commit histories into one when creating a merge commit. But when Git finds that a piece of data has changes in both commit histories, it won't be able to automatically merge it. This situation is known as a version conflict, and Git requires human intervention to proceed with the merge.
ready to merge
Before the actual merge operation, some preparatory steps are required to ensure that the merge process can go smoothly.
Acknowledgment to receive merged branch
Execute the git status
command to check the status of the current branch, and make sure that HEAD
points to the correct branch that received the merge. If not, execute the git checkout
command to switch to the correct branch. In our example, git checkout main
is executed.
Get the latest remote commit
Make sure that both branches involved in the merge operation are updated to the latest state of the remote repository. Execute git fetch
to pull the latest commit from the remote repository. Once the fetch operation is completed, in order to ensure that main
branch is synchronized with the remote branch, the git pull
command needs to be executed.
merge
When the preparations mentioned above are complete, the merger can officially begin. Execute the git merge <branch>
command, where <branch> is the name of the target branch that needs to be merged into the current branch.
Fast forward merge
Fast-forward merges are possible when the commit history between the current working branch and the merge target branch is a linear path. In this case, instead of actually merging the two branches, Git just needs to move the top pointer of the current branch to the top of the target branch (that is, fast-forward). In this case, the fast-forward merge successfully merges the commit history into one place. After all, the commits in the target branch are now included in the commit history of the current branch. For the process of fast-forward merging the feature branch into the main
branch, please refer to the following figure:
However, fast-forward merges are not allowed when two branches are forked. When the commit history of the target branch is not linear relative to the current branch, Git can only decide how to merge the two branches through the three-way merge algorithm. The three-way merge algorithm requires the use of a dedicated commit to combine the commit histories on both sides. The term comes from the fact that Git uses three commits to generate merge commits: the top commit of the two branches, and their common ancestor commit.
While it is actually an option to use these different merge strategies, most developers prefer fast-forward merges (by utilizing rebasing command), especially for small feature development or bug fixes; conversely for merging long-term developed features For branches, it is more inclined to use the three-way merge method. In the second scenario, the merge commit generated by the merge is retained in the commit history as a sign of the merge of the two branches.
Next we use the first example below to show how to fast-forward merge. The following command will first create a new branch, make two commits on the new branch, and then use a fast-forward merge to merge the new branch back into the main
branch.
# Start a new feature
git checkout -b new-feature main
# Edit some files
git add <file>
git commit -m "Start a feature"
# Edit some files
git add <file>
git commit -m "Finish a feature"
# Merge in the new-feature branch
git checkout main
git merge new-feature
git branch -d new-feature
The workflow in this example is usually used for short-term function development. This development process is more regarded as a relatively independent one-time development process, and corresponds to a long-term function development branch that needs to be coordinated and managed.
Also note that in this example Git will not issue a warning for the git branch -d
command, because the contents of the new-feature have already been merged into the master branch.
In some cases, although the commit history of the target branch is linear relative to the current branch, fast-forward merge can be performed, but you still want to have a merge commit to mark that the merge has occurred in this commit, so you can execute the git merge
command when Use the --no-ff
option.
git merge --no-ff <branch>
The above command will merge the specified branch into the current branch, but will always generate a merge commit (even if the merge operation can be fast-forwarded). This command is useful when you need to mark merge events in your repository's commit history.
three-way merge
The following example is similar to the above, but because the main
branch changes itself during the forward development of the feature branch, a three-way merge is required when merging. This scenario is quite common when developing a large feature or with multiple developers working on it at the same time.
Start a new feature
git checkout -b new-feature main
# Edit some files
git add <file>
git commit -m "Start a feature"
# Edit some files
git add <file>
git commit -m "Finish a feature"
# Develop the main branch
git checkout main
# Edit some files
git add <file>
git commit -m "Make some super-stable changes to main"
# Merge in the new-feature branch
git merge new-feature
git branch -d new-feature
Note that in this case, Git cannot perform a fast-forward merge because there is no way to directly move the top pointer of main
to the new-feature
branch.
In most practical work scenarios, new-feature
should be a big feature, and the development process lasted for a long time, so it is inevitable that there will be new commits on the main
branch at the same time. If your feature branch size is as small as the example above, you can completely rebase the new-feature
branch to the main
branch, and then perform a fast-forward merge. This will also avoid creating too much redundancy in the project commit history.
conflict resolution
If the two branches to be merged both modify the same part of the file, Git can't figure out which version of the content to use. When this happens, the merge process stops just before the merge commit commits, in order to give the user an opportunity to fix these conflicts manually.
The great thing about Git's merge process is that it uses the familiar edit/staging/commit workflow to resolve conflicts. When encountering merge conflicts, executing the git status
command will list which files contain conflicts and need to be resolved manually. For example, when both branches have modified the same part of the hello.py
file, you will see something like this:
On branch main
Unmerged paths:
(use "git add/rm ..." as appropriate to mark resolution)
both modified: hello.py
How the conflict is displayed
When Git encounters a conflict during a merge, it edits the relevant content in the affected file and adds visual markers to show what the conflicting parties are different about in this section. These visual markers are: <<<<<<<,========,>>>>>>>>. To find exactly where the conflict occurred, it is very convenient to search for these visual markers in the file.
here is some content not affected by the conflict
<<<<<<< main
this is conflicted text from main
=======
this is conflicted text from feature branch
>>>>>>> feature branch;
Generally speaking, the content before the ====== marker is from the branch that received the merge, and the content after that is from the branch to be merged.
Once the conflicting parts are found, the conflicts can be corrected as needed. When you've fixed the conflict and are ready to continue merging, just execute the git add
command to add the conflicted files to the staging area and tell Git that the conflicts have been resolved. After this, execute git commit
to complete the merge commit as normal commit code. This process is exactly the same as submitting code under normal circumstances, which means that dealing with conflicts is a piece of cake for ordinary developers.
Also note that merge conflicts are only possible during three-way merges, not during fast-forward merges.
Summarize
This article is an overview of the git merge
command. In the process of using Git, merging is a very important operation. This article discusses the mechanics behind the merge operation, and the difference between a fast-forward merge and a three-way merge. The main points for readers to remember are as follows:
- The Git merge process is to merge different commit sequences into a unified commit history
- There are two main ways of merging in Git: fast-forward merging and three-way merging
- Git can usually merge commits automatically unless there is a conflict in the sequence of two commits
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。