GitHub可以通过多种途径为版本库授权,让版本库成为多人共享的版本库,从而让项目管理者围绕项目创建一个核心开发团队。
传统的集中式版本控制系统,如CVS、SVN,所有用户都访问同一个版本库。采用集中式工作模式的GitHub用户也同样是访问同一版本库。
对于由用户gotgithub创建的helloworld版本库,添加了合作者supergirl和incredible,三个人克隆版本库使用如下命令。
- 用户 gotgithub 克隆版本库。
gotgithub$ git clone https://gotgithub@github.com/gotgithub/helloworld.git
- 用户 supergirl 克隆版本库。
supergirl$ git clone https://supergirl@github.com/gotgithub/helloworld.git
- 用户 incredible 克隆版本库。
incredible$ git clone https://incredible@github.com/gotgithub/helloworld.git
对于像Git这样的分布式版本控制系统,提交总是会成功,这是因为提交并不涉及和共享服务器的交互,是针对本地克隆版本库进行的本地操作。采用集中式的工作模式,共享版本库作为各个用户各自本地版本库数据交换、沟通的中介,只有在本地克隆版本库需要和共享版本库同步的时候才要和服务器建立连接。实际上无论采用分布式还是集中式的工作模式,Git都好像工作在一个独立的分支上(克隆即分支),即使共享版本库和本地克隆版本库的分支名都叫做master。
三个用户克隆gitgithub/helloworld版本库后,各自在本地执行了一次或多次提交。三个用户各自的提交都会非常顺利,但是一旦决定将本地提交推送到共享服务器时就可能遇到麻烦。用户 gotgithub 先执行推送,会非常顺利。而其他人就没有这么幸运了,会报告错误:遇到非快进式推送(non-fast-forward)。Git的推送操作就像SVN等集中式版本控制系统的提交操作那样,先执行者成功,后执行者糟糕(要解决冲突,自动或手动)。
合并后推送
GitHub并不对强制推送进行限制,但是用户不要用git push -f命令强制推送,因为那样会覆盖掉共享版本库中用户gotgithub的推送,正确的做法是获取共享版本库中新提交,并在本地版本库中和本地提交合并。即执行:
supergirl$ git fetch
supergirl$ git merge
实际上用户supergirl只需执行一条命令便可完成所有的操作:
supergirl$ git pull
即:git pull = git fetch + git merge。
但是合并操作并不总是会成功,如果自动合并失败,会在暂存区对合并前后文件进行标识,工作区进入冲突解决状态,在冲突解决完成之前不能提交。Git支持多种图形工具帮助完成冲突解决,执行如下命令,即可自动调用已安装的冲突解决工具。
supergirl$ git mergetool
冲突解决完毕,执行提交即完成冲突解决。如果在冲突解决过程把本地文件搞得一团糟,随时可以取消合并操作。执行命令git reset --hard会取消冲突的合并让本地版本库回到合并之前的状态。
成功完成合并后将本地版本库中的提交推送到共享版本库:
supergirl$ git push
合并还是变基
合并并非多个开发者的工作成果融合的唯一选择,有时甚至并非最佳选择。一方面合并会产生除了合并双方(或多方)所有提交外的一个新提交,增加了代码审核的负担,另一方面本地多个提交混杂一起与远程分支合并会更困难。在特定情况下,变基是合并之外的另一个选择。
图中右上是合并操作后的结果,右下是变基操作后的结果。
若用户 incredible 选择变基操作,执行命令如下:
- 获取远程版本库的提交到本地的远程分支。
incredible$ git fetch origin
- 执行变基操作,将本地master分支的提交变基到新的远程分支中。
incredible$ git rebase origin/master
如果一切顺利,变基后推送到共享版本库。
incredible$ git push