Why Git is Better than X
Why Git is Better than X
hg bzr svn perforce
我会做这个网站是因为我花了很多时间在替Gitsters 辩护,对抗那些狂热者(fanboyism),从众者(badwagonism) 还有koolaid-thirst。这里要说明的就是为什么大家都要从X 换成Git,而为什么你也应该这样做的原因。直接点击任何一个原因来展开查看。
使Git 从几乎所有其他SCM 中脱颖而出,最受瞩目的特色,恐怕非它的分支模型莫属。它完全不同于我在此一起比较的其他模型,大部分它们推荐的最佳分支方法仅仅只是复制仓储(repository) 到新的目录而已。
Git 可不这么做。Git 让你可以拥有多个本地的分支,它们可能是完全独立的,而且建立、合并和删除这些开发的支线只需要几秒钟的时间。
这表示你可以这样做:
- 建立一个分支来试试新点子,提交(commit) 个几次然后切回你原本的分支,加上一个patch 然后再切回刚刚实验用的分支,把它合并进来。
- 有一个分支只用来放要释出的版本,另一个用来合并开发中的部份供测试,其他几个小分支用来放每天的开发工作。
- 替每一个你正在实做的新功能建立新的分支,然后你就可以平顺的在它们之中切换,最后删除掉每一个新功能已经合并回主线的分支。
- 建立一个新的分支做实验,结果发现这样行不通就删掉这个分支;放弃一个分支,甚至没有任何人知道它曾经存在(同时你还可以把其他的分支公布出去)
最重要的是,当你要发布到一个远端的仓储,你不需要把你所有的分支都推出去。你可以只分享你的分支的其中一个而不是全部。这让大家可以尝试新的点子而不需要担心要计划要如何、何时合并或与其他人分享。
你在其他系统上可以找到方法做同样的事,但是会比较困难且容易出错。Git让这个过程变得非常简单,而且当开发人员开始学习,它常常会改变他们工作的方法。
这基本上对所有分散式SCM 来说都是一样的,但是在我的经验中Git 把这个特性发挥的更好。除了'fetch', 'pull' 和'push' 这些命令外,几乎没有其他命令会需要硬碟之外的东西。
这不只让大部分操作变得比你可能习惯的还要快得多,它还让你可以离线工作。这听起来也许没有什么,但是我总是惊讶于我有多么常离线工作。当你在飞机上或火车上,你还可以建立分支、合并和提交工作、浏览专案的历史,这是多么的有生产力。
就算是用Mercurial,一些常用的指令如'incoming' 和'outgoing' 也需要连线伺服器,而用Git 你可以在离线前'fetch' 伺服器上所有的资料,然后比较、合并和查看纪录,这些资料原本是在伺服器上还没有在你的本分支中的。
这表示你可以很容易拥有不只你自己的分支的副本,还有其他任何和你一起工作的人的分支都可以存在你的Git 仓储中而不打乱你原有的东西。
Git 很快。大家都这么说,甚至那些其他系统的死忠支持者也都会给予Git 这个评价。使用Git,所有的操作都是在本地端的特性让它比SVN 与Perforce 跑得快许多,它们两个都需要网路连线才能完成大部分操作。然而,就算是与其他也是在本地端操作的DSCM 比较,Git 还是快非常多。
一部分的原因可能是因为它是建立来用在Linux 核心上的,这表示它从一开始就必须有效率的处理非常大的仓储。此外,因为Git 是用C 写的,减少了使用其他高阶语言在执行期的开销。另外一个Git 这么快地原因是因为它的主要开发者们将这个列为设计的目标。
底下是一些我测试的数据,使用Django 的原始码仓储与三种不同的SCM: Git, Mercurial 和Bazaar。我也用SVN 测试了一些同样的项目,不过相信我,它慢更多— 基本上是Bazaar 的数字再加上网路的延迟...
|
|
|
测试的结果是所有操作,除了加新档案之外都是Git 最快。(还有大量的提交操作,Hg 基本上一样快,可是我测试的提交量是如此之大,你平常不太可能有同样的的量— 正常的提交操作在Git 快多了。)
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' 操作的速度慢很多,但这是在大量的档案— 超过2000 个— 上进行新增操作。对于大部分人日常使用来说,在任何系统上新增操作都只会用到几分之一秒而已。其他测试到的操作(除了大量提交...大概) 应该与你日常用到的差不多。
这些数字不会很难重现,只要用不同的系统clone 一份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
Git 真的很懂得怎么节省磁碟空间。你的Git 目录只会(一般来说) 比一个SVN checkout 大一点点— 一些情况下甚至更小(显然.svn 目录里面有很多东西可以丢掉)。
以下数据是用不同系统使用同样的历史纪录点取出Django 之后得到。
Git |
Hg |
Bzr |
Bzr* |
SVN |
|
Repo Alone |
24M |
34M |
45M |
89M |
|
Entire Directory |
43M |
53M |
64M |
108M |
61M |
* 第二个Bzr 数字是我执行'bzr pack' 后得到,我原本以为会让它更小,结果反而让它变大许多...。
和其他系统不一样,Git 有它称为"staging area" 或"index" 的东西。这是一个中间地带让你可以在提交前设定你想要提交什么。
Staging area 最酷的地方,让Git 远远抛开其他工具的,就是你可以轻易的在工作告一段落后stage 一些你的档案,然后提交上去而不需要提交所有修改过的档案,或是必须在命令列上列出所有想要提交的档案。
这还允许你只stage 修改过的档案的一部分。想像有一天你对一个档案做了两项毫不相关的修改,然后你发现忘了先提交其中一个。现在你可以只stage 你现在要提交的部份,然后在stage 剩下的改变给下一次提交。这个功能可扩大应用到任何你对档案的改变。
当然了,Git 也可以很简单的略过这些特性。如果你不想要控制这么多— 只要加上'-a' 到你的commit 命令就可以一次把所有的修改都丢到staging area 去。
任何分散式SCM,当然包括Git,最酷的功能之一就是它是分散式的。这表示你不是只"checkout" 目前最新版的原始码,而是"clone" 整个仓储。
这表示甚至你是使用中央集中式的工作流程,每一位使用者都有会一份主伺服器的备份,每一份都可以在主伺服器当机或损坏时推上去取代主伺服器。基本上使用Git 不会因为遗失单一的点而造成灾难,除非就只有那一个点。
而且这不会使得操作变慢太多。平均来说,一次SVN 的checkout 只比其他DSCM 快一点。当然在我测试过的DSCM 中,Git 是最快的。
|
其中一个Git 令人惊讶的事情就是因为它的分散式设计以及超级分支系统,你可以轻易的实做出几乎任何你想得到的工作流程。
Subversion 式的工作流程
这是一种很常见的Git 工作流程,特别是那些从集中管理式系统转换过来的人会使用的,是一种集中管理式的工作流程。如果在你最后一次fetch 后有人发布过改变,Git 不会允许你跟着发布,所以使用这种集中式的模型,所有的开发人员都发布到同一个伺服器也可以工作的很好。
整合管理员工作流程
另外一种常见的Git 工作流程就是有一个整合管理员— 一个负责提交到'blessed' 仓储的人,然后其他数位开发人员从这个仓储复制,发布到他们自己的独立仓储去,然后要求整合者pull 他们的修改。这是在开放原始码界或是GitHub 仓储上常见的开发模型。
司令官与副手的工作流程
对于一些更复杂的专案,你可以让你的开发人员们使用类似于Linux 核心的开发流程,开发人员们各自负责专案中不同的子系统(副手) 然后合并所有关于此子系统的改变。另外一位整合者(司令官) 只可以从他的副手手上pull 改变,然后发布到'blessed' 仓储让所有人都可以复制回去。
在一次的,Git 是完全非常有弹性的,所以你可以混合和取用适合你的工作流程。
这由我来说可能有点偏颇,因为我替 GitHub 工作,但是我还是决定要写这一部份,因为很多人说他们是因为GitHub而选择Git。
GitHub 是很多人使用Git 的原因之一,因为它更像是一个社交网路而不仅仅是简单的hosting 服务。人们找到其他开发人员或是专案,和他们想要做的事类似,因此可以轻易的分支然后贡献,以Git 和各种专案为中心创造出一个非常活跃的社群。
网路上还有其他类似的服务,有Git 的也有其他SCM 的,但是很少是使用者导向或社交导向的,没有一个其他服务有类似的用户群。这个GitHub 的社交观点是它的杀手级应用,合并以上的特色使得使用Git 与GitHub 工作变成快速开发开放原始码专案的极佳组合。
这样的社群不是其他SCM 所拥有的。
这本来不是真的— 早期Git 不是一个真正的SCM,比较像是一组工具让你可以用分散式的观点做出有版本控制的档案系统。但是现在,Git 的命令集以及学习曲线已经变得和其他SCM 类似,甚至比一些更好。
不特别去做研究的话很难证明这一点,我在这仅显示出Mercurial 与Git 的预设'help' 菜单之间的差异。我把两个系统间相同(或是近似) 的命令做了高亮显示。(在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 或Bzr 比Git 容易学习了。
This site is built and maintained by Scott Chacon , a GitHubber .
If you disagree with anything on the site and you have a good reason, pleaseemail me so I
can fix it.
The source for this site is on GitHub —feel free to send patches if you want
to improve it.