私有的小型团队
我们从最简单的情况开始,一个私有项目,与你一起协作的还有另外一到两位开发者。这里说私有,是指源代码不公开,其他人无法访问项目仓库。而你和其他开发者则都具有推送数据到仓库的权限。
这种情况下,你们可以用 Subversion 或其他集中式版本控制系统类似的工作流来协作。你仍然可以得到 Git 带来的其他好处:离线提交,快速分支与合并等等,但工作流程还是差不多的。主要区别在于,合并操作发生在客户端而非服务器上。让我们来看看,两个开发者一起使用同一个共享仓库,会发生些什么。第一个人,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 则必须先在本地合并后才能推送。于是,John 不得不先把 Jessica 的更新拉下来:
$ git fetch origin
...
From john@githost:simplegit
+ 049d078...fbff5bc master -> origin/master
此刻,John 的本地仓库如图 5-4 所示:
![](https://i-blog.csdnimg.cn/blog_migrate/70de730a54548fefeb8a93601fa1ca93.png)
图 5-4. John 的仓库历史
虽然 John 下载了 Jessica 推送到服务器的最近更新(fbff5),但目前只是 origin/master
指针指向它,而当前的本地分支 master
仍然指向自己的更新(738ee),所以需要先把她的提交合并过来,才能继续推送数据:
$ git merge origin/master
Merge made by recursive.
TODO | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
还好,合并过程非常顺利,没有冲突,现在 John 的提交历史如图 5-5 所示:
![](https://i-blog.csdnimg.cn/blog_migrate/4fbaeca473a09081b4ccf276c23500c7.png)
图 5-5. 合并 origin/master 后 John 的仓库历史
现在,John 应该再测试一下代码是否仍然正常工作,然后将合并结果(72bbc)推送到服务器上:
$ git push origin master
...
To john@githost:simplegit.git
fbff5bc..72bbc59 master -> master
最终,John 的提交历史变为图 5-6 所示:
![](https://i-blog.csdnimg.cn/blog_migrate/7ceb24d4f52000b66c24879d24eb2b5c.png)
图 5-6. 推送后 John 的仓库历史
而在这段时间,Jessica 已经开始在另一个特性分支工作了。她创建了 issue54
并提交了三次更新。她还没有下载 John 提交的合并结果,所以提交历史如图 5-7 所示:
![](https://i-blog.csdnimg.cn/blog_migrate/e1bebefcb612f4d8e8f6cdbc9d748104.png)
图 5-7. Jessica 的提交历史
Jessica 想要先和服务器上的数据同步,所以先下载数据:
# Jessica's Machine
$ git fetch origin
...
From jessica@githost:simplegit
fbff5bc..72bbc59 master -> origin/master
于是 Jessica 的本地仓库历史多出了 John 的两次提交(738ee 和 72bbc),如图 5-8 所示:
![](https://i-blog.csdnimg.cn/blog_migrate/df7a089242ebfb7b7957c6c391bea0e1.png)
图 5-8. 获取 John 的更新之后 Jessica 的提交历史
此时,Jessica 在特性分支上的工作已经完成,但她想在推送数据之前,先确认下要并进来的数据究竟是什么,于是运行 git log
查看:
$ git log --no-merges origin/master ^issue54
commit 738ee872852dfaa9d6634e0dea7a324040193016
Author: John Smith <jsmith@example.com>
Date: Fri May 29 16:01:27 2009 -0700
removed invalid default value
现在,Jessica 可以将特性分支上的工作并到 master
分支,然后再并入 John 的工作(origin/master
)到自己的 master
分支,最后再推送回服务器。当然,得先切回主分支才能集成所有数据:
$ git checkout master
Switched to branch "master"
Your branch is behind 'origin/master' by 2 commits, and can be fast-forwarded.
要合并 origin/master
或 issue54
分支,谁先谁后都没有关系,因为它们都在上游(upstream)(译注:想像分叉的更新像是汇流成河的源头,所以上游 upstream 是指最新的提交),所以无所谓先后顺序,最终合并后的内容快照都是一样的,而仅是提交历史看起来会有些先后差别。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 的提交历史如图 5-9 所示:
![](https://i-blog.csdnimg.cn/blog_migrate/d8e489ecd8d065a4ca6d53d18122ee6c.png)
图 5-9. 合并 John 的更新后 Jessica 的提交历史
现在 Jessica 已经可以在自己的 master
分支中访问 origin/master
的最新改动了,所以她应该可以成功推送最后的合并结果到服务器上(假设 John 此时没再推送新数据上来):
$ git push origin master
...
To jessica@githost:simplegit.git
72bbc59..8059c15 master -> master
至此,每个开发者都提交了若干次,且成功合并了对方的工作成果,最新的提交历史如图 5-10 所示:
![](https://i-blog.csdnimg.cn/blog_migrate/674cd854881f1985e3c7c6ded6cfb94e.png)
图 5-10. Jessica 推送数据后的提交历史
以上就是最简单的协作方式之一:先在自己的特性分支中工作一段时间,完成后合并到自己的 master
分支;然后下载合并 origin/master
上的更新(如果有的话),再推回远程服务器。一般的协作流程如图 5-11 所示:
![](https://i-blog.csdnimg.cn/blog_migrate/2633de91b22117dc97845e154a350368.png)
图 5-11. 多用户共享仓库协作方式的一般工作流程时序
git 在线学习地址:http://git.oschina.net/progit/5-%E5%88%86%E5%B8%83%E5%BC%8F-Git.html#5.2-%E4%B8%BA%E9%A1%B9%E7%9B%AE%E4%BD%9C%E8%B4%A1%E7%8C%AE