代码之家  ›  专栏  ›  技术社区  ›  TM. Randy Simon

Git和Mercurial-比较和对比

  •  514
  • TM. Randy Simon  · 技术社区  · 15 年前

    一段时间以来,我一直在利用颠覆来完成我的个人项目。

    我越来越多地听到关于git、mercurial和dvc的好消息。

    我想试一试整个数字视频控制系统,但我对这两个选项都不太熟悉。

    Mercurial和Git有什么区别?

    注:我是 试着找出哪一个是“最好的”,甚至是我应该从哪一个开始。我主要是在关键领域寻找它们相似的地方和不同的地方,因为我有兴趣知道它们在实施和哲学方面有什么不同。

    11 回复  |  直到 6 年前
        1
  •  445
  •   Vadim Kotov First Zero    7 年前

    免责声明: 我使用git,在git邮件列表中跟踪git的开发,甚至为git(主要是gitweb)做了一些贡献。我从文档中了解到mercurial,还有一些是从freenode上的revctrl irc频道讨论中了解到的。

    感谢Mercurial IRC频道上的所有人,他们为本文提供了有关Mercurial的帮助。



    总结

    这里最好有一些表的语法,比如phpmarkdown/multimarkdown/maruku-extension-of-markdown

    • 存储库结构: Mercurial不允许八达通合并(有两个以上的父对象),也不允许标记非提交对象。
    • 标签: Mercurial使用版本 .hgtags 为每个存储库标记使用特殊规则的文件,并且还支持中的本地标记 .hg/localtags ;在git中,标记是驻留在 refs/tags/ 名称空间,默认情况下,获取时自动收集,需要显式推送。
    • 分支机构: 在Mercurial中,基本工作流基于 匿名头 ;Git使用轻量级的命名分支,并具有特殊类型的分支( 远程跟踪分支 )在远程存储库的分支之后。
    • 修订名称和范围: Mercurial提供 修订号 ,本地到存储库,并在此基础上建立相对修订(从tip开始计算,即当前分支)和修订范围 地方的 编号;Git提供了一种相对于分支提示引用修订的方法,修订范围是拓扑的(基于修订图)
    • 汞的用途 重命名跟踪 ,而Git使用 重命名检测 处理文件重命名
    • 网络: Mercurial支持ssh和http“智能”协议以及静态http协议;现代git支持ssh、http和git“智能”协议以及http(s)“哑”协议。它们都支持离线传输的bundles文件。
    • 汞的用途 扩展 (插件)和已建立的API;Git已经 脚本性 以及既定的格式。

    有一些东西与Git的Mercurial不同,但是还有其他一些东西使它们相似。两个项目都互相借鉴。例如 hg bisect Mercurial中的命令(以前为 bisect extension )灵感来自 git bisect 在Git中使用命令,而 git bundle 受到启发 hg bundle .

    存储库结构,存储修订

    在Git中,对象数据库中有四种类型的对象: 斑点 包含文件内容、层次结构的对象 存储目录结构的对象,包括文件名和文件权限的相关部分(文件的可执行权限,作为符号链接)。 犯罪 对象,其中包含作者信息、指向由提交(通过项目顶部目录的树对象)表示的修订时存储库状态快照的指针,以及对零个或多个父提交的引用,以及 标签 引用其他对象并可以使用pgp/gpg签名的对象。

    Git使用两种存储对象的方法: 释放 格式,其中每个对象存储在单独的文件中(这些文件只写一次,从不修改),以及 拥挤的 在一个文件中存储多个对象的增量压缩格式。操作的原子性是由这样一个事实提供的:对新对象的引用是在写入对象之后写入的(原子性地,使用create+rename技巧)。

    Git存储库需要使用 git gc (为了减少磁盘空间和提高性能),尽管现在Git会自动这样做。(此方法可以更好地压缩存储库。)

    mercurial(据我所知)将文件的历史存储在 文件记录 (我认为,与其他元数据(如重命名跟踪)和一些助手信息一起使用);它使用的平面结构称为 显示 存储目录结构和调用的结构 长乐阁 它存储有关变更集(修订)的信息,包括提交消息和零、一个或两个父级。

    汞的用途 交易日记帐 提供操作的原子性,并依赖于 截断 操作失败或中断后要清理的文件。revlogs仅追加。

    从Git和Mercurial中的存储库结构可以看出,Git更像对象数据库(或内容寻址文件系统),而Mercurial更像传统的固定字段关系数据库。

    差异:
    在Git中 对象形成 分级的 结构;汞 显示 文件是 平的 结构。在GIT中 斑点 对象存储 一个版本 文件内容的;反复无常的 文件记录 商店 单个文件的整个历史记录 (如果我们不考虑重命名的任何并发症)。这意味着,在不同的操作领域,Git将比Mercurial更快,所有其他被认为是相同的东西(如合并,或显示项目历史),以及Mercurial将比Git更快的领域(如应用补丁或显示单个文件的历史)。 这个问题对最终用户可能并不重要。

    因为Mercurial的固定记录结构 长乐阁 结构,mercurial中的提交只能 最多两个家长 ;Git中的提交可以有两个以上的父级(称为“八达通合并”)。虽然(理论上)可以用一系列的双亲合并来替换章鱼合并,但在Mercurial和Git存储库之间转换时,这可能会导致复杂的问题。

    据我所知,Mercurial没有 带注释标签 (标记对象)来自Git。注释标签的特殊情况是 签名标签 (带有PGP/GPG签名);可使用 GpgExtension ,该扩展将与Mercurial一起分发。你不能 标记非提交对象 在Mercurial中,就像在Git中一样,但这并不重要,我认为(一些Git存储库使用标记blob来分发用于验证签名标签的公共PGP密钥)。

    参考:分支和标记

    在Git引用(分支、远程跟踪分支和标记)中,它们驻留在提交的DAG之外(应该如此)。参考文献 refs/heads/ 命名空间(命名空间) 当地分支机构 )指向提交,通常由“git commit”更新;它们指向分支的提示(头),这就是为什么使用这个名称。参考文献 refs/remotes/<remotename>/ 命名空间(命名空间) 远程跟踪分支 )指向提交,跟踪远程存储库中的分支 <remotename> ,并由“git fetch”或等效工具更新。参考文献 参考/标签/ 命名空间(命名空间) 标签 )通常指向提交(轻量级标记)或标记对象(带注释和签名的标记),不打算更改。

    标签

    在Mercurial中,可以使用 标签 ;标记的存储方式与忽略模式类似。这意味着全局可见的标签存储在版本控制中。 HGTAG 存储库中的文件。这有两个后果:第一,Mercurial必须对此文件使用特殊规则,以获取所有标记的当前列表并更新此类文件(例如,它读取文件的最新提交的修订版,而不是当前签出的版本);第二,您必须提交对此文件的更改,以使其他用户/其他存储库可以看到新标记。(据我所知)。

    Mercurial还支持 本地标签 ,存储在 hg/localtags 其他人看不见的(当然不可转让)

    在git中,标记是存储在 参考文献/标签/ 命名空间。默认情况下,当获取或推送一组修订时,Git会自动获取或推送指向正在获取或推送修订的标记。不过,你可以 控制 在某种程度上 提取哪些标签 或推。

    Git处理轻量级标记(直接指向提交)和带注释的标记(指向标记对象,其中包含标记消息,可以选择包含pgp签名,而pgp签名又指向提交),稍有不同,例如,默认情况下,在使用“Git describe”描述提交时,它只考虑带注释的标记。

    在Mercurial中,Git没有严格的本地标签等价物。然而,Git最佳实践建议设置单独的公共裸机存储库,将准备好的更改推送到其中,并从中克隆和获取其他存储库。这意味着不推送的标记(和分支)对存储库是私有的。另一方面,您也可以使用除 heads , remotes tags ,例如 local-tags 用于本地标签。

    个人意见: 在我看来,标签应该位于修订图的外部,因为它们是修订图的外部(它们是指向修订图的指针)。标记应该是非版本化的,但可以转移。Mercurial选择使用类似于忽略文件的机制,这意味着它要么必须处理 HGTAG 特别是(树中的文件是可传输的,但普通的是版本控制的),或者具有仅本地的标记( Hg/LoopLink 是非版本化的,但不可传输)。

    分支机构

    在GIT中 本地分支 (分支提示或分支头)是对提交的命名引用,可以在其中生成新的提交。分支还可以表示活动的开发线,即可以从分支提示访问的所有提交。本地分支机构位于 裁判/指挥部/ 命名空间,例如“master”分支的完全限定名为“refs/heads/master”。

    git中的当前分支(即已签出的分支,以及将要进行新提交的分支)是由head refer引用的分支。可以让head直接指向提交,而不是符号引用;这种匿名匿名匿名分支的情况称为 分离头 (“Git Branch”显示您处于“(无分支)”状态。

    在Mercurial中有匿名分支(分支头),可以使用书签(通过 bookmark extension )这样 书签分支 完全是本地的,并且这些名称(直到1.6版)不能使用mercurial进行转换。可以使用rsync或scp复制 .hg/bookmarks 文件到远程存储库。您也可以使用 hg id -r <bookmark> <url> 获取书签当前提示的修订ID。

    因为可以推/拉1.6个书签。这个 BookmarksExtension 页面上有节 Working With Remote Repositories . 不同的是,在变化莫测的书签名称中 全球的 ,而git中“remote”的定义也描述了 分支名称映射 从远程存储库中的名称到本地远程跟踪分支的名称;例如 refs/heads/*:refs/remotes/origin/* 映射意味着可以在远程存储库的“源站/主站”远程跟踪分支(“refs/remotes/origin/master”)中找到“master”分支(“refs/heads/master”)的状态。

    Mercurial也有 命名分支 ,其中分支名称是 嵌入的 在提交中(在变更集中)。这样的名称是全局的(在获取时传输)。这些分支名称作为变更集\u2019s元数据的一部分永久记录。使用Modern Mercurial,您可以关闭“已命名分支”并停止记录分支名称。在这个机制中,树枝的尖端是动态计算的。

    在我看来,Mercurial的“指定分支”应该称为 提交标签 相反,因为这就是他们的本来面目。在某些情况下,“命名分支”可以有多个提示(多个无子提交),也可以由修订图的几个不相交的部分组成。

    在Git中没有类似于那些反复无常的“嵌入式分支”;而且Git的哲学是,尽管可以说分支包含一些提交,但并不意味着提交属于某个分支。

    请注意,Mercurial文档仍然建议至少对长寿的分支(每个存储库的单个分支工作流)使用单独的克隆(单独的存储库),即 克隆分支 .

    推动中的分支

    默认情况下的mercurial push 所有头 . 如果你想推动一个分支( 单头 )必须指定要推送的分支的提示修订。可以通过分支提示的修订号(本地到存储库)、修订标识符、书签名称(本地到存储库,不传输)或嵌入分支名称(命名分支)来指定分支提示。

    据我所知,如果您推送一系列包含提交的修订,用mercurial的说法标记为“已命名分支”,那么您将在推送到的存储库中拥有这个“已命名分支”。这意味着这些嵌入分支的名称(“命名分支”)是 全球的 (关于给定存储库/项目的克隆)。

    违约(以 push.default 配置变量)“git push”或“git push< 遥远的 >“Git会推 匹配的分支 也就是说,只有那些本地分支在您推入的远程存储库中已经存在它们的等效分支。你可以使用 --all 选择git push(“git push--all”)进行push 所有分支 ,您可以使用“git push<” 遥远的 &; 分支 “推一个 给定单个分支 ,您可以使用“git push<” 遥远的 >头部“推动 电流分支 .

    以上所有假设都假设Git没有配置要通过哪些分支进行推送 remote.<remotename>.push 配置变量。

    提取中的分支

    注: 这里我使用git术语,其中“fetch”意味着从远程存储库下载更改。 没有 将这些变化与当地工作相结合。这是什么? git fetch “和” hg pull “是的。

    如果我理解正确,默认情况下是mercurial fetches 所有头 从远程存储库,但可以指定要通过其获取的分支“ hg pull --rev <rev> <url> “或” hg pull <url>#<rev> “得到 单支路 . 您可以使用修订标识符、“命名分支”名称(changelog中嵌入的分支)或书签名称指定<rev>。但是书签名称(至少目前)不会被传输。您得到的所有“命名分支”修订都属于“转移”。hg pull“存储它作为匿名的、未命名的头提取的分支的提示。

    在git中默认(对于“git clone”创建的“origin”远程,以及对于使用“git remote add”创建的远程) 吉特取出 “(或) git fetch <remote> “”得到 所有分支 从远程存储库(从 参考/标题/ 名称空间),并将它们存储在 refs/remotes/ 命名空间。这意味着,例如,远程“origin”中名为“master”(全名:“refs/heads/master”)的分支将存储(保存)为“origin/master” 远程跟踪分支 (全名:“refs/remotes/origin/master”)。

    你可以拿来 单支路 在GIT中使用 git fetch <remote> <branch> -Git会将请求的分支存储在fetch-head中,类似于mercurial未命名的heads。

    这些只是一些默认情况下 ReFSPEC Git语法:使用refspec,您可以指定和/或配置要获取的分支以及存储它们的位置。例如,默认的“fetch all branches”大小写由“+refs/heads/*:refs/remotes/origin/*”通配符refspec表示,“fetch single branch”是“refs/heads/<branch>:”的简写。refspecs用于将远程存储库中分支(refs)的名称映射到本地refs名称。但是,您不需要知道(很多)关于refspecs的信息,就可以有效地使用git(主要归功于“git-remote”命令)。

    个人意见: 我个人认为mercurial中的“命名分支”(在changeset元数据中嵌入了分支名称)在其全局名称空间中是错误的设计,特别是对于 分布式的 版本控制系统。例如,让我们以Alice和Bob在其存储库中都有“named branch”命名为“for joe”,而这些分支没有共同点为例。然而,在乔的仓库里,这两个分支会被当作一个分支来对待。因此,您不知何故想出了防止分支名称冲突的约定。这与Git无关,在Joe的存储库中,Alice的“for Joe”分支将是“Alice/for Joe”,Bob的分支将是“Bob/for Joe”。也见 Separating branch name from branch identity 在Mercurial wiki上提出的问题。

    Mercurial的“书签分支”目前缺少核心分发机制。

    差异:
    这是Mercurial和Git的主要区别之一,因为 james woodyatt Steve Losh 在他们的回答中说。默认情况下,Mercurial使用匿名的轻量级代码行,在其术语中称为“heads”。Git使用轻量级的命名分支,通过内射映射将远程存储库中分支的名称映射到远程跟踪分支的名称。Git“强制”您命名分支(好吧,除了一个未命名的分支,这种情况称为分离头),但我认为这对于分支繁重的工作流(如主题分支工作流)更好,这意味着在单个存储库范式中有多个分支。

    命名修订

    在Git中,有许多命名修订的方法(如 git rev-parse MangPLE):

    • 完整的sha1对象名(40字节十六进制字符串),或存储库中唯一的子字符串。
    • 符号引用名称,例如“master”(指“master”分支)或“v1.5.0”(指标记)或“origin/next”(指远程跟踪分支)
    • 后缀 ^ to revision参数表示提交对象的第一个父级, ^n 表示合并提交的第n个父级。后缀 ~n to-revision参数表示在第一个父行中提交的第n个祖先。这些后缀可以组合在一起,按照符号引用的路径形成修订说明符,例如“pu~3^2~3”
    • “git-describe”的输出,即最近的标记,可选地后跟一个破折号和一些提交,后跟一个破折号、一个“g”和一个缩写的对象名,例如“v1.6.5.1-75-g5bf8097”。

    还有涉及reflog的修订说明符,这里没有提到。在Git中,每个对象(无论是commit、tag、tree还是blob)都有其sha-1标识符;有一些特殊的语法,例如“next:documentation”或“next:readme”,以在指定的修订版中引用树(目录)或blob(文件内容)。

    Mercurial还有许多命名变更集的方法(如 hg MangPLE):

    • 普通整数被视为修订号。需要记住的是,修订号是 本地到给定存储库 ;在其他存储库中,它们可以是不同的。
    • 负整数被视为与尖端的顺序偏移量,其中-1表示尖端,-2表示尖端之前的修订,依此类推。他们也是 地方的 储存库。
    • 唯一修订标识符(40位十六进制字符串)或其唯一前缀。
    • 标记名(与给定修订关联的符号名)或书签名(扩展名:与给定头关联的符号名,存储库本地)或“命名分支”(提交标签;由“命名分支”提供的修订名是具有给定提交标签的所有提交的提示(无子提交),如果存在多个修订号,则具有最大的修订号。这样小费)
    • 保留名称“tip”是一个特殊的标记,它始终标识最新的修订。
    • 保留名称“空”表示空修订。
    • 保留名称“.”表示工作目录的父目录。

    差异
    正如您可以看到的,比较上面的列表,Mercurial提供了版本号,本地到存储库,而Git没有。另一方面,Mercurial只提供了相对于“tip”(当前分支)的相对偏移量,后者是本地到存储库(至少没有 ParentrevspecExtension ,而git允许从任何提示中指定任何提交后续操作。

    最新版本在git中命名为head,在mercurial中命名为“tip”;在git中没有空版本。Mercurial和Git都可以有许多根(可以有多个无父提交;这通常是以前独立项目加入的结果)。

    另请参见: Many different kinds of revision specifiers 关于以利亚博客的文章(纽伦的)。

    个人意见: 我认为 修订号 被高估(至少对于分布式开发和/或非线性/分支历史)。首先,对于分布式版本控制系统,它们必须是存储库本地的,或者需要以特殊的方式将某些存储库视为中央编号机构。第二,历史较长的大型项目可以在5位数字范围内进行修订,因此与缩短为6-7个字符的修订标识符相比,它们只提供了轻微的优势,并且意味着严格的排序,而修订只是部分排序(我的意思是,修订n和n+1不需要是父级和子级)。

    修订范围

    在Git中,修订范围为 拓扑 . 常见 A..B 语法,对于线性历史,表示修订范围从A开始(但不包括A),到B结束(即范围为 从下面打开 )是用于 ^A B ,这对于历史遍历命令意味着所有可从B访问的提交,不包括可从A访问的提交。这意味着 A、B 范围是完全可预测的(并且非常有用),即使a不是b的祖先: A、B 表示从A和B的共同祖先(合并基)到B的修订范围。

    在Mercurial版本中,范围基于 修订号 . 使用指定范围 A:B 语法,与git范围相反,用作 闭区间 . 另外,范围B:A是以相反顺序的范围A:B,在Git中不是这样(但请参见下面的注释 A...B 语法)。但是这样的简单性是有代价的:修订范围A:B只有当A是B的祖先或者反之亦然时才有意义,也就是说,具有线性历史;否则(我猜)范围是不可预测的,结果是存储库本地的(因为修订号是存储库本地的)。

    这是用Mercurial 1.6修正的,它有新的 拓扑修订范围 ,其中“a..b”(或“a::b”)被理解为同时是x的后代和y的祖先的一组变更集。我猜,这相当于git中的“——祖先路径a..b”。

    Git也有符号 A…B 对于修订的对称差异;它意味着 A B --not $(git merge-base A B) 也就是说,所有可以从A或B中获得的承诺,但不包括所有可以从A或B中获得的承诺(可以从共同祖先中获得)。

    更名

    善变的使用 重命名跟踪 处理文件重命名。这意味着在提交时保存有关文件重命名事实的信息;在Mercurial中,此信息保存在“增强的diff”表单中,格式为 文件记录 (文件revlog)元数据。结果是你必须使用 hg rename / hg mv ……或者你需要记住跑步 hg addremove 进行基于相似性的重命名检测。

    Git在版本控制系统中是独一无二的,因为它使用 重命名检测 处理文件重命名。这意味着在需要时检测到文件被重命名的事实:进行合并时,或显示diff时(如果请求/配置)。这样做的优点是可以改进重命名检测算法,并且不会在提交时冻结。

    Git和Mercurial都需要使用 --follow 当显示单个文件的历史记录时,可选择跟随重命名。在显示文件的行历史记录时,这两者都可以使用重命名。 git blame / hg annotate .

    在Git中 怪罪 命令能够跟踪代码移动,也可以将代码从一个文件移动(或复制)到另一个文件,即使代码移动不是完整文件重命名的一部分。 据我所知,这个特性是Git独有的(撰写时,2009年10月)。

    网络协议

    Mercurial和Git都支持从同一个文件系统上的存储库中获取和推送,其中存储库URL只是到存储库的文件系统路径。两者都支持从 捆绑文件 .

    Mercurial支持通过ssh和HTTP协议获取和推送。对于ssh,需要在目标计算机上有一个可访问的shell帐户和一个已安装/可用的hg副本。对于HTTP访问 hg-serve 或者需要运行mercurial cgi脚本,并且需要在服务器计算机上安装mercurial。

    Git支持两种用于访问远程存储库的协议:

    • “智能”协议 ,包括通过ssh和自定义git://protocol(by)访问 git-daemon )要求在服务器上安装Git。这些协议中的交换包括客户机和服务器协商它们有哪些共同的对象,然后生成和发送一个包文件。现代Git包括对“智能”HTTP协议的支持。
    • “哑”协议 其中包括http和ftp(仅用于提取)和https(用于通过WebDAV推送),不需要在服务器上安装git,但它们确实要求存储库包含由 git update-server-info (通常从钩子上跑)。交换包括客户机遍历提交链,并根据需要下载松散对象和packfile。缺点是,它的下载比严格要求的要多(例如,在只有一个packfile的情况下,即使只获取几个修订版,它也会下载整个packfile),而且它可能需要许多连接才能完成。

    扩展:脚本能力与扩展(插件)

    Mercurial在 蟒蛇 ,其中一些核心代码是用C编写的以提高性能。它提供了用于编写的API 扩展 (插件)作为添加额外功能的一种方式。有些功能,如“书签分支”或签名修订,在使用Mercurial分发的扩展中提供,需要打开它。

    Git在中实现 C , 珀尔 外壳脚本 . Git提供许多低级命令( 管道工程 )适合在脚本中使用。引入新特性的通常方法是将其编写为Perl或Shell脚本,并且当用户界面稳定时,为了性能、可移植性和避免出现角情况(此过程称为 内置 )

    Git依赖并基于[Repository]格式和[Network]协议构建。这里没有语言绑定(部分或完整) 重新实施 在其他语言中的Git(其中一些是部分重新实现的,并且部分围绕Git命令包装):JGit(Java,EGIT使用,Eclipse Git插件),Grit(Ruby),达利奇(Python),Gitγ(C1)。


    DR

        2
  •  56
  •   Greg Hewgill    15 年前

    我认为,通过播放这两个视频,您可以感受到这些系统在哪些方面相似或不同:

    吉特岛上的莱纳斯·托瓦尔兹( http://www.youtube.com/watch?v=4XpnKHJAok8 )
    Bryan O'Sullivan关于Mercurial( http://www.youtube.com/watch?v=JExtkqzEoHY )

    它们在设计上非常相似,但在实现上却非常不同。

    我用的是mercurial。据我所知,Git的一个主要区别是它跟踪文件的内容,而不是文件本身。Linus说,如果您将一个函数从一个文件移动到另一个文件,Git将告诉您整个移动过程中单个函数的历史记录。

    他们还说Git比HTTP慢,但它有自己的网络协议和服务器。

    与Mercurial相比,Git作为SVN胖客户机工作得更好。您可以拉压SVN服务器。此功能在Mercurial中仍在开发中

    Mercurial和Git都有非常好的网络托管解决方案(BitBucket和GitHub),但Google代码只支持Mercurial。顺便说一下,他们对Mercurial和Git进行了非常详细的比较,决定支持哪一个。( http://code.google.com/p/support/wiki/DVCSAnalysis )它有很多好的信息。

        3
  •  30
  •   Steve Losh    15 年前

    不久前,我写了一篇关于Mercurial分支模型的博客,其中包括了与Git分支模型的比较。也许你会发现它很有趣: http://stevelosh.com/blog/entry/2009/8/30/a-guide-to-branching-in-mercurial/

        4
  •  25
  •   james woodyatt    15 年前

    我经常使用这两种。主要的功能差异在于Git和Mercurial名称在存储库中的分支方式。使用mercurial,分支名称将被克隆并与其变更集一起提取。在Mercurial中添加对新分支的更改并将其推送到另一个存储库时,分支名称将同时被推送。因此,分支名称在Mercurial中或多或少是全局的,并且您必须使用书签扩展名,使其仅具有本地的轻量级名称(如果需要,Mercurial默认使用匿名轻量级代码行,在其术语中称为“heads”)。在Git中,分支名称及其到远程分支的内射映射存储在本地,您必须显式地管理它们,这意味着知道如何做到这一点。这正是Git比Mercurial更难学习和使用的原因。

    正如其他人在这里所指出的,有很多微小的差异。分支的区别是很大的。

        5
  •  19
  •   Jakub Narębski adamtaub    15 年前

    看一看 Git vs. Mercurial: Please Relax 帕特里克·汤姆森的博客,他写道:
    吉特是麦吉弗 , mercurial是james bond

    请注意,这篇博文是从2008年8月7日开始的,自那以后,这两个配置管理系统都有了很大的改进。

        6
  •  11
  •   elder_george    15 年前

    Mercurial几乎完全用Python编写。Git的核心是用C语言(应该比Mercurial更快)编写的,工具是用sh、perl、tcl编写的,并且使用标准的gnu-utils。因此,它需要将所有这些实用程序和解释程序带到不包含它们的系统(如Windows)中。

    这两种支持都与SVN一起工作,尽管Afaik SVN支持在Windows上为Git中断(可能我只是不走运/跛脚,谁知道呢)。还有一些扩展允许Git和Mercurial之间进行互操作。

    Mercurial有很好的 Visual Studio integration . 上次我检查的时候, plugin for Git 正在工作,但速度非常慢。

    它们的基本命令集非常相似(init、clone、add、status、commit、push、pull等)。所以,基本的工作流程是相同的。另外,两者都有类似于Tortoissesvn的客户端。

    Mercurial的扩展可以用python编写(毫不奇怪!)对于git,它们可以以任何可执行形式(可执行二进制文件、shell脚本等)写入。有些扩展非常强大,比如 git bisect .

        7
  •  11
  •   Eric Darchis    15 年前

    如果您需要良好的Windows支持,您可能更喜欢Mercurial。 TortoiseHg (Windows资源管理器插件)设法为相当复杂的工具提供一个简单易用的图形界面。作为州政府,您还将拥有 Visual Studio plugin . 但是,上一次我尝试时,SVN接口在Windows上没有那么好地工作。

    如果你不介意命令行界面,我推荐Git。不是出于技术原因,而是出于战略原因。Git采用率为 许多的 较高的。看看有多少著名的开源项目从cvs/svn切换到mercurial,有多少项目切换到git。查看与Mercurial托管相比,使用Git支持可以找到多少代码/项目托管提供商。

        8
  •  11
  •   Vadim Kotov First Zero    7 年前

    在阅读了所有关于mercurial的文章之后(我仍然相信,毕竟互联网社区是这样认为的),当我开始使用git和mercurial时,我觉得git在命令行工作时更容易适应(我开始使用mercurial和tortoisehg)。 主要是因为git命令是根据我来适当命名的,并且数量较少。 mercurial对执行不同任务的每个命令都有不同的命名,而git命令可以根据情况进行多用途(例如, checkout )虽然Git当时比较困难,但现在差别不大。嗯…有了一个像TortoiseHg这样的好的GUI客户机,使用Mercurial更容易,而且我不必记住稍微令人困惑的命令。我不想详细说明相同操作的每个命令是如何变化的,但这里有两个全面的列表: 1 from Mercurial's own site 2nd from wikivs .

    ╔═════════════════════════════╦════════════════════════════════════════════════════════════════════════════════════════════════╗
    ║           Git               ║                Mercurial                                                                       ║
    ╠═════════════════════════════╬════════════════════════════════════════════════════════════════════════════════════════════════╣
    ║ git pull                    ║ hg pull -u                                                                                     ║
    ║ git fetch                   ║ hg pull                                                                                        ║
    ║ git reset --hard            ║ hg up -C                                                                                       ║
    ║ git revert <commit>         ║ hg backout <cset>                                                                              ║
    ║ git add <new_file>          ║ hg add <new_file> (Only equivalent when <new_file> is not tracked.)                            ║
    ║ git add <file>              ║ Not necessary in Mercurial.                                                                    ║
    ║ git add -i                  ║ hg record                                                                                      ║
    ║ git commit -a               ║ hg commit                                                                                      ║
    ║ git commit --amend          ║ hg commit --amend                                                                              ║
    ║ git blame                   ║ hg blame or hg annotate                                                                        ║
    ║ git blame -C                ║ (closest equivalent): hg grep --all                                                            ║
    ║ git bisect                  ║ hg bisect                                                                                      ║
    ║ git rebase --interactive    ║ hg histedit <base cset> (Requires the HisteditExtension.)                                      ║
    ║ git stash                   ║ hg shelve (Requires the ShelveExtension or the AtticExtension.)                                ║
    ║ git merge                   ║ hg merge                                                                                       ║
    ║ git cherry-pick <commit>    ║ hg graft <cset>                                                                                ║
    ║ git rebase <upstream>       ║ hg rebase -d <cset> (Requires the RebaseExtension.)                                            ║
    ║ git format-patch <commits>  ║ hg email -r <csets> (Requires the PatchbombExtension.)                                         ║
    ║   and git send-mail         ║                                                                                                ║
    ║ git am <mbox>               ║ hg mimport -m <mbox> (Requires the MboxExtension and the MqExtension. Imports patches to mq.)  ║
    ║ git checkout HEAD           ║ hg update                                                                                      ║
    ║ git log -n                  ║ hg log --limit n                                                                               ║
    ║ git push                    ║ hg push                                                                                        ║
    ╚═════════════════════════════╩════════════════════════════════════════════════════════════════════════════════════════════════╝
    

    Git在内部保存每个已提交文件版本的记录,而hg只保存占地面积更小的变更集。与hg相比,git更容易改变历史,但它又是一个恨它或爱它的特性。我喜欢前者的Hg,后者的Git。

    我在hg中错过的是git的子模块特性。hg有子epos,但这不完全是git子模块。

    围绕这两者的生态系统也会影响人们的选择:Git必须更受欢迎(但这是微不足道的),Git必须 GitHub 而Mercurial BitBucket ,Mercurial有TortoiseHg,我还没有看到一个和Git一样好的版本。

    每一个都有其优点和缺点,其中任何一个你都不会输。

        9
  •  8
  •   decocijo    14 年前

    退房 Scott Chacon's post 不久以前。

    我认为Git有“更复杂”的名声,尽管根据我的经验,它并不比需要的复杂。IMO,Git模型是 方式 更容易理解(标记包含提交(以及指向零个或多个父提交的指针)包含树包含blob和其他树…完成)。

    不仅仅是我的经验,Git比Mercurial更令人困惑。我建议你再读一遍 this blog post from Scott Chacon 关于这件事。

        10
  •  5
  •   Warren Dew    11 年前

    在我现在的工作中,我使用Git一年多了,在此之前,我在以前的工作中使用Mercurial一年多了。我将从用户的角度提供一个评估。

    首先,两者都是分布式版本控制系统。分布式版本控制系统需要改变传统版本控制系统的思维方式,但一旦人们理解它们,实际上在许多方面工作得更好。因此,我认为Git和Mercurial比Subversion、Performance等都要优越得多,分布式版本控制系统和传统版本控制系统之间的差异要比Git和Mercurial之间的差异大得多。

    然而,Git和Mercurial之间也存在显著的差异,这使得它们更适合自己的用例子集。

    反复无常更容易学习。使用Mercurial几个星期后,我几乎不需要参考文档或注释;即使使用了一年,我仍然需要定期与Git一起参考注释。Git要复杂得多。

    这在一定程度上是因为汞只是简单的清洁剂。您很少需要在mercurial中手动进行分支;mercurial将在需要时自动为您创建匿名分支。Mercurial术语更直观;您不必像处理git那样担心“fetch”和“pull”之间的区别。Mercurial的车少了一点。有一些文件名区分大小写的问题,在使用Git和Mercurial跨平台推送项目时,常常会引起问题;这在Mercurial中已经修复了一段时间,而上次我检查的Git中还没有修复。你可以告诉mercurial有关文件重命名的信息;对于git,如果它不能自动检测到重命名——这在我的经验中是一个非常成功或失败的建议——那么就根本无法跟踪重命名。

    然而,Git额外复杂的另一个原因是,它中的大部分都需要支持额外的特性和功能。是的,在Git中处理分支更加复杂——但是另一方面,一旦你有了分支,用那些在Mercurial中几乎不可能实现的分支做事情就不难了。重新平衡分支是其中之一:您可以移动分支,使其基础(而不是分支时的主干状态)现在是主干的状态;当有许多人在同一代码基础上工作时,这大大简化了版本历史,因为每个对主干的推送都可以显示为连续的,而不是而不是交织在一起。类似地,将分支上的多个提交折叠为单个提交要容易得多,这同样有助于保持版本控制历史的整洁:理想情况下,对一个特性的所有工作都可以在主干中显示为单个提交,替换开发人员在开发该特性时可能进行的所有次要提交和子分支。

    最后,我认为在Mercurial和Git之间的选择应该取决于您的版本控制项目有多大,以同时处理这些项目的人数来衡量。例如,如果您有一组十几个或更多的人在一个单块Web应用程序上工作,那么Git更强大的分支管理工具将使它更适合您的项目。另一方面,如果您的团队正在开发一个异构的分布式系统,并且在任何时候只有一两个开发人员在处理任何一个组件,那么为每个组件项目使用一个mercurial存储库将使开发更加顺利地进行,同时减少存储库管理开销。

    底线:如果您有一个大型团队开发单个大型应用程序,请使用Git;如果您的单个应用程序很小,任何规模都来自于此类应用程序的数量而不是大小,请使用Mercurial。

        11
  •  4
  •   peterh    12 年前

    一个与dvcss本身完全无关的区别是:

    Git似乎很受C开发人员的欢迎。Git实际上是Linux内核的存储库,这可能是它如此受C开发人员欢迎的原因。对于那些只在Linux/Unix环境中工作的人来说,这一点尤其如此。

    Java开发人员似乎更青睐Git。可能有两个原因:一个是许多非常大的Java项目托管在MySimple上,包括JDK本身。另一个是对JavaCAMP的人的结构和干净文档的吸引,而这些人发现Git不一致的WRT命令命名和缺少文档。我不是说这是真的,我是说人们已经习惯了他们通常的栖息地的东西,然后他们倾向于从中选择DVC。

    我想,python开发人员几乎完全喜欢mercurial。事实上,除了Mercurial是基于Python之外,没有其他合理的理由。(我也使用了mercurial,我真的不明白为什么人们会对dvc的实现语言大惊小怪。我一个字也不懂python,如果不是因为它列在某个基于python的地方,我就不会知道了)。

    我认为你不能说一个DVC比另一个更适合一种语言,所以你不应该从中选择。但事实上,人们选择(部分)是基于他们作为社区的一部分最容易接触到的DVC。

    (不,我没有使用统计数据来支持我上面的声明。)这都是基于我自己的主观性)

    推荐文章