GIT 和 CVS 的区别
Git 和 CVS 版本控制系统有什么区别?
我已经愉快地使用 CVS 十多年了,现在我被告知 Git 更好。 有人可以解释一下两者之间的区别是什么,为什么一个比另一个更好?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
Git 和 CVS 版本控制系统有什么区别?
我已经愉快地使用 CVS 十多年了,现在我被告知 Git 更好。 有人可以解释一下两者之间的区别是什么,为什么一个比另一个更好?
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
接受
或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
发布评论
评论(5)
主要区别在于(正如在其他回复中已经说过的)CVS 是(旧的)集中式版本控制系统,而 Git 是分布式的。
但即使您在单台机器(单帐户)上为单个开发人员使用版本控制,Git 和 CVS 之间也存在一些差异:
设置存储库。 Git 将存储库存储在项目顶层目录的
.git
目录中; CVS 需要设置 CVSROOT,这是存储不同项目(模块)版本控制信息的中心位置。 对于用户来说,这种设计的结果是,将现有源导入版本控制就像 Git 中的“git init && git add . && git commit”一样简单,而它是原子操作。 因为 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 Britain”,(更好)相当于“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 rebase”(和“git pull --rebase”)使用提交-合并-重新提交工作流程,这类似于 CVS您可以在更新的状态之上重播您的更改。 但你总是先承诺。
最后,当需要与大量开发人员协作时,Git 提供了更多可能性。 下面是 Git 中的 CVS 对于项目中不同兴趣阶段和位置的差异(使用 CVS 或 Git 进行版本控制):
Git 在这里支持匿名未经身份验证通过自定义高效
git://
协议进行只读访问,或者如果您位于防火墙阻止DEFAULT_GIT_PORT 后面
(9418) 您可以使用纯 HTTP。对于 CVS 来说,只读访问的最常见解决方案(据我所知)是 来宾帐户,用于
CVS_AUTH_PORT
上的“pserver”协议 (2401) ,通常称为“匿名”且密码为空。 凭据默认存储在$HOME/.cvspass
文件中,因此您只需提供一次; 尽管如此,这还是有点障碍(您必须知道来宾帐户的名称,或者注意 CVS 服务器消息)和烦恼。Git 在这里提供了有助于发送者(客户端)和维护者(服务器)传播(发布)机制的工具。 对于想要通过电子邮件发送更改的人,可以使用“ git rebase”(或“git pull --rebase”)工具,用于在当前上游版本之上重播您自己的更改,因此您的更改位于当前版本之上(是新鲜的),并且“git 格式-patch”创建带有提交消息(和作者身份)的电子邮件,以(扩展)统一 diff 格式的形式进行更改(加上 diffstat 以便于审查)。 维护者可以使用“git am"。
CVS 不提供这样的工具:您可以使用“cvs diff”/“cvs rdiff”来生成更改,并使用 GNU 补丁来应用更改,但据我所知,没有办法自动应用提交消息。 CVS 旨在用于客户端<-> 服务器时尚...
这是特定于分布式版本控制系统的解决方案,因此CVS当然不支持这种协作方式。 甚至还有一个名为“git request-pull”的工具,它可以帮助准备电子邮件发送给维护人员,请求从存储库中拉取。 感谢“git bundle”,即使没有公共存储库,您也可以通过电子邮件或运动鞋网发送更改包来使用此机制。 一些 Git 托管站点(例如 GitHub)支持通知有人正在您的项目上工作(发布了一些作品)(前提是他/她使用相同的 Git 托管站点),并用于 PM-ing 一种拉取请求。
使用 Git,您可以选择使用SSH 协议(封装在 SSH 中的 git 协议)来发布更改,并使用“git shell”(以帮助安全,限制 shell 帐户的访问)或 Gitosis(无需单独的 shell 帐户即可管理访问),以及带有 WebDAV 的 HTTPS,以及普通的 HTTP 身份验证。
使用 CVS,可以选择自定义未加密(纯文本) pserver 协议,或使用远程 shell(您确实应该使用 SSH)来发布您的更改,这对于集中式版本控制系统意味着提交您的更改(创建提交)。 好吧,您还可以使用 SSH 隧道“pserver”协议,并且有第三方工具可以自动执行此操作...但我认为这不像 Gitosis 那样容易。
一般来说,分布式版本控制系统(例如 Git)提供了更广泛的可能工作流程选择。 使用集中式版本控制系统(例如 CVS),您必须区分具有存储库提交访问权限的人员和没有权限的人员...并且 CVS 不提供任何工具来帮助接受没有权限的人员的贡献(通过补丁)提交访问。
Karl Fogel 生产开源软件 在关于版本控制的部分中指出,最好不要对允许对公共存储库进行更改的区域提供过于严格、死板和严格的控制; 为此,依靠社会限制(例如代码审查)比依靠技术限制要好得多; 分布式版本控制系统进一步减少了恕我直言......
The main difference is that (as it was already said in other responses) CVS is (old) centralized version control system, while Git is distributed.
But even if you use version control for single developer, on single machine (single account), there are a few differences between Git and CVS:
Setting up repository. Git stores repository in
.git
directory in top directory of your project; CVS require setting up CVSROOT, a central place for storing version control info for different projects (modules). The consequence of that design for user is that importing existing sources into version control is as simple as "git init && git add . && git commit" in Git, while it is more complicated in CVS.Atomic operations. Because CVS at beginning was a set of scripts around per-file RCS version control system, commits (and other operations) are not atomic in CVS; if an operation on the repository is interrupted in the middle, the repository can be left in an inconsistent state. In Git all operations are atomic: either they succeed as whole, or they fail without any changes.
Changesets. Changes in CVS are per file, while changes (commits) in Git they always refer to the whole project. This is very important paradigm shift. One of consequences of this is that it is very easy in Git to revert (create a change that undoes) or undo whole change; other consequence is that in CVS is easy to do partial checkouts, while it is currently next to impossible in Git. The fact that changes are per-file, grouped together led to invention of GNU Changelog format for commit messages in CVS; Git users use (and some Git tools expect) different convention, with single line describing (summarizing) change, followed by empty line, followed by more detailed description of changes.
Naming revisions / version numbers. There is another issue connected with the fact that in CVS changes are per files: version numbers (as you can see sometimes in keyword expansion, see below) like 1.4 reflects how many time given file has been changed. In Git each version of a project as a whole (each commit) has its unique name given by SHA-1 id; usually first 7-8 characters are enough to identify a commit (you can't use simple numbering scheme for versions in distributed version control system -- that requires central numbering authority). In CVS to have version number or symbolic name referring to state of project as a whole you use tags; the same is true in Git if you want to use name like 'v1.5.6-rc2' for some version of a project... but tags in Git are much easier to use.
Easy branching. Branches in CVS are in my opinion overly complicated, and hard to deal with. You have to tag branches to have a name for a whole repository branch (and even that can fail in some cases, if I remember correctly, because of per-file handling). Add to that the fact that CVS doesn't have merge tracking, so you have to either remember, or manually tag merges and branching points, and manually supply correct info for "cvs update -j" to merge branches, and it makes for branching to be unnecessary hard to use. In Git creating and merging branches is very easy; Git remembers all required info by itself (so merging a branch is as easy as "git merge branchname")... it had to, because distributed development naturally leads to multiple branches.
This means that you are able to use topic branches, i.e. develop a separate feature in multiple steps in separate feature branch.
Rename (and copy) tracking. File renames are not supported in CVS, and manual renaming might break history in two, or lead to invalid history where you cannot correctly recover the state of a project before rename. Git uses heuristic rename detection, based on similarity of contents and filename (This solution works well in practice). You can also request detecting of copying of files. This means that:
when examining specified commit you would get information that some file was renamed,
merging correctly takes renames into account (for example if the file was renamed only in one branch)
"git blame", the (better) equivalent of "cvs annotate", a tool to show line-wise history of a file contents, can follow code movement also across renames
Binary files. CVS has only a very limited support for binary files (e.g. images), requiring users to mark binary files explicitly when adding (or later using "cvs admin", or via wrappers to do that automatically based on file name), to avoid mangling of binary file via end-of-line conversion and keyword expansion. Git automatically detects binary file based on contents in the same way CNU diff and other tools do it; you can override this detection using gitattributes mechanism. Moreover binary files are safe against unrecoverable mangling thanks to default on 'safecrlf' (and the fact that you have to request end-of-line conversion, although this might be turned on by default depending on distribution), and that (limited) keyword expansion is a strict 'opt-in' in Git.
Keyword expansion. Git offers a very, very limited set of keywords as compared to CVS (by default). This is because of two facts: changes in Git are per repository and not per file, and Git avoids modifying files that did not change when switching to other branch or rewinding to other point in history. If you want to embed revision number using Git, you should do this using your build system, e.g. following example of GIT-VERSION-GEN script in Linux kernel sources and in Git sources.
Amending commits. Because in distributed VCS such as Git act of publishing is separate from creating a commit, one can change (edit, rewrite) unpublished part of history without inconveniencing other users. In particular if you notice typo (or other error) in commit message, or a bug in commit, you can simply use "git commit --amend". This is not possible (at least not without heavy hackery) in CVS.
More tools. Git offers much more tools than CVS. One of more important is "git bisect" that can be used to find a commit (revision) that introduced a bug; if your commits are small and self-contained it should be fairly easy then to discover where the bug is.
If you are collaboration with at least one other developer, you would find also the following differences between Git and CVS:
If you prefer to have linear history and avoid merges, you can always use commit-merge-recommit workflow via "git rebase" (and "git pull --rebase"), which is similar to CVS in that you replay your changes on top of updated state. But you always commit first.
Finally Git offers many more possibilities when collaboration with large number of developers is needed. Below there are differences between CVS in Git for different stages of interest and position in a project (under version control using CVS or Git):
Git supports here anonymous unauthenticated read-only access via custom efficient
git://
protocol, or if you are behind firewall blockingDEFAULT_GIT_PORT
(9418) you can use plain HTTP.For CVS most common solution (as I understand it) for read-only access is guest account for 'pserver' protocol on
CVS_AUTH_PORT
(2401), usually called "anonymous" and with empty password. Credentials are stored by default in$HOME/.cvspass
file, so you have to provide it only once; still, this is a bit of barrier (you have to know name of guest account, or pay attention to CVS server messages) and annoyance.Git offers here tools which help in this propagation (publishing) mechanism both for sender (client), and for maintainer (server). For people who want send their changes via email there is "git rebase" (or "git pull --rebase") tool to replay your own changes on top of current upstream version, so your changes are on top of current version (are fresh), and "git format-patch" to create email with commit message (and authorship), change in the form of (extended) unified diff format (plus diffstat for easier review). Maintainer can turn such email directly into commit preserving all information (including commit message) using "git am".
CVS offer no such tools: you can use "cvs diff" / "cvs rdiff" to generate changes, and use GNU patch to apply changes, but as far as I know there is no way to automate applying commit message. CVS was meant to be used in client <-> server fashion...
This is solution specific to distributed version control systems, so of course CVS doesn't support such way of collaboration. There is even a tool called "git request-pull" which help to prepare email to send to maintainer with request to pull from your repository. Thanks to "git bundle" you can use this mechanism even without having public repository, by sending bundle of changes via email or sneakernet. Some of Git hosting sites like GitHub have support for notifying that somebody is working (published some work) on your project (provided that he/she uses the same Git hosting site), and for PM-ing a kind of pull request.
With Git you have choice of using SSH protocol (git protocol wrapped in SSH) to publish changes, with tools such as "git shell" (to help security, limiting access of shell accounts) or Gitosis (to manage access without requiring separate shell accounts), and HTTPS with WebDAV, with ordinary HTTP authentication.
With CVS there is a choice between custom unencrypted (plain text) pserver protocol, or using remote shell (where you really should use SSH) to publish your changes, which for centralized version control system means committing your changes (creating commits). Well, you can also tunnel 'pserver' protocol using SSH, and there are thir party tools automating this... but I don't think this is as easy as e.g. Gitosis.
In general distributed version control systems, such as Git, provide much wider selection of possible workflows. With centralized version control systems, such as CVS, by necessity you have to distinguish between people with commit access to repository, and those without... and CVS doesn't offer any tools to help with accepting contributions (via patches) from people without commit access.
Karl Fogel in Producing Open Source Software in section about version control states that it is better to not provide too strict, rigid and rigorous controls on areas where one is allowed to make changes to public repository; it is much better to rely (for this) on social restrictions (such as code review) than on technical restrictions; distributed version control systems reduce that IMHO even further...
Git 网站可能最好地解释了这一点。
我最喜欢的功能是能够在离线时进行提交。 还有速度,除了推和拉以外的所有事情都以惊人的速度发生。 (这些操作在设计上是非破坏性的,所以如果你的中央存储库滞后,你可以在去喝咖啡时推/拉。)另一个好处是它包含电池:内置的 gitk 是一个足够好的历史查看器;
git gui
是一个足够好的提交工具; 对于输出着色,git add -i
、git add -p
、git rebase -i
是足够好的交互界面; 如果您不想/无法摆弄您的中央存储库,那么 git daemon 和 git instaweb 足以进行临时协作。The Git website explains this best probably.
My pet feature is being able to do commits when offline. And the speed, the sheer blazing speed at which everything except pushing and pulling happens. (And these operations are by design nondestructive, so you can push/pull when you go grab a coffee if your central repo is lagged.) Another nice thing is that it comes batteries included: the builtin
gitk
is a good enough history viewer;git gui
is a good enough commit tool; with output colorization,git add -i
,git add -p
,git rebase -i
are good enough interactive interfaces;git daemon
andgit instaweb
are good enough for ad-hoc collaboration if you don't want to / can't fiddle with your central repo.Git 是一种DVCS,与集中式 CVS 不同。 简单的描述是:当您没有连接到多个可能的存储库中的任何一个时,您可以获得版本控制的所有好处,而且操作速度更快。
Git is a DVCS, as opposed to CVS being a centralized one. Simplistic description will be: you get all benefits of version control when you're not connected to any of multiple possible repositories, plus operations are faster.
我也是 cvs 的 10 多年最快乐的用户,尽管我也喜欢 git,并且随着时间的推移会更喜欢它,尽管我目前从事的大多数项目都使用 cvs 或 svn,而且我们似乎不能让我工作的官僚机构相信我们可以在防火墙上打一个漏洞。
使 cvs 比其他方式更好的一些因素是 cvsps,另一个是 Andrew Morton 的补丁脚本或 quilt。 Cvsps 允许您在 quilt 时将提交的多个文件重新构建为单个补丁(从而从 CVS 中提取“变更集”),或者 Andrew Morton 的补丁脚本允许您非常轻松舒适地将合理的“变更集”提交到 cvs 中,从而使您能够同时处理多项事情,同时在提交之前仍然将它们分开。 CVS 有它的怪癖,但我已经习惯了其中的大多数。
I'm also a 10+ year mostly happy user of cvs, though I also like git, and with time will come to prefer it, though most of the projects I work on currently use cvs, or svn, and we can't seem to get the bureacracy where I work convinced to let us punch a git-hole through the firewall.
A couple of things that make cvs nicer than it might otherwise be are cvsps, and another is either Andrew Morton's patch scripts, or quilt. Cvsps lets you reconstitute the multiple files of a commit into a single patch (and thus extract "changesets" from CVS) while quilt, or Andrew Morton's patch scripts allow you to commit sensible "changesets" into cvs pretty easily and comfortably, allowing you to work on mutliple things simultaneously while still keeping them separated prior to committing. CVS has its quirks, but I'm used to most of them.
“愉快地使用 CVS 超过 x 年”,是一个有趣的想法 :-) 与保留大量副本相比,这是一个巨大的进步,但是......
我猜你已经习惯了它的所有怪癖,或者不这样做很多分支和合并。 还有一种更糟糕的可能性;
您组织中的人员已经习惯了简历的限制,您的工作实践也已相应调整;
例如,永远不要让多个开发人员同时处理一个包,只在紧急情况下使用分支等。
基本原则是事情越困难,做的人就越少。
"happily using CVS for over x years", is an interesting idea :-) It's a huge step up from keeping lots of copies, but ...
I'm guessing you have got used to all it's quirks, or don't do much branching and merging. There is a worse possibility;
People in your organisation have got used to cvs limitations and your work practises have adapted accordingly;
for example never having more than one developer work on one package at a time, only using branching in emergencies etc.
The basic principle is the more difficult something is, the less people do it.