共计 3887 个字符,预计需要花费 10 分钟才能阅读完成。
在 Git 中 merge 是用来把分叉的提交历史放回到一起的形式。git merge
命令用来将你之前应用 git branch
命令创立的分支以及在此分支上独立开发的内容整合为一个分支。
请留神上面的所有命令都会是将其余分支合并到以后所在工作分支上。当前工作分支的内容会因为 merge 操作产生更新,然而指标分支则齐全不受影响。再次强调,这意味着 git merge
通常与其余几个 git 命令一起应用,包含应用 git checkout
命令来抉择当前工作分支,以及应用 git branch -d
命令来删除曾经合并过的废除分支。
它是如何运行的
git merge
会将多个提交序列合并进一个对立的提交历史。在最常见的应用场景中,git merge
被用来合并两个分支。在本文档接下来的局部,咱们会专一于这种合并场景。在这种场景中,git merge
承受两个 commit 指针,通常是两个分支的顶部 commit,而后向前追溯到这两个分支最近的一个独特提交。一旦找到这个独特提交,Git 就会创立一个新的 ”merge commit”,用来合并两个分支上各自的提交序列。
比如说咱们有一个性能分支由 main
分支派生进去,当初咱们心愿将这个性能分支合并回 main
分支。
执行合并命令会将指定分支合并到当前工作分支上,咱们假如当前工作分支为main
。Git 依据两个分支自行决定合并提交的算法(将在上面具体探讨)。
合并 commit 与一般 commit 不一样,因为合并 commit 会有两个父提交。创立一个合并 commit 时 Git 会尝试主动将两个独立的提交历史合并为一个。不过当 Git 发现某一块数据在两边的提交历史中都含有变更,它将无奈主动对其进行合并。这种状况被称为版本抵触,此时 Git 须要人为染指调整能力持续进行合并。
筹备合并
在理论进行合并操作之前,须要进行一些筹备步骤,以保障合并过程可能顺利进行。
确认接管合并的分支
执行 git status
命令查看以后分支的状态,确保 HEAD
斧正指向的是正确的接管合并的分支。如果不是,执行 git checkout
命令切换到正确的分支。在咱们的示例中,执行git checkout main
。
获取最新的近程提交
确保合并操作波及的两个分支都更新到近程仓库的最新状态。执行 git fetch
拉取近程仓库的最新提交。一旦 fetch 操作实现,为了保障 main
分支与近程分支同步,还需执行 git pull
命令。
合并
当下面提及的筹备工作都已齐备,合并就能够正式开始了。执行 git merge <branch>
命令,其中 <branch> 为须要合并到以后分支的指标分支名称。
快进合并
当前工作分支到合并指标分支之间的提交历史是线性门路时,能够进行快进合并。在这种状况下,不须要实在的合并两个分支,Git 只须要把以后分支的顶端指针挪动到指标分支的顶端就能够了(也就是快进的意思)。在这种状况下快进合并胜利的将提交历史合并至一处,毕竟指标分支中的提交此时都蕴含在以后分支的提交历史中了。对于将性能分支快进合并到 main
分支的流程能够参见下图所示:
然而快进合并在两个分支呈现分叉的状况下是不容许执行的。当指标分支绝对于以后分支的提交历史不是线性的,Git 只能通过三路合并算法来决定如何对两个分支进行合并。三路合并算法须要应用一个专用 commit 来整合两边的提交历史。这个名词源于 Git 要想生成合并 commit,须要用到三个 commits:两个分支的顶端 commit,以及它们的独特先人 commit。
尽管实际上能够抉择应用这些不同的合并策略,然而大多数开发者更喜爱快进合并(通过利用 rebasing 命令),尤其是用于小性能的开发或者 bug 修复;反之对于合并长期开发的性能分支,则更偏向于应用三路合并的形式。在第二种场景中,merge 产生的合并 commit 会作为两个分支合并的标记保留在提交历史中。
接下来咱们用上面第一个例子来展现如何进行快进合并。上面的命令会先创立一个新分支,在新分支上进行两次提交,而后用快进合并把新分支合并回 main
分支。
# 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
这个例子中的工作流程通常用于短期性能的开发,这种开发流程更多地被当做是比拟独立的一次开发流程,与之对应的则是须要协调和治理的长期性能开发分支。
另外还需注意到,在此例中 Git 不会对 git branch -d
命令收回正告,因为 new-feature 的内容曾经合并到主分支里了。
在某些状况下,尽管指标分支的提交历史绝对于以后分支是线性的,能够进行快进合并,但你依然心愿有一个合并 commit 来标记合并在此 commit 产生过,那么能够在执行 git merge
命令时应用 --no-ff
选项。
git merge --no-ff <branch>
以上命令将指定分支合并到以后分支,但总会生成一个合并 commit(即使这一合并操作能够快进)。当你须要在仓库的提交历史中标记合并事件时这一命令相当有用。
三路合并
接下来的例子与下面比拟像,然而因为 main
分支在 feature 分支向前倒退的过程中,本身也产生的扭转,因而在合并时须要进行三路合并。在进行大的性能开发或者有多个开发者同时进行开发时这种场景相当常见。
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
需注意在这种状况下,因为没有方法间接把 main
的顶端指针挪动到 new-feature
分支上,因而 Git 无奈执行快进合并。
在大多数理论工作场景中,new-feature
应该是一个很大的性能,开发过程继续了相当长的工夫,这也就不免同期间在 main
分支上也有新的提交。如果你的性能分支大小像下面的例子一样小,则齐全能够应用 rebase 将 new-feature
分支变基到 main
分支上,而后再执行一次快进合并。这样也会防止在我的项目提交历史中产生过多的冗余。
解决抵触
如果将要合并的两个分支都批改了同一个而文件的同一个局部内容,Git 就无奈确定应该应用哪个版本的内容。当这种状况产生时,合并过程会进行在合并 commit 提交之前,以便给用户留下机会手动修复这些抵触。
在 Git 的合并过程中,很棒的一点是它应用人们熟知的 编辑 / 暂存 / 提交 这样的工作流程来解决抵触。当碰到合并抵触时,执行 git status
命令会列出哪些文件含有抵触并须要手动解决。比如说当两个分支都批改了 hello.py
文件的同一部分,你会看到相似上面这样的信息:
On branch main
Unmerged paths:
(use "git add/rm ..." as appropriate to mark resolution)
both modified: hello.py
抵触是如何显示的
当 Git 在合并过程中碰到了抵触,它会编辑受影响的文件中的相干内容,并增加视觉标记用以展现抵触中单方在此局部的不同内容。这些视觉标记为:<<<<<<<,=======,>>>>>>>。要找到抵触产生的具体位置,在文件中搜寻这些视觉标记会十分便捷地达成目标。
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;
通常来说在 ====== 标记之前的内容来自于接管合并的分支,而在这之后的内容来自于要合并的分支。
一旦找到抵触的局部,就能够依据须要来修改抵触。当你实现了抵触的修复并筹备好持续进行合并,只须要执行 git add
命令把曾经解决好抵触的文件增加暂存区,通知 Git 这些抵触曾经解决结束即可。这之后就像失常提交代码一样执行 git commit
实现合并 commit。这个过程跟失常状况下提交代码是齐全一样的,也就是说对于一般开发者来说解决抵触也是小菜一碟。
还需注意合并抵触只可能呈现在三路合并过程中,在快进合并中不会呈现抵触。
总结
本文是对于 git merge
命令的概览。在应用 Git 的过程中,合并是十分重要的操作。本文探讨了合并操作背地的机制,以及快进合并与三路合并的区别。须要读者记住的要点如下:
- Git 合并流程是把不同的提交序列合并到一个对立的提交历史中
- Git 合并过程中有两个次要的形式:快进合并 和 三路合并
- 除非两个提交序列中呈现抵触,Git 通常能够主动对提交进行合并