Git 和 SVN/CVS

大学两年里,接触了三种版本控制系统:

  1. 第一个接触是 SVN。学子天地 网站目前使用的版本控制器就是 SVN。作为第一个接触的版本控制系统,SVN 给我一个很新鲜的感觉。SVN 是集中式的版本控制系统,即版本仓库是在一个服务器上,所有开发者从这个“中心版本库”里 checkout, update,然后向“中心版本库“ commit 自己的修改。
  2. 接触 SVN 大约半年之后,开始接触 Git。目前我自己的私人项目都使用 Git 来管理代码,并且在 Github 和 Bitbucket 上托管。Git 不同于 SVN,它是一个分布式的版本控制系统。所谓分布式是指每个开发者都拥有自己的代码仓库,并且可以从其他开发者(也包括服务器)拉取代码更新,Git 和 SVN 的区别在下文会做进一步的阐述。
  3. CVS 并没有作研究,实验室的版本库曾经是 CVS,当时用着跟 SVN 差不多,但它对文件的管理使用的是悲观锁。因为没研究过,所以就不做说明了。

Git 的特别

  1. Git 直接保存快照

Git 关心的是文件数据的整体是否发生变化。而大多是版本控制器是关系文件修改前后的具体差异。也就是说,Git 的每一次 commit 都会保存一份所有被跟踪的文件的快照,然后保存一个指向这个快照的索引。当然,为了提高性能,对于没有修改的文件,只保存指向上一个版本的连接。

  1. Git 是分布式版本控制系统(Distributed Version Control System)。

Git 的一个很特别之处是它是一个分布式版本控制系统。

  • 克隆镜像:SVN checkout 时,默认是将仓库中的最新版本代码提取出来。而 Git 则是将整个版本库完整地克隆到本地形成一个镜像。
  • 本地操作:SVN 所有 commit 都是向服务器提交,其他开发者再从 Server 上 update 最新的代码。所有的操作都需要和服务器通讯,也就是要求提交或者更新代码都需要能连通服务器。Git 近乎所有的操作都在本地进行,因为 Git 是将版本库完整地 clone 到本地,相当于本地就有一个版本库,所有的 commit 都向本地版本库发送。这样可以方便开发者在无法联网的情况下依然可以正常开发项目。(而我也常常使用这个特性来对自己的代码进行管理)
  • 从任何一个仓库拉取提交:git clone 版本库到本地,所以每一个开发者都拥有一份完整的版本库,所以任何一份版本库都可能被拉取提交。
  • 因为每个版本库都是完整的 clone 所以每个私人版本库之间都可以相互提交修改:
  1. Git 的分支与合并

分支是指你可以从开发主线上分离开来,在不影响开发主线的前提下进行新的功能、特性开发。

Git 的分支功能是我最喜欢的一个功能。刚从 SVN 的世界脱离到 Git 时,也许会不习惯,但你会喜欢上它的。

SVN (和大多数版本控制器)的世界里,基本没有分支功能。或者需要分支的时候,要么重新建立一个新的版本库,在同一个版本库里拷贝一个副本进行开发。这样实现分支显得有些不太舒服,对大项目来说创建分支的代价是巨大的。

Git 的世界里,分支的使用显得很频繁。(并且 Git 是鼓励使用分支和合并功能)在上文提及过 Git 通过记录文件的快照来保存每一次提交的版本。Git 中的分支,实际上就是指向提交对象的可变指针。所以在创建分支、分支切换、分支删除的时候都可以很快就执行完毕,Git 的分支管理代码非常之小。

Git 分支模型

良好的 Git 分支使用,能够极大程度的提高开发效率,下面介绍一种 Git 的分支模型。

有两个分支是整个开发过程都存在的:

  • master
  • develop

关于这两个分支,有以下的说明:

  • 每一个开发者需要与 origin/master 保持同步。
  • origin/master 分支总是产品预备发布状态,也就是说 origin/master 必须永远保持可用状态。
  • origin/develop 分支处于开发状态,反应了代码的最新情况。
  • origin/develop 分支处于一个稳定的状态的时候,则可以进行发布。
  • origin/develop 分支的所有修改以及标注都需要合并到 origin/master 分支中。

另外还有 3 个支撑分支:

  • feature
    • feature 分支用于开发新的特性。他从 develop 分支分离出来,并且当新特性开发完成后合并回 develop.

    • 分支命名:feature-xxx

    • 示范:

      $ git checkout -b feature-xxx develop
      // finish develop new feature
      $ git checkout develop
      $ git merge --no-ff feature-xxx
      $ git branch -d feature-xxx
      $ git push origin develop
      
  • release
    • release 分支预发布状态的版本。release 分支下可以对代码进行小型的 bug 修复,以及做元数据的修改,如发布版本,发布时间等信息。

    • release 分支从 develop 分离出来,最终必须合并到 masterdevelop 分支。

    • 分支命名:release-xxx

    • 示范:

      $ git checkout -b release-1.0 develop
      $ ./release-action.sh 1.0
      $ git add ./
      $ git commit -m "Release 1.0"
      $ git checkout master
      $ git merge --no-ff release-1.0
      $ git tag -a 1.0
      $ git checkout develop
      $ git merge --no-ff release-1.0
      $ git branch -D release-1.0
      
  • hotfix
    • hotfix 分支是在预备发布阶段对严重的 bug 进行修复的分支。

    • hotfix 分支从 __master__ 分离出来,最终必须合并到 __master__ 和 __develop__.

    • 分支命名:hotfix-*

    • 示范:

      $ git checkout -b hotfix-1.0 master
      $ ./hotfix
      $ git commit -m "Hotfix"
      $ git checkout master
      $ git merge --no-ff hotfix-1.0
      $ git checkout develop
      $ git merge --no-ff hotfix-1.0
      $ git branch -D hotfix-1.0