我将与其他人协作处理一个使用CVS的项目代码。我们想要使用分布式版本控制系统来管理我们的工作,当我们结束工作或者定期进行提交时,希望将我们的代码以及所有的修改历史记录提交到CVS。由于我们没有对该项目的CVS仓库进行写操作的权限,因此我们不能够频繁提交。有什么工具可以用来将我们的修改历史记录导出到CVS呢?目前,我们正在考虑使用Git或Mercurial,但如果有其他分布式版本控制系统可以更轻松地完成导出任务,则我们也可以使用该工具。
我将与其他人协作处理一个使用CVS的项目代码。我们想要使用分布式版本控制系统来管理我们的工作,当我们结束工作或者定期进行提交时,希望将我们的代码以及所有的修改历史记录提交到CVS。由于我们没有对该项目的CVS仓库进行写操作的权限,因此我们不能够频繁提交。有什么工具可以用来将我们的修改历史记录导出到CVS呢?目前,我们正在考虑使用Git或Mercurial,但如果有其他分布式版本控制系统可以更轻松地完成导出任务,则我们也可以使用该工具。
对于那些仍被迫使用CVS的人来说,幸运的是,Git提供了非常好的工具来做你想要做的事情。我的建议(以及我们在$work中所做的):
使用git cvsimport
将CVS修订历史克隆到Git仓库中。我使用以下调用:
% git cvsimport -d $CVSROOT -C dir_to_create -r cvs -k \
-A /path/to/authors/file cvs_module_to_checkout
-A
选项是可选的,但它有助于使从CVS导入的修订历史看起来更像Git(有关此设置的更多信息,请参见man git-cvsimport
)。
根据CVS代码库的大小和历史记录,这个初始导入将需要非常长的时间。如果您希望确认是否正在进行某些操作,可以在上述命令中添加-v
参数。
完成此过程后,您将拥有一个master
分支,该分支应反映CVS的HEAD(除了git cvsimport
默认忽略最后10分钟的提交,以避免捕获半完成的提交)。然后,您可以使用git log
等工具检查整个代码库的历史记录,就好像一开始就使用Git一样。
有一些配置调整可以使未来从CVS进行增量导入(以及导出)更加容易。虽然这些内容没有在git cvsimport
手册中记录,但我认为它们可能会随时发生变化,因此提供如下建议:
% git config cvsimport.module cvs_module_to_checkout
% git config cvsimport.r cvs
% git config cvsimport.d $CVSROOT
所有这些选项都可以在命令行上指定,因此您可以安全地跳过此步骤。
后续的git cvsimport
应该比第一次调用快得多。但是,它会对每个目录(即使只有Attic
中的文件)进行cvs rlog
操作,因此仍可能需要几分钟时间。如果您已经按照上面建议的设置进行了指定,则只需要执行以下操作:
% git cvsimport
如果您还没有设置配置以指定默认值,则需要在命令行上指定它们:
% git cvsimport -r cvs -d $CVSROOT cvs_module_to_checkout
需要注意以下两点:
master
分支上,以便更改可以合并(或变基)到本地/主题分支中。实践中,我建议始终在分支上进行更改,只有当你准备将这些更改导出回 CVS 存储库时,才合并到master
。你可以在自己的分支上使用任何工作流程(合并、变基、压缩等),但是标准的变基规则适用:如果其他任何人都在你的分支上进行更改,则不要进行变基。
git cvsexportcommit
命令允许你将单个提交导出到 CVS 服务器。你可以指定单个提交 ID(或任何描述特定提交的东西,如man git-rev-parse
中定义)。然后生成一个 diff,应用于 CVS 检查,并且(可选)使用实际的cvs客户端提交到 CVS。你可以将每个主题分支上的微提交导出,但通常我喜欢在最新的master
上创建一个合并提交,并将该合并提交导出到 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的man页面上查看这些选项的含义。您也可以在git配置中设置-w
选项:
% git config cvsexportcommit.cvsdir /path/to/cvs/checkout
如果补丁因任何原因失败,我的经验是你最好手动复制更改的文件,并使用cvs客户端提交。 但是,如果您确保在合并主题分支之前将master
与CVS保持最新,则不应该出现此问题。
如果提交因任何原因失败(网络/权限问题等),您可以在错误输出末尾打印到终端的命令,并在CVS工作目录中执行它。 它通常看起来像这样:
% cvs commit -F .msg file1 file2 file3 etc
下一次执行git cvsimport
时(等待至少10分钟),你应该会看到你导出的提交补丁被重新导入到你的本地代码库中。它们将具有不同的提交ID,因为CVS提交将具有不同的时间戳和可能不同的提交者名称(根据是否在初始的cvsimport
中设置了作者文件)。如果有多个人需要执行cvsimport
,则拥有一个执行cvsimport的单个git代码库,并将所有其他代码库创建为克隆,将更有效率。这完全可以正常工作,克隆库可以像上面描述的那样执行cvsexportcommits。但是有一个注意事项,由于CVS提交以不同的提交ID返回(如上所述),您不希望克隆分支跟踪中央git代码库。默认情况下,这是git clone
配置您的库的方式,但这很容易解决:% git clone [CENTRAL_REPO_HERE]
% cd [NEW_GIT_REPO_DIR_HERE]
% git config --unset branch.master.remote
% git config --unset branch.master.merge
在删除这些配置后,您必须明确指定从哪里和从何处拉取新提交,如果想要从中央仓库拉取新提交:
% git pull origin master
总的来说,我发现这个工作流程相当容易管理,而在完全迁移到Git不可行时,它是“下一个最好的选择”。
git cvsimport
,请尝试执行apt-get install git-cvs
。 - Tino您不应该盲目信任cvsimport,而应检查导入的树是否与CVS存储库中的内容匹配。我通过使用Eclipse CVS插件共享新项目来完成此操作,并发现存在不一致性。
在不到一分钟内完成了两次提交,使用相同的提交消息(为了恢复错误删除的文件),这些提交被合并成一个大提交,导致树中缺少一个文件。
我能够通过将“fuzz”参数修改为小于一分钟来解决这个问题。
例子:
% git cvsimport -d $CVSROOT -C dir_to_create -r cvs -k \
-A /path/to/authors/file cvs_module_to_checkout -z 15
底线:在导入后检查你的树