我已经使用过Windows上的Git (msysGit) 一段时间了,并且我喜欢分布式源代码控制的理念。最近,我开始看Mercurial (hg),它看起来很有趣。然而,我无法理解hg和git之间的区别。
是否有人进行过git和hg的对比?我想知道hg和git之间的区别,而不必卷入支持者讨论。
我已经使用过Windows上的Git (msysGit) 一段时间了,并且我喜欢分布式源代码控制的理念。最近,我开始看Mercurial (hg),它看起来很有趣。然而,我无法理解hg和git之间的区别。
是否有人进行过git和hg的对比?我想知道hg和git之间的区别,而不必卷入支持者讨论。
编辑:将Git和Mercurial与名人进行比较似乎是一种趋势。这里还有一个:
我在Mercurial上工作,但从根本上来说,我认为两个系统是等价的。它们都使用相同的抽象:一系列快照(changesets),这些快照组成了历史记录。每个changeset都知道它来自哪里(父changeset)并且可以有多个子changesets。最近的hg-git扩展提供了Mercurial和Git之间的双向桥梁,也证明了这一点。
Git强调对这个历史图进行改变(带来的所有后果),而Mercurial并不鼓励重写历史,但仍然可以轻松地实现,而对此所产生的后果正是您应该期望的(也就是说,如果我修改了您已经拥有的一个changeset,则当您从我这里拉取时,您的客户端将看到它是新的)。因此,Mercurial具有偏向于非破坏性命令。
至于轻量级分支,自从……以来,Mercurial就支持具有多个分支的存储库。Git具有多个分支的存储库正是多个发展分岔的开发方向。然后,Git为这些分岔添加名称,并允许您在远程查询这些名称。Mercurial的Bookmarks扩展添加了本地名称,并且在Mercurial 1.6中,您可以在推送/拉取时移动这些书签。
我使用Linux,但显然,TortoiseHg在Windows上比Git更快,更好(由于更好地使用了可怜的Windows文件系统)。http://github.com和http://bitbucket.org都提供在线托管服务,Bitbucket的服务很棒,响应很快(我没有尝试过github)。
我选择Mercurial,因为它感觉干净而优雅——我对使用Git时得到的Shell / Perl / Ruby脚本感到厌烦。如果您想知道我的意思,请尝试一下git-instaweb.sh
文件:这是一个shell脚本,生成一个Ruby脚本,我认为它运行一个Web服务器。 shell脚本生成另一个shell脚本来启动第一个Ruby脚本。当然,还有一点Perl。
我喜欢这篇博客文章,它将Mercurial和Git与詹姆斯·邦德(James Bond)和麦克盖尔(MacGyver)进行了比较——Mercurial某种程度上比Git更低调。在我看来,使用Mercurial的人并不容易被吸引。这反映在每个系统如何执行Linus所描述的“最酷的合并!”. 在Git中,您可以通过执行以下操作
git fetch <project-to-union-merge>
GIT_INDEX_FILE=.git/tmp-index git-read-tree FETCH_HEAD
GIT_INDEX_FILE=.git/tmp-index git-checkout-cache -a -u
git-update-cache --add -- (GIT_INDEX_FILE=.git/tmp-index git-ls-files)
cp .git/FETCH_HEAD .git/MERGE_HEAD
git commit
这些命令看起来对我来说很晦涩。在Mercurial中,我们会执行:
hg pull --force <project-to-union-merge>
hg merge
hg commit
注意Mercurial命令非常简单,没有任何特殊之处--唯一不同的是--force
标志用于hg pull
,因为当你从一个无关的仓库pull时,Mercurial会中止操作。正是这样的差异让我感觉Mercurial更加优雅。
git pull <项目的URL>
。你引用的邮件来自git的早期阶段(2005年)。 - knittlGit是一个平台,而Mercurial只是一个应用程序。Git是一个带有分布式版本控制系统应用程序的版本化文件系统平台,但像其他平台应用程序一样,它更加复杂,并且具有较粗糙的边缘。但这也意味着,Git的版本控制系统非常灵活,您可以使用Git做许多与源代码控制无关的事情。
这就是区别的本质。
要深入理解Git,从存储库格式开始理解至关重要。Scott Chacon的“Git Talk”对此进行了很好的介绍。如果您不知道发生了什么,就试图使用Git,最终可能会感到困惑(除非您只使用非常基本的功能)。当你只需要一个每天编程例行事务中使用的DVCS时,这听起来可能很愚蠢,但Git的奇妙之处在于,存储库格式实际上非常简单,您可以相当轻松地理解Git的整个操作。
对于一些更加技术性的比较,我个人觉得Dustin Sallings的文章最好:
他实际上广泛使用过两种分布式版本控制系统,并且对它们都很了解-最终选择了git。主要的差异在于 Windows 上。Mercurial 受到原生支持,Git 则不受支持。你可以通过 bitbucket.org 获得与 github.com 非常相似的托管服务(实际上更好,因为你可以获得免费的私有代码库)。我曾经使用过 msysGit 一段时间,但现在转向了 Mercurial,并非常满意。
如果你是一位寻找基本离线版本控制的Windows开发人员,则选择Hg。我发现Git难以理解,而Hg则简单,并且与Windows shell 很好地集成。我下载了Hg并遵循了这个教程(hginit.com) - 十分钟后我就有了一个本地仓库,并且可以继续我的项目。
我认为有关"Mercurial vs.Git"的最佳描述是:
"Git就像韦斯利·斯尼普斯(Wesley Snipes),而Mercurial则是丹泽尔·华盛顿(Denzel Washington)"
从我个人的角度来看,Git 的模型与命名分支和在同一目录中切换分支之间的概念密切相关;Mercurial 可以通过命名分支做到相同的功能,但它鼓励使用克隆,我个人不太喜欢这种方法。
Git和Mercurial有一个巨大的区别,即它们表示每个提交(commit)的方式。Git将提交视为快照(snapshot),而Mercurial将其表示为差异(diffs)。
这在实践中意味着什么?嗯,在git中许多操作更快,比如切换到另一个提交、比较提交等,尤其是这些提交相距较远时。
据我所知,Mercurial的方法没有任何优势。
如果我正确理解它们(尽管我远非每个专家),这两种基本上有不同的哲学。 我最初使用Mercurial 9个月。现在我已经使用Git 6个月。
Hg是版本控制软件。它的主要目标是跟踪软件版本。
Git是一个基于时间的文件系统。它的目标是为文件系统添加另一个维度。大多数文件和文件夹,Git则添加了时间。这恰好能作为VCS运行是其设计的副产品。
在Hg中,它始终试图维护整个项目历史记录。默认情况下,我认为Hg希望在推送和拉取时获取所有用户对所有对象的所有更改。
在Git中,只有一组对象和这些跟踪文件(分支/头)来确定哪些对象集表示特定状态下文件树。在推送或拉取时,Git仅发送需要的对象,这是所有对象的一个小子集,用于推送或拉取特定的分支。
就Git而言,不存在“1个项目”的概念。您可以在同一个repo中拥有50个项目,Git不会介意。每个项目都可以在同一个repo中单独管理,并且可以很好地运行。
Hg中的分支概念是指从主项目或从分支等分支。Git没有这样的概念。在Git中,分支只是树的状态,所有内容都在分支中。哪个分支是官方的、当前的或最新的在Git中没有意义。
我不知道那是否有意义。如果我可以画图,Hg可能看起来像这样,其中每个提交都是o
o---o---o
/
o---o---o---o---o---o---o---o
\ /
o---o---o
具有单个根和从其分支出的树。虽然Git可以这样做,而且人们经常以这种方式使用它,但这并非强制要求。如果有这样一张Git图片,它可能很容易看起来像这样:
o---o---o---o---o
o---o---o---o
\
o---o
o---o---o---o
实际上,在某些方面,显示git中的分支甚至没有意义。
有一件非常令人困惑的事情是,Git和Mercurial都有一个叫做“分支”的东西,但它们根本不是同一种东西。在Mercurial中,当不同repo之间存在冲突时,就会出现一个分支。而在Git中,一个分支似乎类似于hg中的克隆。但是,尽管可能具有类似的行为,但克隆绝对不是相同的东西。考虑我使用相当大的Chromium repo在git与hg中尝试这些操作的情况。
$ time git checkout -b some-new-branch
Switched to new branch 'some-new-branch'
real 0m1.759s
user 0m1.596s
sys 0m0.144s
现在使用 hg clone 进行克隆
$ time hg clone project/ some-clone/
updating to branch default
29387 files updated, 0 files merged, 0 files removed, 0 files unresolved.
real 0m58.196s
user 0m19.901s
sys 0m8.957
这两个都是热运行。也就是说,我运行了两次,这是第二次运行。hg clone实际上与git-new-workdir相同。这两个都会创建一个全新的工作目录,几乎就像您键入了cp -r project project-clone
一样。这不同于在git中创建一个新分支。它更加重量级。如果有真正等同于git分支的东西,我不知道它是什么。
我从某种程度上理解hg和git 可能能够做类似的事情。如果是这样,那么它们所引导的工作流程仍然存在巨大的差异。在git中,典型的工作流程是为每个功能创建一个分支。
git checkout master
git checkout -b add-2nd-joypad-support
git checkout master
git checkout -b fix-game-save-bug
git checkout master
git checkout -b add-a-star-support
那刚刚创建了三个基于名为master的分支的分支。(我相信在Git中有一些方法可以使它们变成1行而不是2行)
现在只需对其中一个进行操作
git checkout fix-game-save-bug
然后开始工作。提交更改等等。即使在像 Chrome 这样的大型项目中切换分支也几乎是瞬间完成的。我实际上不知道如何在 hg 中做到这一点。这不是我读过的任何教程的一部分。
另一个重要的区别是 Git 的暂存区。
Git 有这个暂存区的概念。你可以将其视为隐藏文件夹。当你提交时,只提交暂存区中的内容,而不是你的工作目录中的更改。这可能听起来很奇怪。如果你想提交工作目录中所有的更改,你可以使用 git commit -a
命令,它会将所有修改过的文件添加到暂存区,然后提交它们。
那么暂存区的作用是什么呢?你可以轻松地将你的提交分开。想象一下,你编辑了 joypad.cpp 和 gamesave.cpp,你想分别提交它们。
git add joypad.cpp // copies to stage
git commit -m "added 2nd joypad support"
git add gamesave.cpp // copies to stage
git commit -m "fixed game save bug"
Git甚至有命令来决定你想复制到阶段的同一文件中的哪些特定行,因此您可以将这些提交单独拆分开。为什么要这样做呢?因为作为单独的提交,其他人可以只拉取他们想要的提交,或者如果出现问题,他们可以撤销仅包含问题的提交。
git add --patch
,请参考http://linux.die.net/man/1/git-add 或使用 git add -i
,例如 https://dev59.com/RnE95IYBdhLWcg3wSsCD。 - tanascius