Why Git is Better than X

最近我花费了大量时间为 Gitsters 辩护以对抗那些 fanboyism, bandwagonism 以及 koolaid-thirst 的指责。 为此我建设了此网站来说明大家为什么要从 X 转换至 Git,以及为何你也应该这么做。点击任何一个原因展开以查看详情。
hg   bzr   svn   perforce

便宜的本地分支

使 Git 从几乎所有 SCM 中脱颖而出并出并且最吸引人的特色,恐怕非它的分支模型莫属。 它完全不同于我在此用于比较的所有其他模型,那些模型所推荐的最佳分支方式仅仅是将库 (repository) 复制到一个新的目录而已。
Git 不那么做。 Git 允许你拥有多个完全独立的本地分支,创建、合并和删除这些分支仅需要几秒钟的时间。
这意味着你可以这样做:
  • 创建一个新分支尝试新的想法,提交几次,切换回原先的分支,应用一个 patch,然后再切换至刚才实验中的新分支,将其合并。
  • 一个分支用来存放将要发布的版本,另一个测试分支专门合并开发中的工作,其他数个小分支存放日常开发工作。
  • 为每一个开发中的新功能建立相应分支,这样便可以在这些分支中无缝切换,并在某个功能开发完毕合并进主分支后删除相应分支。
  • 创建一个分支来做实验,若发现行不通则直接删掉该分支;放弃这个分支,别人甚至不知道它存在过(即使这期间你已经 push 了其他分支)。
重要的是,当你向一个远程库 push 时,你 无需  push 所有分支。你可以只共享一个分支而不是全部。 这会推动大家尝试新想法而不用操心如何、何时合并或与他人共享。
使用其他系统,你也 可以找到一些方法来做同样的事,但会困难的多而且极易出错。 Git 让这个过程异常简单,而且当大部分开发者学习 Git 时,他们同时改变了他们的工作方式。
svn   perforce

所有内容都在本地

虽然所有分布式 SCM 都有这特点,但根据我的经验 Git 做的更好。除了 'fetch', 'pull' 和 'push', 你很少会用到其他需要跟你的硬盘以外的东西打交道的命令。
这不仅使大部分操作比你已经习惯的要快的多,而且让你可以离线工作。 这听起来不怎么样,不过我经常为自己需要离线完成那么多工作感到惊讶。 当你在飞机或火车上还可以建立分支、合并、提交以及浏览项目历史时,你的工作生产力会非常高。
即使是使用 Mercurial,诸如 'incoming' 和 'outgoing' 的常用命令也需要与服务器连接, 而 Git 让你可以在离线前从服务器上 'fetch' 所有数据,然后对原本在你本地分支中并不存在的数据进行比较、合并或查看历史纪录。
这意味着可以很容易的在你的 Git 库中同时保存你自己和与你协同工作的其他人的多个分支,而不会弄混任何内容。
bzr   svn   perforce

Git 很快

Git 很快。 包括大部分其他系统的忠实用户在内的人都这么评价 Git。 Git 所有操作都在本地进行的特性使它比 SVN 和 Perforce 要快,因为后两者的普通操作都要进行网络连接。 即使与其他允许本地操作的分布式 SCM 相比,Git 也要快得多。
部分原因可能是因为 Git 是被创造用来供 Linux 内核开发使用的,而那意味着从一开始它就需要高效处理大型库。 此外,Git 是用 C 语言编写的,这减少了运行期与高层语言进行协作的开销。Git 这么快的另一个原因是它的主要开发者把这当成设计目标。
我使用 Git,Mercurial 和 Bazaar 这三个不同的 SCM 各存放一份 Django 的源代码,进行了一些测试,下面是一些测试结果。 我也用 SVN 进行了一些测试,不过相应我,它要更慢 — 基本上是 Bazaar 的测试结果加上网络延迟...
   
   
测试结果表明除了增加新文件以外,所有的操作都是 Git 最快。(此外在一些非常大的提交操作测试中,Hg 基本上与 Git 一样快,不过我测试的那种提交操作实在太大, 你不大可能会遇到那种情况 — Git 处理普通提交比其他 SCM 要快得多)
Git Hg Bzr
Init 0.024s 0.059s 0.600s
Add 8.535s 0.368s 2.381s
Status 0.451s 1.946s 14.744s
Diff 0.543s 2.189s 14.248s
Tag 0.056s 1.201s 1.892s
Log 0.711s 2.650s 9.055s
Commit (Large) 12.480s 12.500s 23.002s
Commit (Small) 0.086s 0.517s 1.139s
Branch (Cold) 1.161s 94.681s 82.249s
Branch (Hot) 0.070s 12.300s 39.411s
Cold 和 Hot 是第一次和第二次对一个库进行分支操作的结果数字 — 第二次分支使用了硬盘缓存。
需要注意的是虽然 'add' 操作 Git 要慢很多,但这是在大量文件 — 超过 2000 个 — 上进行的新增操作。 对于大部分人的日常工作来说,任意一个系统上的新增操作只会花费几分之一秒。其他测试到的操作(可能除了大提交)都与日常使用到的相近。
这些测试结果并不难重现。只要用不同系统复制一份 Django 工程就可以比较出来了。
  • git clone git://github.com/brosner/django.git dj-git
  • hg clone http://hg.dpaste.com/django/trunk dj-hg
  • bzr branch lp:django dj-bzr
  • svn checkout http://code.djangoproject.com/svn/django/trunk dj-svn
svn

Git 很小巧

Git 真的非常善于节省磁盘空间。你的 Git 目录一般只会比一个 SVN checkout 大一点点 — 有时更小(显然 .svn 目录中的许多内容可以去掉)。
从 Django 工程 的同一个历史纪录点取出的不同部分的 clone,提供给我们这些数据。
Git Hg Bzr Bzr* SVN
Repo Alone 24M 34M 45M 89M
Entire Directory 43M 53M 64M 108M 61M
* 第二个 Bar 数字是我执行 'bzr pack' 后得到的,我本以为该命令会让它体积变小,但结果反而让它变得大得多。
hg   bzr   svn   perforce

暂存区域

不同于其他系统,Git 有它称之为暂存区域("staging area")或 "index" 的东西。 这是一个用来在提交前对提交内容进行设置的临时区域。
暂存区域最酷、也是让 Git 不同于其他工具的地方,是在你完成一部分文件的修改后,可以方便地 stage 并提交它们,同时又不用提交工作目录中其他已修改的文件或在提交命令中列出那些文件。
你还可以只 stage 已修改的一个文件的一部分内容。再也不会发生这样的事情了:对同一个文件中逻辑上并不相关的两部分进行修改后才发现没有对它们进行分别提交。 现在你可以先 stage 当前提交要包括的修改,然后 stage 下次提交要包括的修改。这一特性适用于你需要对文件进行的任意范围的修改。
当然,如果你不想控制这么多,你也可以很轻松的忽略这些特性 — 只需在提交命令上加上 '-a' ,就可以把所有修改过的文件加入到暂存区域中去了。
svn   perforce

分布式

包括 Git 在内的所有分布式 SCM 的最佳特性之一是分布式。这意味着你不是 "checkout" 源代码的最新版,而是 "clone" 整个代码库。
这意味着即使使用中央集中式的工作流,每一个用户都拥有一份主服务器的备份,每一份都可以在主服务器当机或损坏时用来替换它。使用 Git 便不存在单点故障了,除非只有一个点。
同时这不会使操作变得太慢。平均来说,SVN checkout 只比任何一种分布式 SCM 快一点。在我测试过的分布式 SCM 中,Git 是最快的。
Git 1m 59s
Hg 2m 24s
Bzr 5m 11s
SVN 1m 4s
svn   perforce

适用于任何工作流

Git 令人惊叹的特性之一是,由于其天生的分布式特征及强大的分支系统,可以轻而易举的应用任何想的到的工作流。

Subversion 式的工作流

集中式工作流是一种很常见的工作流,这对于那些从集中式系统迁移过来的人来说尤其如此。如果你上次 fetch 过后,已经有其他人进行了 push 操作,那么 Git 将不允许你直接 push; 所以这种所有开发者向同一台服务器 push 的集中式模型可以工作的很好。

集成管理员工作流

另一种常见工作流是有一名集成管理员专门负责向 'blessed' 库提交,其他开发者复制该库,push 到他们自己独立的库,随后请求集成管理员 pull 他们的修改。 这是开源工程或 GitHub 库中很常见的一种开发模式。

司令官与副官工作流

对于规模更庞大的项目,你可以让开发者使用类似 Linux 内核开发的工作流,每一个子系统都有专人(副官)负责合并与该子系统相关的修改。 另有一名整合者(司令官)只从副官那里 pull ,然后 push 到 'blessed' 库,其他所有人则再从 'blessed' 库复制。

再次强调,对于工作流 Git 非常有弹性,你可以混合及选用任何适合你的工作流。
hg   bzr   svn   perforce

GitHub

我本人在   GitHub  工作,所以这   可能  显得有点偏颇, 不过我还是加入了这一部分,因为很多人说正是 GitHub 让他们选择了 Git 。
GitHub 是很多人使用 Git 的原因,相比简单的托管网站,它更象一个社交网络。 人们找到与他们在做的事相关(似)的其他开发人员或项目,然后轻松地 fork 和贡献,这样形成了一个以 Git 和 各种项目为中心的活跃社区。
也有其他许多针对 Git 和其他 SCM 的服务,但很少有用户导向或社交导向的,更没有哪个是基于用户群的。 GitHub 的社交性是杀手级特性,上述特性使得 Git 和 GitHub 成为快速开发开源项目的最佳组合。
其他任何一种 SCM 都不提供这样的社区。
perforce

容易学习

本来并非如此 — 早期的 Git 并不是真正意义上的 SCM,而更象一套让你可以用分布式的方式进行版本控制的工具。 但是现在 Git 命令集和学习曲线已经和其他 SCM 类似,甚至比其中一些更好。
不作针对性的研究很难证明这一点,在此我仅仅演示一下 Mercurial 和 Git 命令中的默认帮助菜单的区别。这两个系统中相同(或相近)的命令将被高亮显示。 (在 Hg 中,如果你输入 'hg help',你会得到一份 40 多个命令的清单。)

Mercurial Help

add        add the specified files ...

annotate   show changeset informati...

clone      make a copy of an existi...

commit     commit the specified fil...

diff       diff repository (or sele...

export     dump the header and diff...

init       create a new repository ...

log        show revision history of...

merge      merge working directory ...

parents    show the parents of the ...

pull       pull changes from the sp...

push       push changes to the spec...

remove     remove the specified fil...

serve      export the repository vi...

status     show changed files in th...

update     update working directory

Git Help

add        Add file contents to the index

bisect     Find the change that introduce...

branch     List, create, or delete branches

checkout   Checkout a branch or paths to ...

clone      Clone a repository into a new ...

commit     Record changes to the repository

diff       Show changes between commits, ...

fetch      Download objects and refs from...

grep       Print lines matching a pattern

init       Create an empty git repository

log        Show commit logs

merge      Join two or more development h...

mv         Move or rename a file, a direc...

pull       Fetch from and merge with anot...

push       Update remote refs along with ...

rebase     Forward-port local commits to ...

reset      Reset current HEAD to the spec...

rm         Remove files from the working ...

show       Show various types of objects

status     Show the working tree status

tag        Create, list, delete or verify...

在 Git 1.6 之前,所有 Git 命令都存放在可执行路径下,这让使用者非常迷惑。 现在虽然 Git 仍能识别所有这些命令,但存放在可执行路径下的只有 'git' 这一命令。 如果你比较 Mercurial 和 Git 会发现,Git 的命令集与帮助系统与 Mercurial 几乎完全一样 — 从初学者的 UI 角度来说两者几乎没有区别。
现在已经很难说 Mercurial 或 Bazaar 比 Git 更易学了。

你可能感兴趣的:(git)