【git】git分支的合并

原文:  html

http://gitbook.liuhui998.com/3_3.html
http://gitbook.liuhui998.com/5_3.html
1、如何分支的合并
在git中,可使用git merge 和git rebase两个命令来进行分支的合并。
git merge 和git rebase在大致上都差很少,下文主要以git merge来例来说解分支的合并流程。
若是你想了解分支合并的更多内容,请阅读《 git merge简介》,《 git rebase简介(基本篇)》和《 git rebase简介(高级篇)》。
git merge命令示例:
$ git merge branchname
这个命令把分支"branchname"合并到了当前分支里面。
若有冲突(冲突--同一个文件在远程分支和本地分支里按不一样的方式被修改了);那么命令的执行输出就像下面同样
$ git merge next
 100% (4/4) done
Auto-merged file.txt
CONFLICT (content): Merge conflict in file.txt
Automatic merge failed; fix conflicts and then commit the result.
在有问题的文件上会有冲突标记,在你手动解决完冲突后就能够把此文件添 加到索引(index)中去,用git commit命令来提交,就像平时修改了一个文件 同样。
若是你用gitk来查看commit的结果,你会看到它有两个父分支:一个指向当前的分支,另一个指向刚才合并进来的分支。
2、解决合并中的冲突
若是执行自动合并无成功的话,git会在索引和工做树里设置一个特殊的状态, 提示你如何解决合并中出现的冲突。
有冲突(conflicts)的文件会保存在索引中,除非你解决了问题了而且更新了索引,不然执行 git commit都会失败:
$ git commit
file.txt: needs merge
若是执行 git status 会显示这些文件没有合并(unmerged),这些有冲突的文件里面会添加像下面的冲突标识符:
<<<<<<< HEAD:file.txt
Hello world
=======
Goodbye
>>>>>>> 77976da35a11db4580b80ae27e8d65caf5208086:file.txt
你所须要的作是就是编辑解决冲突,(接着把冲突标识符删掉),再执行下面的命令:
$ git add file.txt
$ git commit
注意:提交注释里已经有一些关于合并的信息了,一般是用这些默认信息,可是你能够添加一些你想要的注释。
上面这些就是你要作一个简单合并所要知道的,可是git提供更多的一些信息来 帮助解决冲突。
3、撒销一个合并
若是你以为你合并后的状态是一团乱麻,想把当前的修改都放弃,你能够用下面的命令回到合并以前的状态:
$ git reset --hard HEAD
或者你已经把合并后的代码提交,但仍是想把它们撒销:
$ git reset --hard ORIG_HEAD
可是刚才这条命令在某些状况会很危险,若是你把一个已经被另外一个分支合并的分支给删了,那么 之后在合并相关的分支时会出错。
关于撤销的更多内容请参考《 git reset简介
4、快速向前合并
还有一种须要特殊对待的状况,在前面没有提到。一般,一个合并会产生一个合并提交(commit), 把两个父分支里的每一行内容都合并进来。
可是,若是当前的分支和另外一个分支没有内容上的差别,就是说当前分支的每个提交(commit)都已经存在另外一个分支里了,git 就会执行一个“快速向前"(fast forward)操做;git 不建立任何新的提交(commit),只是将当前分支指向合并进来的分支。
5、在合并过程当中获得解决冲突的协助
git会把全部能够自动合并的修改加入到索引中去, 因此git diff只会显示有冲突的部分. 它使用了一种不常见的语法:
$ git diff
diff --cc file.txt
index 802992c,2b60207..0000000
--- a/file.txt
+++ b/file.txt
@@@ -1,1 -1,1 +1,5 @@@
++<<<<<<< HEAD:file.txt
 +Hello world
++=======
+ Goodbye
++>>>>>>> 77976da35a11db4580b80ae27e8d65caf5208086:file.txt
回忆一下, 在咱们解决冲突以后, 获得的提交会有两个而不是一个父提交: 一个父提交是当前分支提交前的HEAD,; 另一个父提交是被合并分支的HEAD, 被暂时存在MERGE_HEAD.
在合并过程当中, 索引中保存着每一个文件的三个版本. 三个"文件暂存(file stage)"中的每个都表明了文件的不一样版本:
$ git show :1:file.txt  # 两个分支共同祖先中的版本.
$ git show :2:file.txt  # HEAD中的版本.
$ git show :3:file.txt  # MERGE_HEAD中的版本.
当你使用git diff去显示冲突时, 它在工做树(work tree), 暂存2(stage 2)和暂存3(stage 3)之间执行三路diff操做, 只显示那些两方都有的块(换句话说, 当一个块的合并结果只从暂存2中获得时, 是不会被显示出来的; 对于暂存3来讲也是同样).
上面的diff结果显示了file.txt在工做树, 暂存2和暂存3中的差别. git不在每行前面加上单个'+'或者'-', 相反地, 它使用两栏去显示差别: 第一栏用于显示第一个父提交与工做目录文件拷贝的差别, 第二栏用于显示第二个父提交与工做文件拷贝的差别. (参见git diff-files中的"COMBINED DIFF FORMAT"取得此格式详细信息.)
在用直观的方法解决冲突以后(可是在更新索引以前), diff输出会变成下面的样子:
$ git diff
diff --cc file.txt
index 802992c,2b60207..0000000
--- a/file.txt
+++ b/file.txt
@@@ -1,1 -1,1 +1,1 @@@
- Hello world
-Goodbye
++Goodbye world
上面的输出显示了解决冲突后的版本删除了第一个父版本提供的"Hello world"和第二个父版本提供的"Goodbye", 而后加入了两个父版本中都没有的"Goodbye world".
一些特别diff选项容许你对比工做目录和三个暂存中任何一个的差别:
$ git diff -1 file.txt      # 与暂存1进行比较
$ git diff --base file.txt          # 与上相同
$ git diff -2 file.txt      # 与暂存2进行比较
$ git diff --ours file.txt          # 与上相同
$ git diff -3 file.txt      # 与暂存3进行比较
$ git diff --theirs file.txt    # 与上相同.
还有,git log和gitk命令也为合并操做提供了特别的协助:
$ git log --merge
$ gitk --merge
这会显示全部那些只在HEAD或者只在MERGE_HEAD中存在的提交, 还有那些更新(touch)了未合并文件的提交.
你也可使用git mergetool, 它容许你使用外部工具如emacs或kdiff3去合并文件.
 
每次你解决冲突以后, 应该更新索引:
$ git add file.txt
完成索引更新以后, git-diff(缺省地)再也不显示那个文件的差别, 因此那个文件的不一样暂存版本会被"折叠"起来.
6、多路合并
你能够一次合并多个头, 只需简单地把它们做为git merge的参数列出. 例如,
$ git merge scott/master rick/master tom/master
至关于:
$ git merge scott/master
$ git merge rick/master
$ git merge tom/master
7、子树
有时会出现你想在本身项目中引入其余独立开发项目的内容的状况. 在没有路径冲突的前提下, 你只须要简单地从其余项目拉取内容便可.
若是有冲突的文件, 那么就会出现问题. 可能的例子包括Makefile和其余一些标准文件名. 你能够选择合并这些冲突的文件, 可是更多的状况是你不肯意把它们合并. 一个更好解决方案是把外部项目做为一个子目录进行合并. 这种状况不被递归合并策略所支持, 因此简单的拉取是无用的.
在这种状况下, 你须要的是子树合并策略.
这下面例子中, 咱们设定你有一个仓库位于/path/to/B (若是你须要的话, 也能够是一个URL). 你想要合并那个仓库的master分支到你当前仓库的dir-B子目录下.
下面就是你所须要的命令序列:
$ git remote add -f Bproject /path/to/B (1)
$ git merge -s ours --no-commit Bproject/master (2)
$ git read-tree --prefix=dir-B/ -u Bproject/master (3)
$ git commit -m "Merge B project as our subdirectory" (4)
$ git pull -s subtree Bproject master (5)
子树合并的好处就是它并无给你仓库的用户增长太多的管理负担. 它兼容于较老(版本号小于1.5.2)的客户端, 克隆完成以后立刻能够获得代码.
然而, 若是你使用子模块(submodule), 你能够选择不传输这些子模块对象. 这可能在子树合并过程当中形成问题.
译者注: submodule是Git的另外一种将别的仓库嵌入到本地仓库方法.
另外, 若你须要修改内嵌外部项目的内容, 使用子模块方式能够更容易地提交你的修改.
相关文章
相关标签/搜索