解决Git上传冲突

在下面的几个案例里面,为了使讲述的内容更简洁,我们将不会按照上面的规范去写很规范的提交注释,并使用-m选项去做git commit。听我们说,但是不要学我们做^^。

冲突发生在不同文件

你遇到的最简单的私有项目的配置可能是只有两三个开发者。这里的“私有项目”是指闭源不会对外公布的项目,但是你和其他开发者都可以访问代码库。
在这个背景下, 你可以像使用Subversion或其他代码管控系统一样去跟踪一个项目流程。你仍然可以使用比如离线上传、分支、合并等功能,并且流程是非常相似的。主要的不同是合并操作可以只需要有客户端,而不必立即同步到服务段。让我们来看一下,当两个开发者开始共同开发这个代码库会是什么样子。John是其中一位开发者,克隆了这个代码库,做了一些修改后,然后把修改上传到了本地。(在这个案例里面,我们将以…代替出现的大段出现的协议信息,以简化案例)

# John‘s Machine
$ git clone john@githost:simplegit.git
Initialized empty Git repository in /home/john/simplegit/.git/
...
$ cd simplegit/
$ vim lib/simplegit.rb
$ git commit -am ‘removed invalid default value‘
[master 738ee87] removed invalid default value
 1 files changed, 1 insertions(+), 1 deletions(-)

另外一位开发者,Jessica,做了同样的事情, 克隆了工程并提交了自己的修改到本地:

# Jessica‘s Machine
$ git clone jessica@githost:simplegit.git
Initialized empty Git repository in /home/jessica/simplegit/.git/
...
$ cd simplegit/
$ vim TODO
$ git commit -am ‘add reset task‘
[master fbff5bc] add reset task
 1 files changed, 1 insertions(+), 0 deletions(-)

现在Jessica同步她的修改到服务器上:

# Jessica‘s Machine
$ git push origin master
...
To jessica@githost:simplegit.git
   1edee6b..fbff5bc  master -> master

John也打算同步他的修改到服务器:

# John‘s Machine
$ git push origin master
To john@githost:simplegit.git
 ! [rejected]        master -> master (non-fast forward)
error: failed to push some refs to ‘john@githost:simplegit.git‘

John没能成功同步他的修改到服务器,因为Jessica也在同时做了一样的事情。这一点对曾用过Subversion的你特别重要,因为你可能注意到了两个开发者的修改没有涉及相同的文件。在这种情况下,Subversion会自动完成这个合并,但是Git却不会,所以你需要先在本地merge两个人的修改。John不得不先获取Jessica的修改,将这些修改合并再和服务器同步。

$ git fetch origin
...
From john@githost:simplegit
 + 049d078...fbff5bc master     -> origin/master

这时,John的本地仓库差不多是这样的:
技术分享
John’s divergent history


John知道Jessica的修改与自己的并不相关,但是他还是不得不先把这些修改合并到他本地的库中,这样才会被服务器允许同步他的修改:

$ git merge origin/master
Merge made by recursive.
 TODO |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

合并动作完成了,John的上传记录现在是这个样子的:
技术分享
John’s repository after merging origin/master.


现在John可以测试他的代码以保证它们仍然正常有效,并且他可以同步自己的修改到服务器了:

$ git push origin master
...
To john@githost:simplegit.git
   fbff5bc..72bbc59  master -> master

最终,John的提交记录是这个样子的:
技术分享
John’s history after pushing to the origin server.


冲突发生涉及同一文件

与此同时,Jessica还在开发一个主题分支。她创建了一个名为issue54的分支,然后在这个分支上提交了三次修改。她还没有获取John的修改,现在他的提交记录是这样的:
技术分享
Jessica’s topic branch.


Jessica要同步John的修改:

# Jessica‘s Machine
$ git fetch origin
...
From jessica@githost:simplegit
   fbff5bc..72bbc59  master     -> origin/master

Jessica拉取了John同步到服务器上的修改,现在Jessica的提交记录是这样的:
技术分享
Jessica’s history after fetching John’s changes.


Jessica认为她的分支已经准备好了,但是她想知道她必须merge哪些东西后她才可以向服务器同步她的修改。她运行git log 去查看以下内容:

 $ git log --no-merges issue54..origin/master
commit 738ee872852dfaa9d6634e0dea7a324040193016
Author: John Smith <[email protected]>
Date:   Fri May 29 16:01:27 2009 -0700

   removed invalid default value

“issue54..origin/master”这个参数的语法是一个日志过滤器,可以要求Git只显示在第二个参数分支origin/master上有,但是issue54分支上还没有的commits的列表。更多这个参数语法请参看”Commits Ranges”。
现在,我们从输出看到Jessica未整合的John的提交只有一个。如果Jessica要整合origin/master,这个commit将会修改她在本地的内容。现在Jessica要先合并她的主题分支到主分支中,再合并John的那个commit到她的主分支,最后同步到服务器。 首先,Jessica回到她的主分支去整合所有这些修改:

$ git checkout master
Switched to branch ‘master‘
Your branch is behind ‘origin/master‘ by 2 commits, and can be fast-forwarded.

Jessica可以先合并 origin/master,也可以先合并issue54分支,它们都是需要上传的,所以顺序并不重要。最后的项目状态snapshot都应该是一样的, 不管采用什么顺序,只有上传记录会有一点不同而已。Jessica选择先合并issue54分支:

$ git merge issue54
Updating fbff5bc..4af4298
Fast forward
 README           |    1 +
 lib/simplegit.rb |    6 +++++-
 2 files changed, 6 insertions(+), 1 deletions(-)

合并成功。就像你看到的这是一个非常简单快推进, 现在Jessica要开始合入John的修改了(即origin/master主干分支的内容):

$ git merge origin/master
Auto-merging lib/simplegit.rb
Merge made by recursive.
 lib/simplegit.rb |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

所有的东西都很干净的合并了,现在Jessica查看到的上传记录像是这样:
技术分享
Jessica’s history after merging John’s changes


Jessica的master分支是可以访问origin/master的,所以她能够成功的同步修改到服务器(假设John在这段时间没有上传过其他修改):

$ git push origin master
...
To jessica@githost:simplegit.git
   72bbc59..8059c15  master -> master

每一个开发者都提交自己的修改并且也成功合并过别人的修改。
技术分享
Jessica’s history after pushing all changes back to the server


这是一个最简单的工作流程实例。你在开发一段时间后,通常是指在一个主题分支开发中,要整合这段时间完成的修改到你的master分支以便提交。当你打算分享?你的修改,你把修改合入你的master分支,获取origin/master并且合入,最后同步到服务器。这流程顺序类似下面这个图:
技术分享
General sequence of events for a simple multiple-developer Git workflow.


内容有点多,翻译不够细致,后续持续改进。

原文链接

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。