GIT 与 CVS 的区别

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

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

101365 次浏览

Git 网站 可能最好地解释了这一点。

我最喜欢的功能是离线时可以进行提交。还有速度,除了推拉之外,所有事情都发生的极速。(而且这些操作都是无损设计的,所以当你去买咖啡的时候,如果你的中央回购延迟了,你可以推拉。)另一个好处是它包括电池: 内置的 gitk是一个足够好的历史查看器; git gui是一个足够好的提交工具; 输出彩色化,git add -igit add -pgit rebase -i是足够好的交互式界面; git daemongit instaweb是足够好的临时协作,如果你不想/不能摆弄你的中央回购。

Git 是 DVCS,而 CVS 是集中式的。简单的描述将是: 当您没有连接到多个可能的存储库的 任何时,您将获得版本控制的所有好处,而且操作更快。

主要的区别在于(正如在其他响应中已经说过的) CVS 是(旧的)集中式版本控制系统,而 Git 是分布式的。

但是,即使您对单个开发人员使用版本控制,在单个机器(单个帐户)上,Git 和 CVS 之间也有一些区别:

  • 设置存储库 。Git 将存储库存储在项目顶部目录的 .git目录中; CVS 需要设置 CVSROOT,这是存储不同项目(模块)的版本控制信息的中心位置。对于用户来说,这种设计的结果是将现有的源代码导入到版本控制中就像“ git init & & git add”一样简单。在 Git 中是“ & & Git commit”,而在 CVS 中是 更复杂

  • 原子操作 。因为 CVS 最初是围绕每个文件的 RCS 版本控制系统的一组脚本,所以在 CVS 中提交(和其他操作)不是原子操作; 如果存储库上的操作在中间被中断,存储库可能会处于不一致的状态。在 Git 中,所有操作都是原子操作: 要么作为整体成功,要么在没有任何更改的情况下失败。

  • 更改集 。CVS 中的更改是针对每个文件的,而 Git 中的更改(提交)总是指整个项目。这是非常重要的 范式转换。这样做的后果之一是,在 Git 中很容易恢复(创建一个撤销的更改)或撤销 完整更改; 另一个后果是,在 CVS 中很容易执行部分签出,而在 Git 中几乎不可能。事实上,每个文件的变化,分组在一起导致发明 GNU 更新格式提交消息在 CVS; Git 用户使用(和一些 Git 工具期望)不同的约定,单行描述(总结)变化,其次是空行,其次是更详细的描述变化。

  • 命名修订/版本号 。还有一个问题与 CVS 中每个文件的更改有关: 版本号(正如您在 关键字扩展中有时可以看到的,参见下文) ,如1.4反映了给定文件的更改次数。在 Git 中,项目的每个版本(每个提交)都有自己独特的名称,通常前7-8个字符就足以识别一个提交(在编号中不能使用简单的分散式版本控制——这需要中央编号权限)。在 CVS 中使用版本号或符号名称来表示整个项目的状态,你可以使用 标签; 如果你想在某个版本的项目中使用类似于‘ v1.5.6-rc2’的名称,在 Git 中也是如此... ... 但是在 Git 中使用标记要容易得多。

  • 容易分支 。我认为 CVS 的分支过于复杂,难以处理。您必须对分支进行标记,以便为整个存储库分支命名(如果我没记错的话,甚至在某些情况下,由于每个文件的处理,分支也可能失败)。再加上 CVS 没有 合并追踪,所以你必须要么记住,要么手动标记合并和分支点,手动为“ CVS update-j”提供正确的信息来合并分支,这使得分支变得不必要的难以使用。在 Git 中,创建和合并分支非常容易; Git 自己记住所有需要的信息(所以合并一个分支就像“ Git merge 分支名称”一样容易) ... ... 它必须这样做,因为分布式开发自然会导致多个分支。

    这意味着您可以使用 主题分支,即在单独的特性分支中的多个步骤中开发单独的特性。

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

    • 当检查指定的提交时,您将获得某个文件被重命名的信息,
    • 正确地合并将重命名考虑在内(例如,如果文件只在一个分支中重命名)
    • 与“ cvs 注释”(一种按行显示文件内容历史记录的工具)等价的(更好的)“ git Blame”也可以跨重命名跟踪代码移动
  • 二进制文件 。CVS 对二进制文件(例如图像)的支持非常有限,要求用户在添加时显式地标记二进制文件(或稍后使用“ CVS admin”,或通过包装器根据文件名自动标记) ,以避免通过行尾转换和关键字扩展损坏二进制文件。Git 根据内容自动检测二进制文件,方法与 CNU diff 和其他工具相同; 您可以使用 gitAttribute 机制覆盖这种检测。此外,由于默认设置为“ safecrlf”,二进制文件对于不可恢复的错误处理是安全的(事实上,你必须请求行结束转换,尽管这可能会在默认情况下根据分布打开) ,而且(有限的)关键字扩展在 Git 中是一个严格的‘ opt-in’。

  • 关键字扩展 。与 CVS 相比,Git 提供了一组非常非常有限的关键字(默认情况下)。这是因为两个事实: Git 中的更改是每个存储库而不是每个文件,Git 避免修改在切换到其他分支或回退到历史上的其他点时没有更改的文件。如果你想使用 Git 嵌入修订号,你应该使用你的构建系统,例如下面的例子 GIT-VERION-GEN 脚本在 Linux 内核源代码和 Git 源代码。

  • 修改提交 。因为在分布式 VCS 中,例如 出版的 Git 操作与创建提交是分开的,所以可以在不影响其他用户的情况下更改(编辑、重写)未发布的部分历史记录。特别是如果您注意到提交消息中的输入错误(或其他错误) ,或者提交中的 bug,那么您可以简单地使用“ git commit —— Amendment”。这是不可能的(至少没有重黑客)在 CVS。

  • 更多工具 。Git 比 CVS 提供了更多的工具。其中一个更重要的是“ Git Bisect”,它可以用来查找引入 bug 的提交(修订) ; 如果您的提交很小并且是自包含的,那么应该很容易发现 bug 在哪里。


如果您与至少一个其他开发人员合作,您还会发现 Git 和 CVS 之间的以下差异:

  • 在合并之前提交 Git 使用 合并前提交,而不是像 CVS、 先合并后提交(或 更新然后提交)那样。如果你在编辑文件,准备创建新提交(新版本)的时候,其他人在同一个分支上创建了新提交,现在它已经在存储库中了,CVS 会强制你首先更新你的工作目录,并在允许你提交之前解决冲突。Git 的情况并非如此。首先提交,将状态保存在版本控制中,然后合并其他开发人员的更改。您还可以要求其他开发人员进行合并并解决冲突。

    如果您喜欢使用线性历史记录并避免合并,那么您总是可以通过“ git rebase”(和“ git pull —— rebase”)使用 提交-合并-重新提交工作流,这与 CVS 类似,因为您可以在更新状态之上重播您的更改。但你总是先下手为强。

  • 不需要中央存储库 在 Git 中,不需要在提交更改的单个中心位置。每个开发人员都可以拥有自己的存储库(或者更好的存储库: 他/她在其中进行开发的私有存储库,以及他/她在其中发布已准备好的部分的公共存储库) ,他们可以以对称的方式从彼此的存储库中提取/获取。另一方面,对于较大的项目来说,通常有定义/指定的 社交方面中央存储库,每个人都从中提取(从中获取更改)。


最后,当需要与大量开发人员协作时,Git 提供了更多的可能性。下面是针对项目中不同阶段的兴趣和位置(在使用 CVS 或 Git 的版本控制下) ,Git 中的 CVS 之间的区别:

  • 潜伏者。如果你只对从一个项目中获得最新的变更感兴趣,(没有传播您的更改) ,或者做 二等兵开发(不对原始项目做出贡献) ; 或者你使用外国项目作为你自己项目的基础(变更是本地的,发布它们没有意义)。

    Git 在这里支持通过自定义高效的 git://协议进行 < em > 匿名未经认证 只读访问,或者如果防火墙阻塞了 DEFAULT_GIT_PORT(9418) ,则可以使用普通 HTTP。

    对于 CVS 来说,最常见的只读访问解决方案是 CVS_AUTH_PORT(2401)上的‘ pserver’协议的 客户账户,通常称为“匿名”,密码为空。凭据默认存储在 $HOME/.cvspass文件中,因此您只能提供一次; 但是,这仍然有一点障碍(您必须知道客户帐户的名称,或者注意 CVS 服务器消息)和烦恼。

  • 边缘显影剂(叶贡献者) 。在 OSS 中传播更改的一种方法是 通过电子邮件发送补丁。这是最常见的解决方案,如果您是(或多或少)偶然的开发人员,发送单个更改,或单个 bug 修复程序。顺便说一句。发送补丁可能是通过审查委员会(补丁审查系统)或类似的方式,而不仅仅是通过电子邮件。

    Git 在这里为发送方(客户机)和维护方(服务器)提供了有助于这种传播(发布)机制的工具。对于那些希望通过电子邮件发送更改的人来说,有“ Git rebase”(或“ git pull —— rebase”)工具可以在当前上游版本的基础上重播你自己的更改,所以你的更改是在当前版本的基础上的(是新鲜的) ,而“ Git 格式-补丁程序”可以创建带有提交消息(和作者)的电子邮件,以(扩展的)统一差异格式的形式进行更改(加上 diststat 以便更容易地查看)。维护人员可以使用“ 走吧”将这些电子邮件直接转换为提交保存所有信息(包括提交消息)。

    CVS 没有提供这样的工具: 您可以使用“ CVS diff”/“ CVS rdiff”来生成更改,并使用 GNU 补丁来应用更改,但据我所知,没有办法自动应用提交消息。CVS 应该以客户端 <-> 服务器的方式使用..。

  • 中尉。如果你是一个项目(子系统)的独立部分的维护者,或者如果你的项目的开发遵循 Linux 内核开发中使用的“信任网络”工作流程... 或者只是如果你有自己的公共存储库,并且你想发布的更改太大而不能通过电子邮件作为 补丁系列发送,你可以发送 撤回请求到项目的(主)维护者。

    这是 分发版本控制系统特有的解决方案,因此 CVS 当然不支持这种协作方式。甚至还有一个名为“ git request-pull”的工具,它可以帮助准备发送给维护人员的电子邮件,并请求从存储库中提取。多亏了“ git bundle”,即使没有公共存储库,您也可以使用这种机制,通过电子邮件或运动鞋网络发送更改包。一些 Git 托管站点,比如 GitHub,支持通知某人正在为你的项目工作(发布了一些作品)(前提是他/她使用相同的 Git 托管站点) ,以及 PM-ing 一种拉请求。

  • Main 开发人员 ,即 直接出版他/她的更改(到 main/canonical 存储库)的人。这一类别对于分布式版本控制系统来说更为广泛,因为拥有多个具有对中央存储库的写访问权限的开发人员不仅仅是可能的工作流程(你可以拥有一个 更改为规范存储库的维护人员,一组他/她从中抽取的副手/子系统维护人员,以及通过邮件将补丁发送给维护人员/项目邮件列表或者其中一个副手/子维护人员的广泛的叶子开发人员)。

    使用 Git,你可以选择使用 SSH 协议(包装在 SSH 中的 Git 协议)发布更改,使用“ Git shell”(帮助安全性,限制对 shell 帐户的访问)或 Gitosis(不需要单独的 shell 帐户就可以管理访问) ,使用 WebDAV 的 HTTPS,使用普通的 HTTP 认证。

    对于 CVS,可以选择定制的 未加密(纯文本) 观察者协议,或者使用 远程外壳程序(您真正应该使用 SSH的地方)来发布您的更改,对于 集中版本控制系统,这意味着提交您的更改(创建提交)。好吧,你也可以使用 SSH 隧道’pserver’协议,并且有他们的聚会工具自动化这个... 但是我不认为这是像 Gitosis 一样容易。

在一般的分布式版本控制系统中,如 Git,提供了更广泛的可能的工作流选择。对于像 CVS 这样的集中式版本控制系统,你必须区分提交存储库访问权限的用户和没有提交存储库访问权限的用户。而且 CVS 没有提供任何工具来帮助接受没有提交访问权限的用户的贡献(通过补丁)。

Karl Fogel 在 开源软件的开发中关于版本控制的章节中指出,在允许对公共存储库进行更改的领域,最好不要提供过于严格、严格和严格的控制; 在这方面,依赖社会限制(例如代码审查)比依赖技术限制要好得多; 分布式版本控制系统甚至进一步降低了这一点..。

高架桥 (希望有所帮助)

“愉快地使用 CVS 超过 X 年”,是一个有趣的想法: ——)这是一个巨大的进步,从保持大量的副本,但..。

我猜你已经习惯了它的所有怪癖,或者不做太多的分支和合并。还有一种更糟糕的可能性;

组织中的人们已经习惯了简历的局限性,你的工作实践也相应地适应了;

例如,永远不要让一个以上的开发人员同时处理一个包,只有在紧急情况下才使用分支等。

最基本的原则是,事情越难,做的人就越少。

虽然我也喜欢 git,但我也是一个10年以上的快乐用户,随着时间的推移,我会越来越喜欢它,尽管我目前工作的大多数项目都使用 cvs,或 svn,我们似乎不能得到官僚主义的工作说服,让我们穿过防火墙一个 git 洞。

使得 cvs 比其他方式更好的一些东西是 cvsps,另一个是 Andrew Morton 的补丁脚本,或者 quilt。Cvsps 允许你将一个提交的多个文件重建为一个补丁(从而从 CVS 中提取“变更集”) ,而 quilt 或 Andrew Morton 的补丁脚本允许你将合理的“变更集”轻松地提交到 CVS 中,允许你同时处理多个事情,同时在提交之前将它们分开。CVS 有它的怪癖,但大部分我都习惯了。