Git和CVS版本控制系统有什么区别?
我已经愉快地使用CVS超过10年了,现在有人告诉我Git要好得多。能否请有人解释一下两者的区别,以及为什么一个比另一个更好呢?
Git和CVS版本控制系统有什么区别?
我已经愉快地使用CVS超过10年了,现在有人告诉我Git要好得多。能否请有人解释一下两者的区别,以及为什么一个比另一个更好呢?
主要的区别在于(正如其他回答中已经提到的),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进行版本控制的项目的不同阶段(对于感兴趣的位置)之间的差异:
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旨在以客户端<->服务器方式使用...使用Git,您可以选择使用SSH协议(用SSH包装的git协议)来发布更改,使用如“git shell”等工具(以帮助安全性,限制shell账户的访问),或使用Gitosis(管理访问而无需单独的shell账户),以及使用WebDAV的HTTPS,使用普通HTTP身份验证。
使用CVS,可以选择使用自定义的未加密(明文)pserver协议,或使用远程shell(在这里您真的应该使用SSH)来发布更改,在集中式版本控制系统中,这意味着提交您的更改(创建提交)。好吧,您还可以使用SSH隧道传输“pserver”协议,并且有第三方工具自动化此过程...但我认为这不像Gitosis那样简单。
在一般的分布式版本控制系统(如Git)中,提供了更广泛的可能性工作流。对于集中式版本控制系统(如CVS),必须区分具有提交存储库访问权限和没有访问权限的人...而CVS不提供任何工具来帮助接受那些没有提交访问权限的人的贡献(通过补丁)。gitk
是足够好的历史记录查看器;git gui
是足够好的提交工具;通过输出着色,git add -i
、git add -p
、git rebase -i
是足够好的交互式界面;git daemon
和git instaweb
对于临时协作足够好,如果您不想/无法操作中央仓库。Git是一种分布式版本控制系统(DVCS),相较于CVS是一种集中式版本控制系统。简单来说就是:当你没有连接到任何可能的代码库时,你仍然可以享受所有版本控制的好处,并且操作速度更快。
我也是一个使用cvs超过10年的用户,虽然我也喜欢git,并且随着时间的推移,我会更喜欢它,但我目前大部分工作项目都使用cvs或svn,我们似乎无法说服我工作的地方打开一个git防火墙。
有几件事情让cvs比它本来可能更好用,其中之一是cvsps,另一个是Andrew Morton的补丁脚本或quilt。 Cvsps允许您将提交的多个文件重新组合成单个补丁(从而从CVS中提取“更改集”),而quilt或Andrew Morton的补丁脚本则使您可以轻松舒适地将明智的“更改集”提交到cvs中,使您能够同时处理多个事物,同时在提交之前将它们分开。 CVS有其怪癖,但我已经习惯了大部分问题。