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中它几乎是不可能的.将更改按文件组合在一起的事实导致在CVS中为提交消息发明GNU Changelog格式; Git用户使用(和一些Git工具期望的)不同的约定,单行描述(汇总)更改,然后是空行,然后是更详细的更改说明.
命名修订版/版本号.还有一个问题与CVS更改是每个文件的事实有关:版本号(有时在关键字扩展中可以看到,见下文),如1.4反映了给定文件的更改时间.在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脚本示例.
修改提交.因为在分布式VCS中,例如Git的发布行为与创建提交是分开的,所以可以改变(编辑,重写)未发布的历史部分而不会给其他用户带来不便.特别是如果你发现提交消息中的拼写错误(或其他错误),或提交中的错误,你可以简单地使用"git commit --amend".这在CVS中是不可能的(至少不是没有沉重的hackery).
更多工具.Git提供的工具比CVS多得多.其中一个更重要的是" git bisect ",可用于查找引入错误的提交(修订); 如果您的提交很小并且自包含,那么应该很容易发现错误的位置.
如果您与至少一个其他开发人员合作,您会发现Git和CVS之间存在以下差异:
在合并之前提交 Git使用commit-before-merge而不是像CVS一样使用merge-before-commit(或update-then-commit).如果在编辑文件时,准备创建新的提交(新版本),则其他人在同一分支上创建了新的提交,并且它现在位于存储库中,CVS会强制您首先更新工作目录并在允许提交之前解决冲突.Git不是这种情况.首先提交,在版本控制中保存状态,然后合并其他开发人员更改.您还可以要求其他开发人员进行合并并解决冲突.
如果您希望拥有线性历史记录并避免合并,则可以始终通过"git rebase"(和"git pull --rebase")使用commit-merge-recommit工作流程,这类似于CVS,因为您在顶部重放更改更新状态.但你总是首先承诺.
不需要中央存储库使用Git,您无需在提交更改的地方设置单个中心位置.每个开发人员都可以拥有自己的存储库(或者更好的存储库:他/她进行开发的私有存储库,以及公开他/她发布已准备好的部分的存储库),并且可以从彼此的存储库中提取/获取,对称时尚.另一方面,较大的项目通常具有社交定义/指定的中央存储库,每个人都可以从中获取(从中获取更改).
最后,当需要与大量开发人员进行协作时,Git提供了更多可能性.下面是Git中CVS对于不同兴趣阶段和项目中的位置(使用CVS或Git进行版本控制)之间的差异:
潜伏者.如果您只对从项目中获取最新更改(不传播您的更改)或进行私有开发(无需回馈原始项目)感兴趣; 或者您使用外国项目作为您自己项目的基础(更改是本地的,发布它们没有意义).
Git支持通过自定义高效协议进行匿名未经身份验证的只读访问git://
,或者如果您支持防火墙DEFAULT_GIT_PORT
(9418),则可以使用纯HTTP.
对于CVS,对于只读访问,最常见的解决方案(据我所知)是(2401)上的"pserver"协议的访客帐户CVS_AUTH_PORT
,通常称为"匿名"并且具有空密码.凭证默认存储在$HOME/.cvspass
文件中,因此您只需提供一次; 仍然,这是一个障碍(你必须知道访客帐户的名称,或注意CVS服务器消息)和烦恼.
边缘开发者(叶片贡献者).在OSS中传播更改的一种方法是通过电子邮件发送补丁.如果您是(或多或少)意外开发人员,发送单个更改或单个错误修复,这是最常见的解决方案.BTW.发送补丁可能是通过审查委员会(补丁审查系统)或类似手段,而不仅仅是通过电子邮件.
Git提供了这些工具,它们有助于发送者(客户端)和维护者(服务器)的传播(发布)机制.对于想要通过电子邮件发送更改的人来说,有" git rebase "(或"git pull --rebase")工具可以在当前上游版本的基础上重放您自己的更改,因此您的更改是在当前版本之上(很新鲜) )和" git format-patch "创建带有提交消息(和作者身份)的电子邮件,以(扩展)统一差异格式的形式进行更改(加上diffstat以便于查看).维护人员可以直接将此类电子邮件转换为使用" git am " 保留所有信息(包括提交消息)的提交.
CVS不提供这样的工具:你可以使用"cvs diff"/"cvs rdiff"来生成更改,并使用GNU补丁来应用更改,但据我所知,没有办法自动应用提交消息.CVS本打算用于客户端< - >服务器时尚......
中尉.如果您是项目(子系统)的独立部分的维护者,或者您的项目的开发遵循Linux内核开发中使用的"信任网络"工作流程...或者只是您拥有自己的公共存储库,并且您更改了想发布过大的通过电子邮件发送补丁系列,你可以向项目的(主)维护者发送拉请求.
这是分布式版本控制系统特有的解决方案,因此CVS当然不支持这种协作方式.甚至还有一个名为"git request-pull"的工具,它有助于准备发送给维护者的电子邮件,并请求从您的存储库中提取.感谢"git bundle",您可以使用此机制,即使没有公共存储库,也可以通过电子邮件或sneakernet发送更改包.一些像GitHub这样的Git托管网站支持通知某人正在你的项目上工作(发布一些工作)(前提是他/她使用相同的Git托管网站),并支持PM一种拉取请求.
主要开发人员,即直接发布他/她的更改的人(到主/规范存储库).这个类别对于分布式版本控制系统来说更广泛,因为让多个开发人员对中央存储库具有写入权限不仅是可能的工作流程(您可以让单个维护者将更改推送到规范存储库,一组中尉/子系统维护者,他/她拉,以及通过邮件将修补程序发送到维护者/项目邮件列表或中尉/子维护者之一的各种叶子开发人员.
使用Git,您可以选择使用SSH协议(用SSH包装的git协议)发布更改,使用"git shell"(帮助安全,限制shell帐户访问)或Gitosis等工具(无需单独的shell帐户即可管理访问) )和使用WebDAV的HTTPS,具有普通的HTTP身份验证.
使用CVS,可以选择自定义未加密(纯文本) pserver协议,或使用远程shell(您确实应该使用SSH)来发布更改,这对于集中式版本控制系统来说意味着提交更改(创建提交).好吧,你也可以使用SSH隧道'pserver'协议,并且有自动化的派对工具......但我认为这不像Gitosis那么容易.
通常,分布式版本控制系统(例如Git)提供了更广泛的可能工作流程选择.对于集中式版本控制系统,例如CVS,您必须区分具有对存储库的提交访问权限的人和没有...的人员,并且CVS不提供任何工具来帮助接受来自没有人的贡献(通过补丁)提交访问权限
Karl Fogel在关于版本控制的部分中制作开源软件时指出,最好不要对允许对公共存储库进行更改的区域提供过于严格,严格和严格的控制; 依靠(为此)社会限制(例如代码审查)而不是技术限制要好得多; 分布式版本控制系统进一步减少了IMHO ......
HTH (希望有助于)