一、合并
为了把 other_branch 合并到 branch 中,你应该检出目标分支并把其他分支合并进去,如下所示:
$ git checkout branch
$ git merge other_branch
二、为合并做准备
在开始合并之前,最好整理一下工作目录。在正常合并结束的时候,Git 会创建新版本的文件并把它放到工作目录中。此外,Git 在操作的时候还用索引来存储文件的中间版本。
如果已经修改了工作目录中的文件,或者已经通过 git add 或者 git rm 修改了索引,那么版本库里就已经有了一个脏的工作目录或者索引。如果在脏的状态下开始合并,Git 可能无法一次和并所有分支以及工作目录或索引的修改。
不必从干净的目录启动合并。例如,当受合并操作影响的文件和工作目录的脏文件无关的时候,Git 才进行合并。然而,作为一般规则,如果每次合并都从干净的工作目录和索引开始,那么关于 Git 的操作将会容易得多。
三、处理合并冲突
一个分支上的修改可能与一个不同的分支上的相似或完全不同。修改可能会改变相同的或无关的文件。Git 可以处理所有这些不同的可能性,但是通常需要你的指导来解决冲突。
定位冲突文件:
使用 git status 命令或者 git ls-files -u 命令来显示工作树中任然未合并的一组文件。
$ git status
On branch master
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: name.txt
no changes added to commit (use "git add" and/or "git commit -a")
$ git ls-files -u
100644 e58835da4f1858ae5e279334b5dc747340635408 1 name.txt
100644 7dab57c084e10c2125de87e512b81fb1305c3801 2 name.txt
100644 27606668f6313d817d211efc570c4853a704c84a 3 name.txt
可以使用 git diff 命令来显示没合并的内容,但是它也会显示所有的细节。
检查冲突
当冲突出现时,通过三方比较或合并标记强调工作目录中的每个冲突文件的副本。
$ cat name.txt
foo
wt
<<<<<<< HEAD
aj
=======
dj
>>>>>>> new-branch
合并标记划定文件冲突部分的两个可能版本。可以简单地选择其中一个,移除冲突标记,然后执行 git add 和 git commit 命令。
三方合并标记线(<<<<<<<、=======、>>>>>>>)是自动生成的,它们只是给提供给你看的,一旦解决了冲突,就应该在文本编译器里删除他们。
对冲突使用 git diff 命令:
Git 有一个特殊的。特定于合并的 git diff 辩题来同时显示针对两个父版本做的修改
$ git diff
diff --cc name.txt
index 7dab57c,2760666..0000000
--- a/name.txt
+++ b/name.txt
@@@ -1,8 -1,8 +1,9 @@@
foo
ang
msh
wt
++<<<<<<< HEAD
+aj
++=======
+ dj
++>>>>>>> new-branch
这只是两个 diff 文件的简单组合:一个对应第一个称为 HEAD 的父版本,另一个对应第二个称为 new-branch 的父版本。Git 也给第二个父版本起了一个特殊的名字——MERGE_HEAD。
可以拿 HEAD 和 MERGE_HEAD 版本跟工作目录(“合并的”)版本进行比较。
在较新版本的 Git 中,git-diff –ours 是 git diff HEAD 的同义词,因为它显示了“我们的”版本和合并后版本的区别。同样,git diff MERGE_HEAD 可以写成 git diff –theirs。可以用 git diff –base 命令来查看自合并基础之后的变更组合。
对冲突使用 git log 命令:
在解决冲突的过程中,可以使用一些特殊的 git log 选项来帮助你找出变更的确切来源和原因。
$ git log --merge --left-right -p
commit < 245370451d194bbff90a7bd6236a37b129831211
Author: Jon Loeliger <jdl@example.com>
Date: Tue Aug 8 10:30:59 2017 +0800
add aj
diff --git a/name.txt b/name.txt
index e58835d..7dab57c 100644
--- a/name.txt
+++ b/name.txt
@@ -5,3 +5,4 @@ ang
msh
wt
+aj
commit > e0b4372b68ad435586d8d1015d665c15edb5a870
Author: Jon Loeliger <jdl@example.com>
Date: Tue Aug 8 10:28:55 2017 +0800
add dj
diff --git a/name.txt b/name.txt
index e58835d..2760666 100644
--- a/name.txt
+++ b/name.txt
@@ -5,3 +5,4 @@ ang
msh
wt
+dj
在合并中的两个分支都影响冲突的文件,此命令将显示这两部分历史中的所有提交,并显示每次提交引入的实际变更。
git log 的选项如下:
- –merge:只显示跟产生冲突的文件相关的提交。
- –left-tight:如果提交来自合并的“左”边则显示<(“我们的”版本,就是你开始的版本),如果提交来自合并的“右”边则显示>(“他们的”版本,就是你要合并到的版本)
- –p:显示提交信息和每个提交相关联的补丁。
如果版本库更加复杂而且有好几个文件发生冲突,也可以在命令行参数里指定确切的文件名:
$ git log --merge --left-right -p hello
小规模的提交和更频繁的合并周期可以减少解决冲突的痛苦。
结束解决冲突
在宣布合并前对冲突文件做最后一次修改。
$ cat name.txt
foo
ang
msh
wt
aj
dj
该文件已经完全合并而且解决冲突了,git add 命令就把索引再次简化为只有一份 name.txt 文件的副本。
$ git add name.txt
$ git ls-files -s
100644 088e2309c5b9be087c7a93c3da99c040714fa4a2 0 name.txt
git ls-files 的 -s 参数显示所有文件的各个阶段。
在 SHA1 和路径名中间单独的 0 表示无冲突文件的暂存编号是零。
必须解决索引中记录的所有冲突文件。只要有未解决的冲突就不能提交。因此,当解决一个文件的冲突之后,执行 git add(或者 git rm、git update-index等)以清除它的冲突状态。
注意:不要对有冲突标记的文件执行 git add 命令。虽然这会清除索引中的冲突,并允许提交,但文件将是错误的。
最后,对最终结果执行 git commit 命令。
中止或重新启动合并
在合并提交执行最后的 git commit 命令前,使用如下命令:
$ git reset --hard HEAD
这条命令立即把工作目录和索引都还原到 git merge 命令之前。
如果要中止或在它已经结束(也就是,引进一个新的合并提交)后放弃,请使用以下命令:
$ git reset --hard ORIG_HEAD
在开始合并操作前,GIt 把原分支的 HEAD 保存在 ORIG_HEAD .这是为了这种目的。