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

我使用CVS已有10多年了,现在我被告知Git更好。有人可以解释一下两者之间的区别是什么,为什么一个比另一个更好?

最佳答案

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

但是,即使您对单个开发人员使用版本控制,也可以在单个计算机(单个帐户)上使用Git和CVS之间存在一些差异:

  • 设置存储库。 Git将存储库存储在项目顶层目录的.git目录中; CVS需要设置CVSROOT,这是用于存储不同项目(模块)的版本控制信息的中央位置。这种为用户设计的结果是,将现有源导入版本控制就像在Git中“git init && git add。&& git commit”一样简单,而在CVS中就是more complicated
  • 原子操作。因为开始时CVS是围绕每个文件的RCS版本控制系统的一组脚本,所以提交(和其他操作)在CVS中不是原子的。如果对存储库的操作在中间中断,则存储库可能处于不一致状态。在Git中,所有操作都是原子的:要么整体成功,要么失败而没有任何更改。
  • 变更集。 CVS中的更改是针对每个文件的,而Git中的更改(提交)始终引用整个项目。这是非常重要的范式转换。其后果之一是,在Git中很容易还原(创建撤消的更改)或撤消整个更改。另一个结果是,在CVS中,很容易进行部分 check out ,而在Git中,这几乎是不可能的。更改是按文件分组的事实,导致了CVS中提交消息的GNU Changelog格式的发明; Git用户使用(并且有些Git工具期望)不同的约定,其中一行描述(总结)更改,其后是空白行,然后是更详细的更改描述。
  • 命名修订/版本号。还有一个问题与事实有关,即CVS中的更改是针对每个文件的:版本号(如您有时在关键字扩展中看到的,请参见下文)(如1.4)反射(reflect)了给定文件的更改时间。在Git中,整个项目的每个版本(每次提交)都有其唯一的名称(由SHA-1 id给出);通常,前7-8个字符足以标识一次提交(对于分布式版本控制系统中的版本,您不能使用简单的编号方案-需要中央编号权限)。在CVS中,具有涉及项目整体状态的版本号或符号名,可以使用标记;如果您想在项目的某些版本中使用“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脚本示例。
  • 修改将提交。因为在Git之类的分布式VCS中,发布行为与创建提交是分开的,所以可以更改(编辑,重写)历史的未发布部分,而不会给其他用户带来麻烦。特别是,如果您在提交消息中发现拼写错误(或其他错误),或者在提交中存在错误,则只需使用“git commit --amend”。这在CVS中是不可能的(至少没有重型黑客的支持)。
  • 更多工具。 Git提供的工具比CVS多得多。其中更重要的一个是“git bisect”,它可以用于查找引入了错误的提交(修订)。如果您的提交很小并且是独立的,那么应该很容易发现错误所在。


  • 如果您与至少一位其他开发人员合作,那么您还会发现Git和CVS之间存在以下差异:
  • 合并前提交 Git使用合并前提交而不是像CVS那样先合并后提交(或update-then-commit)。如果在编辑文件时准备创建新的提交(新修订),而其他人在同一分支上创建了新的提交,而现在又在存储库中,则CVS会强制您首先更新工作目录并解决冲突,然后再允许提交。 Git并非如此。您首先提交,将状态保存在版本控制中,然后合并其他开发人员更改。您还可以要求其他开发人员进行合并并解决冲突。

    如果您希望具有线性历史记录并避免合并,则始终可以通过“git rebase”(和“git pull --rebase”)使用commit-merge-recommit工作流程,这与CVS类似,因为您可以在顶部重播更改状态更新。但是你总是先犯。
  • 不需要中央存储库使用Git,不需要在单个中央位置提交更改。每个开发人员可以拥有自己的存储库(或更好的存储库:在其中进行开发的私有(private)存储库,在其发布已准备好的部分的公共(public)存储库中公开),并且他们可以从彼此的存储库中提取/获取信息。对称时尚。另一方面,大型项目通常具有社会定义/指定的中央存储库,每个人都可以从中获取(从中获取更改)。


  • 最终,当需要与大量开发人员合作时,Git提供了更多的可能性。下面是针对项目的不同兴趣阶段和职位的Git中CVS之间的区别(在使用CVS或Git的版本控制下):
  • 潜伏。如果您只对从项目中获取最新更改感兴趣(不传播您的更改),或者进行私有(private)开发(不回馈原始项目);或者您将国外项目用作自己项目的基础(更改是本地的,发布这些更改没有意义)。

    Git在这里通过自定义的有效git://协议(protocol)支持匿名未经身份验证的只读访问,或者如果您在防火墙后面阻止DEFAULT_GIT_PORT(9418),则可以使用纯HTTP。

    对于CVS,最常见的只读访问解决方案(据我所知)是CVS_AUTH_PORT(2401)上的“pserver”协议(protocol)的 guest 帐户,通常称为“匿名”,密码为空。凭据默认存储在$HOME/.cvspass文件中,因此您只需提供一次即可;尽管如此,这还是有点麻烦(您必须知道 guest 帐户的名称,或者注意CVS服务器消息)和烦恼。
  • 边缘开发人员(叶贡献者)。传播OSS更改的一种方法是通过电子邮件发送补丁。如果您(或多或少)是偶然的开发人员,发送单个更改或单个错误修正,则这是最常见的解决方案。顺便说一句。发送补丁程序可能是通过审核委员会(补丁程序审核系统)或类似方式,而不仅是通过电子邮件。

    Git在这里提供了一些工具,可以帮助发送者(客户端)和维护者(服务器)实现这种传播(发布)机制。对于想通过电子邮件发送更改的人,有一个“git rebase”(或“git pull --rebase”)工具可以在当前上游版本之上重放您自己的更改,因此您的更改位于当前版本之上(是最新的)和“git format-patch”来创建带有提交消息(和作者身份)的电子邮件,并以(扩展的)统一的diff格式(加上diffstat便于查看)的形式进行更改。维护人员可以使用“git am”将此类电子邮件直接转换为提交,以保留所有信息(包括提交消息)。

    CVS没有提供这样的工具:您可以使用“cvs diff” /“cvs rdiff”生成更改,并使用GNU补丁来应用更改,但是据我所知,没有办法自动应用提交消息。 CVS应该以客户端服务器方式使用...
  • 中尉。如果您是项目(子系统)各个部分的维护者,或者您的项目开发遵循的是Linux内核开发中使用的“信任网络”工作流程...或者只是您拥有自己的公共(public)存储库,而您所做的更改如果想要发布太大而无法通过电子邮件作为补丁程序系列发送,则可以将拉取请求发送给项目的(主要)维护者。

    这是特定于分布式版本控制系统的解决方案,因此CVS当然不支持这种协作方式。甚至还有一个名为“git request-pull”的工具,可以帮助准备要发送给维护者的电子邮件,其中包含从存储库中提取请求的请求。多亏了“git bundle”,即使没有公共(public)存储库,您也可以使用此机制,方法是通过电子邮件或sneakernet发送更改包。一些Git托管站点(例如GitHub)支持通知某人正在您的项目上工作(发布了一些作品)(前提是他/她使用了相同的Git托管站点),并且支持PM发出某种拉取请求。
  • 主要开发人员,即直接将的更改发布到主/规范库的人。此类别对于分布式版本控制系统而言范围更广,因为拥有多个开发人员具有对中央存储库的写访问权不仅是可能的工作流程(您可以拥有一个维护者,更改推送到规范存储库,一组中尉/子系统维护者,从中/ she拉扯,还有广泛的叶子开发人员,他们通过邮件将补丁发送到维护者/项目邮件列表,或发给中尉/子维护者之一。

    使用Git,您可以选择使用 SSH协议(protocol)(SSH封装的git协议(protocol))来发布更改,并使用“git shell”(以帮助确保安全性,限制对shell帐户的访问)或Gitosis(无需单独管理访问) Shell帐户),以及使用普通HTTP身份验证的 HTTPS 和WebDAV。

    借助CVS,您可以选择使用自定义未加密(纯文本) pserver 协议(protocol),还是使用远程 shell (您实际上应该使用 SSH )发布更改,对于集中版本控制系统,这意味着提交更改(创建提交)。嗯,您还可以使用SSH隧道化'pserver'协议(protocol),并且有第三方工具可以自动执行此操作...但是我不认为这像例如胃部变态。

  • 在一般的分布式版本控制系统中,例如Git,提供了更多可能的工作流选择。使用集中式版本控制系统(例如CVS),您必须区分具有提交访问存储库权限的人员和没有提交权限的人员...,并且CVS不提供任何工具来帮助接受不具有提交权限的人员(通过补丁)提交访问权限。

    Producing Open Source Software中有关版本控制的章节中的Karl Fogel指出,最好不要在允许更改公共(public)存储库的区域上提供过于严格,严格和严格的控制; (为此)依靠社会限制(例如代码审查)比依靠技术限制要好得多;分布式版本控制系统进一步减少了恕我直言...

    HTH(希望有帮助)

    08-27 21:12
    查看更多