深入理解Git 工作流

git 工作流

集中式工作流

集中式工作流以中央仓库作为项目所有修改的单点实体。相比SVN缺省的开发分支trunk,Git叫做master,所有修改提交到这个分支上。本工作流只用到master这一个分支。要发布修改到正式项目中,开发者要把本地master分支的修改『推』到中央仓库中。这相当于svn commit操作,但push操作会把所有还不在中央仓库的本地提交都推上去。

示例

  1. 初始化一个空仓库 git init --bare /XX.git
  2. 员工A和B克隆中央仓库 git clone /xxx.git
  3. A开发功能 Git status, Git add , Git commit这些命令都是在本地提交,可以 反复操作多次,不用担心中央仓库。
  4. B开发功能 Git status, Git add , Git commit
  5. A 发布功能 git push origin master origin是 A 在科隆仓库时git创建的远程中央仓库别名。master参数告诉git推送的分支。
  6. B 发布功能 git push origin master时 B的本地历史和中央仓库有分歧,提交失败。如果要避免这种情况,B要先 pull A的更新到他的本地仓库合并上他的本地修改,再push。
  7. B在 A的提交之上 rebase。 B用 git pull 合并上游的修改到自己仓库,类似于SVN的 update。命令如下:git pull -rebase origin master。 –rebase告诉git 把B的提交移到中央仓库的master分支顶部。如果你忘记这个选项,pull仍然可以完成,但是每次pull操作要同步中央仓库中别人修改时,提交历史会以一个多余的’合并提交‘结尾。对于集中式工作流最好还是使用 –rebase 选项。
  8. B解决合并冲突。执行git rebase —abort可以回到执行git pull —rebase之前的样子。
  9. B成功发布功能。 git push origin master

功能分支工作流

功能分支工作流以集中式工作流为基础,不同的是为各个新功能分配一个专门的分支去开发。这样可以把新功能集成到正式项目前,用pull Request 的方式讨论变更。功能分支应该有一个描述性的名字,比如animated-menu-itemsissue-#1061,可以让分支有个清楚的用途。

示例

  1. A在开发新功能之前,建立一个独立的分支。git checkout -b xxx master 这个命令检出一个基于 master 的名为xxx分支,git -b 选项表示如果不存在就新建分支。然后老规矩 git status/add/commit
  2. 去吃午饭前,push功能分支到中央仓库是很好的做法,方便备份和开发协作。git push -u origin xxx -u选项表示设置本地分支去跟踪远程对于的分支,设置以后,A就可以使用git push 省去指定推送分支的参数。
  3. A回来之后,完成了整个功能的开发,在合并master之前,A发起了一个pull Request 让团队其他人知道功能已经完成。然后请求合并到master。
  4. B收到pull Request 会查看XXX分支的修改,决定在合并到正式项目前是否还要修改,且通过pull Request和A进行讨论。
  5. A 再次修改,编辑,暂存,提交并push到中央仓库,A的活动都会显示在pull Request上。B如果有需要也可以吧XXX分支拉到本地,自己修改,他的提交也会在pull Request上。

Git flow 工作流

Gitflow工作流定义了一个围绕项目发布的严格分支模型。虽然比功能分支工作流复杂几分,但提供了用于一个健壮的用于管理大型项目的框架。Gitflow工作流没有用超出功能分支工作流的概念和命令,而是为不同的分支分配一个很明确的角色,并定义分支之间如何和什么时候进行交互。除了使用功能分支,在做准备、维护和记录发布也使用各自的分支。

历史分支

Gitflow工作流使用2个分支来记录项目的历史。master分支存储了正式发布的历史,而develop分支作为功能的集成分支。

功能分支

功能分支不是从master分支上拉出新分支,而是使用develop分支作为父分支。当新功能完成时,合并回develop分支。新功能提交应该从不直接与master分支交互。

发布分支

一旦develop分支上有了做一次发布的,就从develop分支上fork一个发布分支。新建的分支用于开始发布循环,所以从这个时间点开始之后新的功能不能再加到这个分支上。这个分支只应该做Bug修复、文档生成和其它面向发布任务。一旦对外发布的工作都完成了,发布分支合并到master分支并分配一个版本号打好Tag。另外,这些从新建发布分支以来的做的修改要合并回develop分支。常用的分支约定:用于新建发布分支的分支(develop),用于合并的分支(master),分支命名(relese-X或 relese/X)

维护分支

维护分支或是热修复(hotfix)分支用于生成快速给产品发布版本打补丁,这是唯一可以从master分支fork出来的分支。修复完成,修改应该马上合并回master分支和develop分支(当前的发布分支),master分支应该用新的版本号打好Tag。

示例

  1. 创建开发分支。为master分支配套一个develop分支。简单来做可以本地创建一个空的develop分支,push到服务器上。git branch developgit push -u origin develop,以后这个分支会包含项目的全部历史,而master分支只包含部分历史,其他开发者应该克隆中央仓库,建好develop分支跟踪分支。git clone XXX.git,git checkout -b develop origin/develop
  2. A 和 B 开始开发新功能。新分支应基于develop。git checkout -b xxx develop.然后 git status/add/commit…
  3. A完成功能开发,合并到他本地的develop分支后push到中央仓库。git pull origin develop,git checkout develop,git merge xxx,git push,git branch -d xxx
  4. A 开始准备发布,他用一个新的分支做发布准备,这一步也确定了发布的版本号。git checkout -b release-0.1 develop。这个分支是清理发布,执行测试,更新文档等用于改善发布的分支。
  5. A 完成发布,一旦准备好对外发布,A合并并修改master分支和develop分支,删除发布分支。合并回develop分支很重要。发布分支是作为功能开发(develop)和对外发布(master)之间的缓冲。只要合并到master,就应该打好tag方便跟踪。
  6. 用户发现bug。 为了处理bug,A从master分支拉出一个维护分支,提交修改解决问题。然后直接合并到master分支,还有,这些信息需要包含到develop分支中。然后安全的删除这个维护分支。

forking工作流

forking工作流是分布式工作流,充分利用 git 在分支上的优势,可以安全的管理可靠的开发者,并且可以接受不信任的贡献者的提交.这种工作流不是使用单个服务器的中央仓库代码基线,而是让每个开发者都有一个仓库.每个代码贡献者由两个Git 仓库,一个是本地私有的,另一个服务端公开的.Forking 的优势还有,不需要所有人都能 push代码到中央仓库中,开发者 push 到自己的服务端仓库,而只有项目维护者才能 push 到正式仓库.这也成为了开源项目的理想工作流.

工作方式

和其他的 Git 工作流一样, Forking 工作流要先有一个公开的正式仓库存储在服务器上.但一个新的开发者想在项目上工作时,不是直接从正式仓库克隆,而是 fork 正式项目在服务器上创建一个拷贝.这个拷贝作为他个人公开仓库,其他开发者不允许 push 到这个仓库,但可以 pull 到修改.创建自己的服务器拷贝后就可以和往常一样执行 git clone 了.提交本地修改时, 提交到自己的公开仓库中,然后给正式仓库发起一个 pull request, 让项目维护者知道有新的集成了.维护者同意变更后会合并变更到自己本地的 master 中,然后 push master 分支到服务器的正式仓库中.

示例

  1. 开发者 fork 正式仓库

  2. 开发者克隆自己 fork 出来的仓库

    相比用 origin 远程别名指向中央仓库, forking 需要2个远程别名,一个指向正式仓库,一个指向自己的服务端仓库.常见约定使用 origin 作为远程克隆的仓库别名, upstream 作为正式仓库的别名.

  3. 开发者开发自己的功能

  4. 开发者发布自己的功能

    push 代码到自己的公开仓库,发起 pullRwquest 指定要合并的分支.一般是上游( upstream)的 master 分支

  5. 项目维护者集成开发者的功能

    项目维护者收到 pull request, 他有两种方式,一是直接在 pull request 中查看代码,二是 pull 代码到自己的本地仓库,再手动合并.如果出现合并冲突,需要用第二种方式解决.

  6. 开发者和正式仓库做同步

由于正式仓库更新,其他开发需要和正式仓库同步,git pull upstream master.

pull Request

Pull Request 可以让开发者更方便的进行协作,可以再代码合并之前对修改进行讨论.如果变更有任何问题,团队成员反馈在 PR 中,所有的这些活动都直接跟踪在 PR 中.

PR 需要提供4个信息以发起 pull Request: 源仓库,源分支,目的仓库,目的分支. PR 可以和以上的 git 工作流一起使用,基本过程是这样的:

  1. 开发者在本地仓库新建一个分支开发功能.
  2. 开发者 push 分支修改到公开的仓库中.
  3. 开发者通过公开的仓库发起一个 pull request
  4. 项目的其他成员 review code ,讨论并修改
  5. 项目维护者合并功能到官方仓库中并关闭 pull requset

GIt Flow 插件的使用

git flow 的简单介绍

git flow 是构建在 git 之上的一个组织软件开发活动的模型,是在 Git 之上构建的一项软件开发最佳实践,也是一套使用 Git 进行源代码管理的一套行为规范和简化部分 git 操作的工具.总之, git flow 就是通过在一个项目里划分不同的分支,来实现功能开发, bug 修复,版本发布,以及代码冲突处理等.

git flow 把分支划分了几个类别

  • Master (稳定无 BUG 发布版)
  • Develop (功能开发最前线)
  • Feature (为每一个新功能从 Develop 创建出来的分支)
  • Hotfix (紧急修复 BUG)
  • Release (版本发布,项目上线前的一些全面测试以及准备,同时也肩负版本归档,回滚支持)

git flow 插件的常用命令

(feature 版本)

  • 切换到相应目录 cd ..
  • 查看分支 git branch -a
  • 切换到相应分支 git checkout develop
  • 初始化 git flow init (-f)
  • 新建分支 git flow feature start xxx develop(基于创建的分支)
  • 发布分支 git flow feature publish
  • 操作 git add . / git status / git commit -m “feat: XXX”/git push
  • 结束分支 git flow feature finish XXX
  • 取得一个发布的新特性分支 git flow feature pull origin XXX
  • 跟踪在 origin 上的特性分支 git flow feature track XXX

(release版本)

  • 开始准备 release 版本 git flow release start RELESE [BASE 参数]
  • 创建后发布 git flow release publish RELESE
  • 签出远程变更 git flow release track RELESE
  • 完成release 版本 git flow release finish RELEASE

(hotfix 版本)

  • 开始紧急修复 git flow hotfix start version [BASENAME 版本号]
  • 完成紧急修复 git flow hotfix finish VERSION