如何将修订历史从mercurial或git导出到cvs?

我将与其他人一起使用来自使用CVS的项目的代码。 我们想使用分布式的vcs来完成我们的工作,当我们完成或者偶尔每隔一段时间,我们想把我们的代码和我们所有的修订历史提交给cvs。 我们没有对项目的cvs repo的写权限,所以我们不能经常提交。 我们可以使用什么工具将我们的修订历史导出到CVS? 目前我们正在考虑使用git或者mercurial,但是如果可以使导出更容易,我们可以使用其他分布式vcs。

幸运的是,对于那些仍然被迫使用CVS的人来说,git提供了很好的工具来完成你想做的事情。 我的build议(以及我们在$ work的工作):

创build初始克隆

使用git cvsimport将CVS修订历史logging复制到git存储库中。 我使用以下调用:

 % git cvsimport -d $CVSROOT -C dir_to_create -r cvs -k \ -A /path/to/authors/file cvs_module_to_checkout 

-A选项是可选的,但它有助于使从CVS导入的修订历史logging看起来更像git(有关如何设置的更多信息,请参阅man git-cvsimport )。

根据CVS存储库的大小和历史logging,第一次导入将需要很长时间。 如果你想让事情真正发生,那么你可以在上面的命令中添加一个-v。

一旦这个过程完成,你将有一个master分支,应该反映CVS的HEAD(除了git cvsimport在默认情况下忽略了最后10分钟的提交以避免捕获一半的提交)。 然后你可以使用git log和朋友来检查版本库的整个历史logging,就像从一开始就使用git一样。

configuration调整

有一些configuration调整,将使从CVS(以及出口)的增量导入更容易。 这些没有logging在git cvsimport手册页上,所以我想他们可以改变,恕不另行通知,但FWIW:

 % git config cvsimport.module cvs_module_to_checkout % git config cvsimport.r cvs % git config cvsimport.d $CVSROOT 

所有这些选项都可以在命令行中指定,这样就可以安全地跳过这一步。

增量import

后续的git cvsimport应该比第一次调用快得多。 但是,它确实在每个目录(甚至那些在Attic只有文件的目录)上都有一个cvs rlog ,所以它仍然需要几分钟的时间。 如果你已经指定了上面的build议configuration,你只需要执行:

 % git cvsimport 

如果你没有设置你的configuration来指定默认值,你需要在命令行中指定它们:

 % git cvsimport -r cvs -d $CVSROOT cvs_module_to_checkout 

无论哪种方式,要牢记两件事:

  1. 确保你在你的git仓库的根目录下。 如果你在其他地方,它会尝试做一个新的cvsimport ,将永远cvsimport下去。
  2. 确保你在你的master分支,这样的变化可以合并(或重新)到您的本地/主题分支。

进行本地更改

在实践中,我build议在分支上进行更改,只有当您准备好将这些更改导出到CVS存储库时,才能进行合并。 你可以在你的分支上使用你喜欢的任何工作stream程(合并,重新绑定,压扁等),但是当然也可以使用标准的重新分配规则:如果其他人一直在你的分支上进行修改,不要重新分配。

导出对CVS的更改

git cvsexportcommit命令允许您将单个提交导出到CVS服务器。 你可以指定一个提交ID(或者任何描述man git-rev-parse定义的特定提交)。 然后生成差异,应用于CVS签出,然后(可选)使用实际的cvs客户端提交给CVS。 您可以导出主题分支上的每个微型提交,但通常我喜欢在最新的master上创build合并提交并将该单一合并提交导出到CVS。 当你导出一个合并提交时,你必须告诉git使用哪个提交父代来生成diff。 另外,如果你的合并是快进的(见man git-merge的“HOW MERGE WORKS”部分,以获得一个快进合并的描述),这将不起作用,所以你必须使用--no-ff执行合并时的选项。 这是一个例子:

 # on master % git merge --no-ff --log -m "Optional commit message here" topic/branch/name % git cvsexportcommit -w /path/to/cvs/checkout -u -p -c ORIG_HEAD HEAD 

您可以在git-cvsexportcommit的手册页上看到每个选项的含义。 你可以在你的git config中设置-w选项:

 % git config cvsexportcommit.cvsdir /path/to/cvs/checkout 

如果补丁由于某种原因失败了,我的经验是,(不幸的是)可能会更好地复制手动更改的文件并使用cvs客户端进行提交。 这不应该发生,但是,如果你确定master在CVS合并之前合并你的主题分支。

如果提交由于某种原因(networking/权限问题等)而失败,则可以在错误输出结束时将命令打印到terminal,并在CVS工作目录中执行。 它通常看起来像这样:

 % cvs commit -F .msg file1 file2 file3 etc 

下一次你做一个git cvsimport (等待至less10分钟),你应该看到你的导出提交补丁重新导入到本地存储库。 他们将有不同的提交ID,因为CVS提交会有不同的时间戳,可能还有一个不同的提交者名称(具体取决于您是否在上面的初始cvsimport设置了一个作者文件)。

克隆你的CVS克隆

如果您有多个人需要执行cvsimport ,那么使用一个执行cvsimport的git存储库并将所有其他存储库创build为一个克隆会更有效率。 这完美的工作,克隆的存储库可以执行cvsexportcommits就像上面所描述的。 有一个警告,但是。 由于CVS提交的方式通过不同的提交ID返回(如上所述),所以您不希望克隆的分支跟踪中央git存储库。 默认情况下,这是如何git cloneconfiguration您的存储库,但很容易修复:

 % git clone [CENTRAL_REPO_HERE] % cd [NEW_GIT_REPO_DIR_HERE] % git config --unset branch.master.remote % git config --unset branch.master.merge 

在你删除了这些configuration之后,当你想从中央资料库中提交新的提交时,你将不得不明确地说出从哪里以及从哪里拉取:

 % git pull origin master 

总的来说,我发现这个工作stream程非常易于pipe理,而完全迁移到git时的“下一个最好的事情”是不实际的。

您不应该盲目地信任cvsimport,并检查导入的树是否与CVS回购中的内容匹配。 我已经通过使用eclipse CVS的插件共享这个新项目,并发现有不一致的地方。

用同样的提交信息(为了恢复被错误地删除的文件)在不到一分钟的时间内完成的两个提交被分组到一个大提交中,这导致树中缺less文件。

我能够通过修改'fuzz'参数来解决这个问题,不到一分钟。

例:

 % git cvsimport -d $CVSROOT -C dir_to_create -r cvs -k \ -A /path/to/authors/file cvs_module_to_checkout -z 15 

底线: 导入后检查你的树

除了Brian Phillips的回答:还有git-cvsserver ,它的function像CVS服务器,但实际上访问git仓库…但它有一些限制。