7

场景如下:

我有一个大型 CVS 存储库,我想将其转换为 14 个不同的 git 存储库。该cvs2git过程的一部分很好,并导致了一个大型存储库 repo.git。

对于 14 个 git 存储库中的每一个,我都克隆了主存储库并运行以下命令:

git filter-branch -d /tmp/rep --tag-name-filter cat --prune-empty --subdirectory-filter "sub/directory" -- --all

但是,在此命令之前,我必须对一些 git 存储库执行另一个git filter-branch命令,因为我必须重写提交才能将文件从一个目录移动到另一个目录。这--tree-filter是我使用的选项。以下是执行的命令行示例:

script_tree_filter="if test -f rep/to/my/file && test -d another/rep ; then echo Moving my file ; mv rep/to/my/file another/rep; fi"
git filter-branch -d /tmp/rep --tag-name-filter cat --prune-empty --tree-filter '$script_tree_filter' -- --all

在过程结束时(14500 次提交:大约需要 1 小时!)我清理了 refs 并使用git gc

git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d
git reflog expire --expire=now --all
git gc --prune=now

最后,我获得了一个大小为 1.2Go 的存储库(显然还是太大了),通过查看提交,我可以看到很多旧的仍然存在。--subdirectory-filter它们涉及在命令之后不应再出现的文件和目录。

在提交的历史中,不需要的提交和好的提交之间存在不连续性,如下所示gitk --all

在 gitk 中看到的不连续性

我很确定这些提交仍然存在,因为它们上有一些标签。如果是这种情况,是否可以在不删除良好提交的情况下删除这些标签?

如果标签不是原因,有什么想法吗?

更多信息,refs目录的内容(在 subdirectory-filter 获取的 git 仓库中)为空:

$ ls -R refs/
refs/:
heads  original  tags

refs/heads:

refs/original:
refs

refs/original/refs:
heads  tags

refs/original/refs/heads:

refs/original/refs/tags:

refs/tags:

我发现分支和标签列在packed-refsgit 存储库的文件中:

d0c675d8f198ce08bb68f368b6ca83b5fea70a2b refs/tags/v03-rev-04
95c3f91a4e92e9bd11573ff4bb8ed4b61448d8f7 refs/tags/v03-rev-05

文件中列出了 817 个标签和 219 个分支。

4

2 回答 2

5

我设法通过改变我使用的方式来解决我的问题cvs2git:我没有转换整个 CVS 库然后使用subdirectory-filter命令,而是转换了我想要的每个子模块。就我而言,这导致启动了 18 个不同的cvs2git命令:

cvs2git --blobfile=blob --dump=dump /path/to/cvs/base
# Module 1
git filter-branch --tag-name-filter cat --prune-empty --subdirectory-filter "path/to/module1" -- --all
# Module 2
git filter-branch --tag-name-filter cat --prune-empty --subdirectory-filter "path/to/module2" -- --all

现在

# Module 1
cvs2git --blobfile=blob_module1 --dump=dump_module1 /path/to/cvs/base/path/to/module1
# Module 2
cvs2git --blobfile=blob_module2 --dump=dump_module2 /path/to/cvs/base/path/to/module2

每个存储库现在都有一个完美的历史。

为什么以前的方法不起作用?我的猜测是这cvs2git与所有子模块混淆(其中一些在其历史期间更改了目录名称)。

@Michael @CharlesB 感谢您抽出宝贵时间回答并帮助我。

于 2013-07-31T14:38:14.513 回答
2

我打赌你会被这个打击:

  • CVS 和 git 分支/标签模型之间的区别:CVS 允许从多个源分支的源修订的任意组合创建分支或标签。它甚至允许将从未同时发生的文件修订添加到单个分支/标签中。另一方面,Git 只允许完整的源代码树,因为它存在于历史的某个时刻,被分支或标记为一个单元。此外,一个 git 版本的祖先会影响该版本的内容。这种差异意味着从根本上不可能 100% 忠实地表示 git 存储库中的任意 CVS 历史记录。cvs2git 使用以下解决方法:

    • cvs2git 尝试从单个源创建一个分支,但如果它不知道如何创建分支,它会使用来自多个源分支的“合并”来创建分支。在病态情况下,分支的合并源数量可以任意大。由此产生的历史表明,每当将任何文件添加到分支时,整个源分支都会合并到目标分支中,这显然是不正确的。(另一种方法是省略合并,将丢弃某些内容从一个分支移动到另一个分支的信息。)

    • 如果 cvs2git 无法确定可以从单个修订版创建 CVS 标记,则它会创建一个名为 TAG.FIXUP 的标记修复分支,然后标记该分支。(这是一个必要的解决方法,因为 git 只允许标记现有的修订。) TAG.FIXUP 分支是作为包含在标记中包含的文件修订的所有分支之间的合并创建的,这涉及到所描述的相同权衡上面的分支。TAG.FIXUP 分支在转换结束时被清除,但(由于 git 快速导入文件格式的技术限制)没有被删除。在某些情况下,可以从单个修订版创建标签,但 cvs2git 没有意识到它并创建了多余的标签修复分支。通过运行 contrib/git-move-refs 可以在转换后删除多余的标签修复分支。

  • 没有检查 CVS 分支和标签名称是合法的 git 名称。可能还有其他 git 约束也应该检查。见 cvs2git

您是在转换后显示新目录或大型 repo 的 refs 目录吗?您可以在过滤和拆分大型存储库之前删除单个大型导出存储库中的标签。

您可以通过删除目录中的文件来删除大型 repo 中的标签 - 它只是对 SHA 的引用。

于 2013-07-28T20:51:16.670 回答