我将与其他人一起处理使用 cvs 的项目中的代码。 我们希望使用分布式 vcs 来完成我们的工作,当我们完成时,或者每隔一段时间,我们希望将我们的代码和所有修订历史记录提交到 cvs。 我们没有对该项目的 cvs 存储库的写入权限,因此我们无法频繁提交。 我们可以使用什么工具将修订历史记录导出到 cvs? 目前我们正在考虑使用 git 或 Mercurial,但如果可以使导出更容易,我们可以使用另一个分布式 vcs。
I'm going to be working with other people on code from a project that uses cvs. We want to use a distributed vcs to make our work and when we finish or maybe every once in a while we want to commit our code and all of our revision history to cvs. We don't have write access to the project's cvs repo so we can't commit very frequently. What tool can we use to export our revision history to cvs? Currently we were thinking of using git or mercurial but we could use another distributed vcs if it could make the export easier.
发布评论
评论(3)
幸运的是,对于我们这些仍然被迫使用 CVS 的人来说,git 提供了非常好的工具来完成您想做的事情。 我的建议(以及我们在 $work 中所做的事情):
创建初始克隆
使用 git cvsimport 将 CVS 修订历史记录克隆到 git 存储库中。 我使用以下调用:
-A
选项是可选的,但它有助于使从 CVS 导入的修订历史记录看起来更像 git (请参阅man git-cvsimport
了解有关如何设置的更多信息) 。根据 CVS 存储库的大小和历史记录,第一次导入将花费很长时间。 如果您希望放心,某些事情确实正在发生,您可以在上述命令中添加 -v。
一旦这个过程完成,您将拥有一个应该反映 CVS 的 HEAD 的
master
分支(除了git cvsimport
默认情况下会忽略最后 10 分钟的提交以避免捕获一个半完成的提交)。 然后,您可以使用 git log 和朋友来检查存储库的整个历史记录,就像它从一开始就使用 git 一样。配置调整
有一些配置调整可以使将来从 CVS 的增量导入(以及导出)变得更加容易。 这些没有记录在 git cvsimport 手册页上,所以我想它们可能会更改,恕不另行通知,但是,FWIW:
所有这些选项都可以在命令行上指定,因此您可以安全地跳过此步骤。
增量导入
后续 git cvsimport 应该比第一次调用快得多。 但是,它确实会对每个目录(甚至那些在 Attic 中只有文件的目录)执行
cvs rlog
操作,因此仍然需要几分钟的时间。 如果您已指定上面的建议配置,则您需要做的就是执行:如果您尚未设置配置来指定默认值,则需要在命令行上指定它们:
无论哪种方式,有两件事需要注意:请记住:
cvsimport
,这将再次花费很长时间。master
分支上,以便可以将更改合并(或重新调整基础)到您的本地/主题分支中。进行本地更改
实际上,我建议始终在分支上进行更改,并且仅在准备好将这些更改导出回 CVS 存储库时才合并到
master
。 您可以在分支上使用您喜欢的任何工作流程(合并、变基、压缩等),但当然,标准变基规则适用:如果其他人已经将其更改基于您的分支,则不要变基。将更改导出到 CVS
git cvsexportcommit
命令允许您将单个提交导出到 CVS 服务器。 您可以指定单个提交 ID(或描述man git-rev-parse
)。 然后生成差异,应用于 CVS 签出,然后(可选)使用实际的 cvs 客户端提交到 CVS。 您可以导出主题分支上的每个微提交,但通常我喜欢在最新的master
上创建合并提交,并将该单个合并提交导出到 CVS。 当您导出合并提交时,您必须告诉 git 使用哪个提交父级来生成差异。 另外,如果您的合并是快进的,则这将不起作用(请参阅man git-merge
了解快进合并的描述),因此您必须使用--no-执行合并时的 ff
选项。 下面是一个示例:您可以在 git-cvsexportcommit 的手册页。 您可以选择在 git 配置中设置
-w
选项:如果补丁由于某种原因失败,我的经验是(不幸的是)您最好将更改的文件复制到手动并使用 cvs 客户端提交。 但是,如果您在合并主题分支之前确保
master
与 CVS 保持同步,则不会发生这种情况。如果提交由于任何原因(网络/权限问题等)而失败,您可以获取错误输出末尾打印到终端的命令,并在 CVS 工作目录中执行它。 它通常看起来像这样:
下次执行 git cvsimport 时(至少等待 10 分钟),您应该会看到导出的提交的补丁重新导入到本地存储库中。 它们将具有不同的提交 ID,因为 CVS 提交将具有不同的时间戳,并且可能具有不同的提交者名称(取决于您是否在上面的初始
cvsimport
中设置了authors 文件)。克隆您的 CVS 克隆
如果您有多个人需要执行 cvsimport,那么使用一个执行 cvsimport 的 git 存储库并将所有其他存储库创建为克隆会更有效。 这工作得很好,克隆的存储库可以执行 cvsexportcommits,如上所述。 不过,有一点需要注意。 由于 CVS 提交通过不同的提交 ID 返回的方式(如上所述),您不希望克隆的分支跟踪中央 git 存储库。 默认情况下,这就是 git clone 配置存储库的方式,但这很容易补救:
删除这些配置后,您必须明确说明要拉入的位置和内容来自中央存储库的新提交:
总的来说,我发现这个工作流程非常易于管理,并且完全迁移到 git 时的“下一个最好的事情”是不切实际的。
Fortunately for those of us who are still forced to use CVS, git provides pretty good tools to do exactly what you're wanting to do. My suggestions (and what we do here at $work):
Creating the Initial Clone
Use
git cvsimport
to clone the CVS revision history into a git repository. I use the following invocation:The
-A
option is optional but it helps to make your revision history that's imported from CVS look more git-like (seeman git-cvsimport
for more info on how this is set up).Depending on the size and history of the CVS repository, this first import will take a VERY long time. You can add a -v to the above command if you want the peace of mind that something is in fact happening.
Once this process is completed, you will have a
master
branch that should reflect CVS's HEAD (with the exception thatgit cvsimport
by default ignores the last 10 minutes worth of commits to avoid catching a commit that is half-finished). You can then usegit log
and friends to examine the entire history of the repository just as if it had been using git from the beginning.Configuration Tweaks
There are a few configuration tweaks that will make incremental imports from CVS (as well as exports) easier in the future. These are not documented on the
git cvsimport
man page so I suppose they could change without notice but, FWIW:All of these options can be specified on the command line so you could safely skip this step.
Incremental Imports
Subsequent
git cvsimport
should be much faster than the first invocation. It does, however, do ancvs rlog
on every directory (even those that have only files inAttic
) so it can still take a few minutes. If you've specified the suggested configs above, all you need to do is execute:If you haven't set up your configs to specify the defaults, you'll need to specify them on the command line:
Either way, two things to keep in mind:
cvsimport
that will again take forever.master
branch so that the changes can be merged (or rebased) into your local/topic branches.Making Local Changes
In practice, I recommend always making changes on branches and only merging to
master
when you're ready to export those changes back to the CVS repository. You can use whatever workflow you like on your branches (merging, rebasing, squashing, etc) but of course the standard rebasing rules apply: don't rebase if anyone else has been basing their changes on your branch.Exporting Changes to CVS
The
git cvsexportcommit
command allows you to export a single commit out to the CVS server. You can specify a single commit ID (or anything that describes a specific commit as defined inman git-rev-parse
). A diff is then generated, applied to a CVS checkout and then (optionally) committed to CVS using the actualcvs
client. You could export each micro commit on your topic branches but generally I like to create a merge commit on an up-to-datemaster
and export that single merge commit to CVS. When you export a merge commit, you have to tell git which commit parent to use to generate the diff. Also, this won't work if your merge was a fast-forward (see the "HOW MERGE WORKS" section ofman git-merge
for a description of a fast-forward merge) so you have to use the--no-ff
option when performing the merge. Here's an example:You can see what each of those options mean on the man page for git-cvsexportcommit. You do have the option of setting the
-w
option in your git config:If the patch fails for whatever reason, my experience is that you'll (unfortunately) probably be better off copying the changed files over manually and committing using the cvs client. This shouldn't happen, however, if you make sure
master
is up-to-date with CVS before merging your topic branch in.If the commit fails for whatever reason (network/permissions issues, etc), you can take the command printed to your terminal at the end of the error output and execute it in your CVS working directory. It usually looks something like this:
The next time you do a
git cvsimport
(waiting at least 10 minutes) you should see the patch of your exported commit re-imported into your local repository. They will have different commit IDs since the CVS commit will have a different timestamp and possibly a different committer name (depending on whether you set up an authors file in your initialcvsimport
above).Cloning your CVS clone
If you have more than one person needing to do the
cvsimport
, it would be more efficient to have a single git repository that performs the cvsimport and have all the other repositories created as a clone. This works perfectly and the cloned repository can perform cvsexportcommits just as described above. There is one caveat, however. Due to the way CVS commits come back through with different commit IDs (as described above), you don't want your cloned branch to track the central git repository. By default, this is howgit clone
configures your repository but this is easily remedied:After you've removed these configs, you will have to explicitly say where and what to pull from when you want to pull in new commits from the central repository:
Overall, I've found this work-flow to be quite manageable and the "next best thing" when migrating completely to git isn't practical.
您不应该盲目信任cvsimport并检查导入的树是否与 CVS 存储库中的树匹配。 我通过使用 eclipse CVS 插件共享新项目来完成此操作,发现存在不一致。
两次提交在不到一分钟的时间内完成,并且具有相同的提交消息(为了恢复错误删除的文件)被分组为一个大提交,这导致树中缺少文件。
我能够通过将“fuzz”参数修改为不到一分钟来解决这个问题。
示例:
底线:导入后检查您的树
You should not trust cvsimport blindly and check if the imported tree matches what is in the CVS repo. I've done this by sharing the new project using eclipse CVS' plug-in and found that there were inconsistencies..
Two commits that were done in less than a minute with the same commit message (in order to revert a wrongfully deleted file) were grouped into one big commit, which resulted in a missing file from the tree..
I was able to solve this problem by modifying the 'fuzz' parameter to less than a minute.
example:
bottom line: check your tree after importing
除了 Brian Phillips 的回答:还有 git-cvsserver 的 CVS 服务器模拟器,其功能类似于 CVS 服务器,但实际上访问 git 存储库...但它有一些限制。
In addition to Brian Phillips answer: there is also git-cvsserver which functions like CVS server but actually access git repository... but it has some limitations.