上一篇主要介绍了git 的基本操作,这一章主要讲解git 在实际项目开发中的使用。很多时候我们是多个人同时为做一件事情而努力,如何有效化解多人协同运作过程中出现的种种矛盾是相当重要的。实践证明,Git可以很好的胜任此类任务,这也是我们要在实验室内部推广Git应用的主要原因。
两个人如何协同 :
小明与小强是本节的两位主角。现在假设小明开始着手开发一个APP,并按照 前一篇所讲述的Git基本用法将APP纳于Git的管理之下。但是,很快小明就 发现了仅凭个人之力很难项目规定期限内完成这项工作,因此他邀请小强来参与APP,故事就这样开始了。
cd work
git clone xiaoming@192.168.0.7:~/work/app
git-clone可利用各种网络协议访问远端机器中的Git仓库,从中导出完整的 工作树到本地。
一个阶段之后,二人均将所做的工作不断地提交到各自的Git仓库中,直至他 们觉得有必要将各自所做的工作合并起来之后再进行新的开发阶段。由于小明作为主要开发者,二人的工作在他的机器上进行合并是比较自然的。
为实现与小强的工作合并,小明执行了以下操作:
cd ~/work/app
git pull xiaoqiang@192.168.0.5:~/work/app
git-pull命令可将属于同一项目的远端仓库与同样属于同一项目的本地仓库进行合并,它包含了两个操作:从远端仓库中取出更新版本,然后合并到本地仓库。上述命令可在小明的app仓库中完成对小强机器上的app仓库的合并。
如何解决仓库合并冲突 :
现在假设小明和小强在各自的工作树中对同一份文件foo.txt进行了修改,造成了冲突。需求进行了手工合并。最后,小明将合并处理结果提交到仓库中,即完
成了重叠冲突的合并问题的解决。
三人以至更多人如何协同:
上述模式主要讲了两人的主次关系,多若引入多人时,小明需要一一取回他们仓库,然后更新,才能完成版本的合并。 这样小明就会疲于应付。因此小明希望其他人能为他分担一些版本合并问题。
Git提供了git-pull的对偶命令,即git-push。顾名思义,git-pull命令负责从远端仓库取回版本更新,而git-push可将本地版本更新推送到远端仓库中。利用git-pull与git-push命令,那么在一个协同周期之内,除了小明之外之外,其余多人的项目开发流程大致如下:
git clone lyr@192.168.0.7:~/work/m2ge
...项目开发...
git add ./demo.php
git commit
git pull
...解决版本合并问题 ...
git push
在一个协同周期内,小明对app仓库的管理工作相当于管理一份他个人项目一般,因为app库是位于他的机器上,他是不需要git-pull与git-push的。
项目中协同开发优化:
上述所给出的三人及三人以上的协同工作模式有些不合理,譬如小明过于 特殊,别人都要git-pull与git-push,唯独他不需要。现在要剥夺他的这一特权,最有效的办法就是将app仓库建立在一台单独的服务器上。
首先,小明通过SSH登录到服务器,寻找合适位置,建立app.git目录,譬如/project/app.git,然后初始化一个空仓库,以此作为app仓库:
mkdir -p ~/project/app.git
cd ~/project/app.git
git--bare init --shared
上述操作中,git-init命令的--bare选项可以让app.git目录等价于一个仓库。也就是说,app.git本来是一个工作树,但是--bare选项将本应当存放在app.git/.git中的仓库内容全部放置在app.git目录下,就好像仓库完全的裸 露在工作树中,所以称之为赤裸的仓库。
然后,小明将自己机器上已经接受Git管理的app仓库推送到服务器端的app.git仓库:
cd ~/work/app
git push git@192.168.0.2:~/project/app.git master
上述git-push命令中出现的master参数的含义将在下面讲述,此处可略过不谈。现在,大家已经得到了app仓库的最初版本,并且可以使用git-clone命令在本地创建工作目录:
git clone git@192.168.0.2:~/project/app.git
之后,我们就可以开始一个又一个协同周期,服务器上的app.git仓库将会逐次记录着每位协同开发者的版本更新提交,此基本过程可参考上一节所述内容来理解。
项目分支管理:
git最为世人称道的就是它那强大的项目分支管理功能,现在较为流行的版本控制系统,诸如CVS、SVN等,虽然也提供了项目分支管理功能,但是可用性极低。对于Git而言,管理多个项目分支如探囊取物耳。本章主要讲述Git的项目分支管理的基本知识以及如何利用这一功能形成更有章法的项目协同开发模式。
如何产生项目分支 :
前两章所讲内容未有提及项目分支问题,但事实上是有一个分支存在的,那就是master分支(主分支),该分支是由Git自动产生的。在此之前,我们针对项目版本的各种操作都是在主分支上进行的,只是我们未察觉它的存在而已。Git可以轻松地产生新的项目分支,譬如下面操作可添加一个名曰“local”的新的项目分支:
git branch local
对于新产生的local分支,初始时是完全等同于主分支的。但是,在local分支所进行的所有版本更新工作都不影响主分支,这意味着作为项目的参与者,可以在local中开始各种各样的更新尝试。查看项目仓库中存在多少分支,可直接使用git-branch命令,譬如使用该命令查看我的M2Doc项目分支列表:
git branch
local
*master
在上述操作输出结果中,若分支名之前存在*符号,表示此分支为当前分支。其实Git各分支不存在尊卑之别,只存在哪个分支是当前分支的区别。为了某种良好的秩序,很多人默认是将master分支视为主分支,本文也将沿用这一潜在规则。
由上述操作输出的分支列表可以看出,虽然使用git-branch命令产生了local分支,但是Git不会自动将当前分支切换到local下。可使用git-checkout命令实现分支切换,下面操作将当前分支切换为前文所产生的local分支:
git checkout local
分支的合并 :
我们产生了local分支,并在该分支下进行了诸多修改与数次的版本更新提交,但是该如何将这一分支的最终状态提交到master分支中呢?git-merge命令可实现两个分支的合并。譬如我们将local分支与master分支。合并,操作如下:
git checkout master #将当前分支切换为master
git merge local #将local分支与当前分支合并
当一个分支检查无误并且与master分支成功合并完毕后,那么这一分支基本上就没有存在的必要性了,可以删除掉:
git branch -d local
注意,git-branch的-d选项只能删除已经参与了合并的分支,对于未有合并的分支是无法删除的。如果想不问青红皂白地删除一个分支,可以使用git-branch的 -D选项。
APP协同开发模式:
现在来讨论一下如何基于Git项目分支管理功能实现更为稳健、高效的APP库的协同开发机制。
一台单独服务器上已经建立了app仓库。现在以小明作为主角,看一看他围绕app开发工作的一天中的工作过程。
git pull #更新自己机器上的工作树
git log #查看其他成员的版本更新
git branch merchandise #新建一个merchandies 分支
git checkout merchandise #切换到该分支
……在新分支上开发一天的工作
git checkout #切换到主分支
git branch #查看当前分支
git merge merchandise #合并merchantdies上的更新
git branch -d merchandise #删除一合并的分支
git pull #获取其他成员在公共仓库的更新
……若有冲突解决冲突
git push #将更新推送到公共仓库
至此,对于我们而言,在基于Git的app协同开发过程中,引入分支管理功能,可有效防止因个人操作不当而导致向服务器app仓库提交太多的脏数据。另外,也有效保持了本地项目主分支的干净,避免了频繁git-clone服务器端的M2GE仓库来恢复本地的项目主分支。
小技巧:
如果你在项目中,某个文件比较私有,不想被push到中心版本库。例如数据库连接配置(开发环境和线上环境不同)。你可以将其忽略!
git update-index --assume-unchanged <file>
又或者你想让上述文件重新回到版本控制下你可以执行下面的命令:
git update-index --no-assume-unchanged <file>