4.2.2 基本合并(Basic Merging)
假设你的issue #53工作做完了,你决定把它合并到你的master分支中去了。为了实现这一点,你将把你的iss53分支合并进来,这很像你之前把hotfix分支合并进来。所有你需要做的是check out你希望合并到的那个分支,然后运行git merge 命令:
$ git checkout master
$ git merge iss53
Merge made by recursive.
README | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
这看上去与你之前所作的hotfix合并有点不同。在此情况下,你的开发历史已经从某一个更老的点开始偏离了。因为你所在分支的提交不直接是你正在合并进来的分支的祖先,Git不得不需要做一些工作。此时,Git做一些简单的三方合并:使用两个分支末端指向的快照和它们的两者的共同祖先。图3-16突出显示了在这种情况下Git做合并时使用的三个快照。
Git创建一个新的从这个三方合并中得来的快照并自动创建一个新提交指向它(如图3-17)而不是仅仅把分支指针向前移动。这个提交被称为一个合并提交,特殊的是它有多于一个的父亲。
值得指出的是Git采用最共同的祖先来作为其合并的基础;这是不同于CVS或者Subversion(1.5版本前)的一点,在那里,开发者在合并时,需要自己指出最优的合并基础。这使得在Git中合并远比在其它系统中容易。
现在,你的工作被合并进来,你不再需要iss53分支了。你可以删除它然后手工去关闭你ticket-tracking中的ticket。
$ git branch -d iss53
4.2.3 基本合并冲突(Basic Merge Conflicts)
有时候,这个过程不会那么顺利。如果你分别在正在合并的两个分支中更改了同一个文件的相同部分,Git不会清楚地合并它们。如果你在修复issue #53所作的改动修改了hotfix中的一个文件的相同部分,那么你将会得到一个合并冲突,它看起来如下:
$ git merge iss53
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.
Git没有自动创建一个新的合并提交。它暂时停止了这个过程等待你解决这个冲突。如果你想看一下在一个合并冲突后哪些文件没有被合并,你可以运行git status:
[master*]$ git status
index.html: needs merge
# On branch master
# Changed but not updated:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# unmerged: index.html
#
任何有合并冲突的以及还没有被解决的冲突都被列为未合并的(unmerged)。Git增加了标准的冲突解决标志给那些有冲突的文件,以便你可以手工打开它们并解决这些冲突。你的文件包含了一个段落看起来如下:
<<<<<<< HEAD:index.html
<div id="footer">contact : email.support@github.com</div>
=======
<div id="footer">
please contact us at support@github.com
</div>
>>>>>>> iss53:index.html
这意味者HEAD中的版本(你的master分支,因为这是你运行合并命令时已经检出checkout的版本)位于这个显示块的上部(任何在=======之上的部分),而在你版本iss53分支的版本看起来位于下部。为了解决这个冲突,你需要或者选择一个版本,或者选择另一个版本,或者自己来合并这些内容。例如,你可以用以下内容替代整个块来解决冲突:
<div id="footer">
please contact us at email.support@github.com
</div>
这个解决方案分别有每个版本的一小部分,而且,我已经完全移除了<<<<<<<, =======以及>>>>>>>这些行。当你已经解决了每个冲突文件的每个这样的部分后,为每个文件运行git add以标记它为冲突已解决状态。在Git中缓存文件标记其为已解决状态。如果你想使用一个图形化的工具来解决这些问题,你可以运行git mergetool,它会触发调用一个合适的合并工具并使你能够解决这些冲突:
$ git mergetool
merge tool candidates: kdiff3 tkdiff xxdiff meld gvimdiff opendiff emerge vimdiff
Merging the files: index.html
Normal merge conflict for 'index.html':
{local}: modified
{remote}: modified
Hit return to start merge resolution tool (opendiff):
如果你想使用一个非缺省的合并工具(在本例中,Git为我选择了opendiff因为我在一个mac上运行该命令),你可以看到所有支持的工具被列在上部“合并工具候选”的后面。输入你想使用的工具名称。在第7章,我们将讨论怎么为你的环境改变这些缺省值。
在你退出合并工具后,Git会询问合并是否已经成功,如果你告诉脚本说已经成功,它将会为你缓存文件并标记其为已解决。
你可以再次运行git status来验证所有的冲突已经解决:
$ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: index.html
#
如果你很满意,你验证了所有的冲突已经被缓存,那么你可以输入git commit来最终确定合并提交。缺省的提交消息看起来如下:
Merge branch 'iss53'
Conflicts:
index.html
#
# It looks like you may be committing a MERGE.
# If this is not correct, please remove the file
# .git/MERGE_HEAD
# and try again.
#
你可以修改这个消息使其更具体包括你是怎么解决合并问题的等等那些你认为当其它人未来来查看这个合并时有用的信息――也就是你做了些什么以及为什么,如果它不是那么明显的话。