GIT 和 CVS 的区别

143

Git和CVS版本控制系统有什么区别?

我已经愉快地使用CVS超过10年了,现在有人告诉我Git要好得多。能否请有人解释一下两者的区别,以及为什么一个比另一个更好呢?


2
这个由Git的原始作者Linus所做的演讲,几乎可以总结出来。Google Tech Talks:Linus Torvalds on Git 注意:这是一个高度主观的演讲。 - kungfoo
CVS非常老旧,我无法相信一个程序员能够使用它。 - PersianGulf
11
这个问题是8年前提出的。我目前使用GIT。 - jay
12
东西年代久远并不代表它不好。 - Justin Meiners
5个回答

367

主要的区别在于(正如其他回答中已经提到的),CVS是一个(旧的)集中式版本控制系统,而Git是分布式的。

但即使你将版本控制用于单个开发人员,在单个计算机(单个帐户)上,Git和CVS之间仍有一些差异:

  • 设置仓库。Git将仓库存储在项目顶级目录下的.git目录中;CVS需要设置CVSROOT,一个用于存储不同项目(模块)版本控制信息的中央位置。对用户的影响是,在Git中导入现有源代码到版本控制非常简单,只需执行"git init && git add . && git commit",而在CVS中则 更加复杂

  • 原子操作。因为CVS最初是围绕每个文件的RCS版本控制系统编写的一组脚本,所以提交(和其他操作)在CVS中不是原子的;如果对仓库的操作在中途被中断,则仓库可能处于不一致状态。在Git中,所有操作都是原子的:要么完全成功,要么没有任何更改失败。

  • 变更集。CVS中的更改是针对每个文件的,而在Git中,更改(提交)总是涉及整个项目。这是非常重要的范式转变之一。这导致的后果之一是,在Git中很容易恢复(创建撤消)或撤消整个更改;另一个后果是,在CVS中很容易进行部分检出,而在Git中几乎不可能。更改是按文件分组的这一事实,导致了GNU Changelog格式的发明,用于CVS提交消息;Git用户使用(并且一些Git工具期望)不同的约定,其中单行描述(总结)更改,然后是空行,然后是更详细的更改说明。

  • 命名修订/版本号。与CVS中更改针对每个文件的事实有关的另一个问题是:版本号(如您有时在关键字扩展中看到的)例如1.4反映了给定文件已更改的次数。在Git中,项目的每个版本作为整体(每个提交)都有其唯一的名称,由SHA-1 id给出;通常前7-8个字符足以标识提交(您无法在分布式版本控制系统中使用简单的编号方案来进行版本控制 - 这需要中央编号机构)。在CVS中,如果要使用像“v1.5.6-rc2”这样的名称来表示某个项目的某个版本,则必须使用标记;如果想要使用像“v1.5.6-rc2”这样的名称来表示某个项目的某个版本,则在Git中也是如此...但是在Git中使用标记要容易得多。

  • 轻松分支。我认为CVS中的分支过于复杂,难以处理。您必须标记分支以获得整个仓库分支的名称(即使在某些情况下,由于每个文件的处理,这也可能失败,如果我记得正确的话)。再加上CVS没有合并跟踪,因此您必须记住或手动标记合并和分支点,并手动为“cvs update -j”提供正确的信息来合并分支,这使得分支使用变得非常困难。在Git中创建和合并分支非常容易; Git自己记住所有所需的信息(因此将分支合并起来就像“git merge branchname”一样简单)...

    这意味着您可以使用主题分支,即在单独的功能分支中逐步开发单独的功能。

    • 重命名(和复制)跟踪。CVS不支持文件重命名,手动重命名可能会将历史记录分成两部分或导致无法正确恢复重命名前项目状态的无效历史记录。Git使用启发式重命名检测,基于内容和文件名的相似性(这种解决方案在实践中效果很好)。您还可以请求检测文件的复制。这意味着:

    • 当检查指定的提交时,您将获得有关某个文件已重命名的信息,

    • 合并正确地考虑了重命名(例如,如果文件仅在一个分支中重命名),

    • "git blame"是"cvs annotate"的更好替代品,是一种显示文件内容逐行历史记录的工具,也可以跟随代码移动跨越重命名。

    • 二进制文件。 CVS对二进制文件(例如图像)的支持非常有限,需要用户在添加时明确标记二进制文件(或稍后使用"cvs admin"或通过包装器自动根据文件名执行此操作),以避免通过换行符转换和关键字扩展来搞乱二进制文件。 Git根据内容自动检测二进制文件,方式与CNU diff和其他工具相同;您可以使用gitattributes机制覆盖此检测。此外,二进制文件由于默认为'safecrlf'(以及您必须请求换行符转换,尽管这可能根据发行版默认打开),并且(有限的)关键字扩展在Git中是一个严格的“选择加入”。

    • 关键字扩展。与CVS相比,Git提供了非常非常有限的关键字集(默认情况下)。这是因为两个事实:Git中的更改是每个仓库而不是每个文件的,而且当切换到其他分支或倒回到历史记录中的其他点时,Git避免修改未更改的文件。如果要使用Git嵌入修订号,则应使用构建系统,例如Linux内核源代码和Git源代码中GIT-VERSION-GEN脚本的示例。

    • 修改提交。因为在分布式VCS(如Git)中发布操作与创建提交操作是分开的,所以可以更改(编辑,重写)未发布的历史记录部分而不会给其他用户带来不便。特别是如果您注意到提交消息中的拼写错误(或其他错误)或提交中的错误,则可以简单地使用“git commit --amend”。这在CVS中不可能(至少没有重大的黑客攻击)。

    • 更多工具。Git提供比CVS更多的工具。其中一个更重要的工具是“git bisect”,可用于查找引入错误的提交(修订版);如果您的提交很小且自包含,则应该相当容易地发现错误所在的位置。


    如果你和至少另一个开发者合作,你会发现Git和CVS之间还有以下区别:
    - 提交前合并:Git使用提交-合并(commit-before-merge)而不是像CVS一样的合并-提交(merge-before-commit)或更新-提交(update-then-commit)。如果在编辑文件、准备创建新提交(新版本)时,其他人在同一分支上创建了新提交并且现在在仓库中,CVS会强制你先更新你的工作目录并解决冲突,然后才允许你提交。但这在Git中不是这样的。你首先提交,将你的状态保存在版本控制中,然后再合并其他开发者的更改。你也可以要求其他开发者进行合并并解决冲突。
    - 无需中央仓库:使用Git时,没有必要有单一的中央位置来提交你的更改。每个开发者都可以拥有自己的仓库(或更好的仓库:私有仓库用于开发,公共裸仓库用于发布已经准备好的部分),他们可以以对称的方式从彼此的仓库中提取/拉取。另一方面,对于较大的项目来说,通常会有社交定义/指定的中央仓库,每个人都从中获取变更。
    如果你喜欢线性历史并避免合并,你可以始终通过 "git rebase"(和 "git pull --rebase")使用提交-合并-重新提交(commit-merge-recommit)工作流程,这与CVS类似,即在更新的状态之上重播你的更改。但你总是先提交。

    最后,当需要与大量开发人员协作时,Git提供了许多更多的可能性。以下是在使用CVS或Git进行版本控制的项目的不同阶段(对于感兴趣的位置)之间的差异:

    • 旁观者。如果您只对从项目中获取最新更改(不传播您的更改)或进行私有开发(而不向原始项目做出贡献)感兴趣;或者您将外部项目用作自己项目的基础(更改是本地的,没有必要发布它们)。

    Git支持使用定制高效的git://协议进行此处的匿名未经身份验证只读访问,或者如果您在阻止DEFAULT_GIT_PORT(9418)的防火墙后面,则可以使用纯HTTP。

    对于CVS,我理解的最常见的只读访问解决方案是通过CVS_AUTH_PORT(2401)上的“pserver”协议的来宾帐户,通常称为“匿名”,并带有空密码。凭据默认存储在$HOME/.cvspass文件中,因此您只需提供一次即可;尽管如此,这仍然是一个障碍(您必须知道来宾帐户的名称或注意CVS服务器消息)和恼人的事情。

    • 边缘开发者(叶子贡献者)。在开源软件中传播您的更改的一种方法是通过电子邮件发送补丁。如果您是(或多或少是)偶然的开发人员,只需发送单个更改或单个错误修复,这是最常见的解决方案。顺便说一句,发送补丁可以通过审查委员会(补丁审查系统)或类似手段,而不仅仅是通过电子邮件。

    Git在此提供了工具,可帮助发送方(客户端)和维护者(服务器)在此传播(发布)机制中使用。对于想要通过电子邮件发送其更改的人们,有 "git rebase"(或 "git pull --rebase")工具,可以在当前上游版本之上重放自己的更改,以便您的更改位于当前版本之上(即为最新),并且 "git format-patch" 可以创建带有提交消息(和作者)的电子邮件,以扩展统一差异格式的形式进行更改(加上更改统计信息以便于审核)。维护者可以使用 "git am" 将此类电子邮件直接转换为提交,同时保留所有信息(包括提交消息)。

    CVS没有提供这样的工具:您可以使用"cvs diff" / "cvs rdiff"生成更改,并使用GNU patch应用更改,但据我所知,没有办法自动应用提交消息。 CVS旨在以客户端<->服务器方式使用...
    中尉。如果您是项目的单独部分(子系统)的维护者,或者如果您的项目开发遵循Linux内核开发中使用的“信任网络”工作流程...或者如果您拥有自己的公共存储库,并且要发布的更改太大而无法通过电子邮件作为补丁系列发送,则可以向项目的(主)维护者发送pull请求。
    这是特定于分布式版本控制系统的解决方案,因此当然不支持CVS这种协作方式。甚至有一个名为“git request-pull”的工具,它可帮助准备发送给维护者的电子邮件,请求从您的存储库中拉取。由于“git bundle”,即使没有公共存储库,也可以使用此机制,方法是通过电子邮件或sneakernet发送更改捆绑包。一些Git托管站点(如GitHub)支持通知有人正在处理您的项目(提供他/她使用相同的Git托管站点),并针对PM-ing一种pull请求。
    • 主开发者,即直接将自己的更改(提交到主/规范存储库)的人。在分布式版本控制系统中,这个类别更广泛,因为让多个开发人员具有对中央存储库的写访问权限不仅是可能的工作流程(您可以有单个维护者将更改推送到规范存储库,一组从中获取的副官/子系统维护者,以及广泛的叶开发人员,他们通过邮件发送补丁,或将补丁发送到维护者/项目邮件列表之一,或发送给其中一个副官/子维护者)。

    使用Git,您可以选择使用SSH协议(用SSH包装的git协议)来发布更改,使用如“git shell”等工具(以帮助安全性,限制shell账户的访问),或使用Gitosis(管理访问而无需单独的shell账户),以及使用WebDAV的HTTPS,使用普通HTTP身份验证。

    使用CVS,可以选择使用自定义的未加密(明文)pserver协议,或使用远程shell(在这里您真的应该使用SSH)来发布更改,在集中式版本控制系统中,这意味着提交您的更改(创建提交)。好吧,您还可以使用SSH隧道传输“pserver”协议,并且有第三方工具自动化此过程...但我认为这不像Gitosis那样简单。

    在一般的分布式版本控制系统(如Git)中,提供了更广泛的可能性工作流。对于集中式版本控制系统(如CVS),必须区分具有提交存储库访问权限和没有访问权限的人...而CVS不提供任何工具来帮助接受那些没有提交访问权限的人的贡献(通过补丁)。
    卡尔·福格尔在开源软件生产的版本控制部分指出,在允许更改公共存储库的区域上不要提供过于严格、刻板和严谨的控制,更好地依赖社会限制(例如代码审查)而不是技术限制;分布式版本控制系统甚至进一步减少了这种情况...

4
Jakub被列为GIT的五位主要作者之一,因此回答非常详尽。如果世界法律简单,那么只有四个人能够回答得更好 ;) - samuil
1
@samuil:我不是Git的作者之一。提交次数并不是唯一的衡量标准。我主要活跃在gitweb(Git网络界面)领域。 - Jakub Narębski
1
我本来想要一个CVS和GIT的比较表,但这个答案更好。点赞! :) 还有一篇有用的文章,我希望能用作参考(http://thinkvitamin.com/code/why-you-should-switch-from-subversion-to-git/),虽然它并不像这个答案那么好。 :) - Android Eve

5
Git官网可能是最好的解释。
我最喜欢的功能是可以在离线状态下提交。而且,除了推送和拉取之外的所有操作都非常快。 (这些操作设计为非破坏性,因此如果您的中央仓库滞后,可以在去拿咖啡时进行推送/拉取。)另一个好处是自带许多实用工具:内置的gitk是足够好的历史记录查看器;git gui是足够好的提交工具;通过输出着色,git add -igit add -pgit rebase -i 是足够好的交互式界面;git daemongit instaweb对于临时协作足够好,如果您不想/无法操作中央仓库。

4

Git是一种分布式版本控制系统(DVCS),相较于CVS是一种集中式版本控制系统。简单来说就是:当你没有连接到任何可能的代码库时,你仍然可以享受所有版本控制的好处,并且操作速度更快。


3
"幸福地使用 CVS 已经超过 x 年了",这是一个有趣的想法 :-) 它比保留大量文件副本的方式高级得多,但是...
我猜你已经习惯了它所有的怪癖,或者不经常分支和合并。还有更糟糕的可能性:
你所在的组织中的人们已经习惯了 CVS 的限制,并且你的工作方式已经相应地进行了调整;例如,从未让多个开发者同时在同一包中工作,仅在紧急情况下使用分支等。
基本原则是:越困难的事情,人们做得越少。

3

我也是一个使用cvs超过10年的用户,虽然我也喜欢git,并且随着时间的推移,我会更喜欢它,但我目前大部分工作项目都使用cvs或svn,我们似乎无法说服我工作的地方打开一个git防火墙。

有几件事情让cvs比它本来可能更好用,其中之一是cvsps,另一个是Andrew Morton的补丁脚本或quilt。 Cvsps允许您将提交的多个文件重新组合成单个补丁(从而从CVS中提取“更改集”),而quilt或Andrew Morton的补丁脚本则使您可以轻松舒适地将明智的“更改集”提交到cvs中,使您能够同时处理多个事物,同时在提交之前将它们分开。 CVS有其怪癖,但我已经习惯了大部分问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接