将Subversion代码库的部分内容转换为Git

4

我有一个旧的Subversion存储库,里面有许多我的私人项目。其中一部分是几年前从旧的CVS存储库转换而来的(使用cvs2svn或类似工具)。它当前的结构如下:

  • 主干
    • latex
    • java
      • awt-doku
      • pps
        • build.xml
        • src
          • ant
          • de
            • dclj
            • faq
            • paul
              • (约20个其他软件包)
              • ltxdoclet
                • (一些Java文件)
    • lua
    • (其他目录)
  • 分支
  • 标签
  • 导入
问题在于,我对这个存储库进行了相当多的重新组织 - 例如,pps目录的所有内容曾经都在import的子目录中(我认为我从CVS中将其导入到那里),可能还有其他移动。

我现在对目录的内容以及路径中的其他文件,如build.xml、目录等感兴趣。我想要它们的完整历史记录,包括移动文件之前的历史记录,并且我现在想把它作为一个git仓库(因为我想在github上发布这个项目)。标签和分支从来没有被真正使用过,所以它们不重要。
我不想要这个仓库的其余部分(它们有时会成为单独的git仓库)- 这会使我的仓库变得太大(而且有些东西我不想公开)。
理想情况下,我的最终git仓库(在HEAD状态下)应该是这样的: pps - build.xml - src -- ant -- de --- dclj ---- paul ----- ltxdoclet ------ (一些java文件)
我并不关心历史目录配置,但是历史记录不应包含未触及这些目录(或它们的前身)中任何文件的提交。
当然,git svn 似乎是最佳选择的工具。(还有其他吗?) git svn clone 似乎是正确的命令...但是需要哪些选项呢?我创建了一个 authors.txt 文件来将 CVS 或 SVN 用户名转换为我的姓名和地址。为了只获取感兴趣的文件和目录,我使用了 --ignore-paths
这是我的尝试:
filter='^/xcb-src/|_00|src/resources|dclj/faq|dclj/paul/([^l]|l[^t])'
git svn clone svn+ssh://mathe-svn/ --trunk trunk/java/pps -A authors.txt --ignore-paths=$filter latexdoclet

当然,它只显示提交2306之后的历史记录,当时我将import/java-pps移动到了trunk/java/pps...而且它有很多提交根本没有任何更改。
为解决第一个问题,我考虑同时给出旧目录作为--trunk参数:
git svn clone svn+ssh://mathe-svn/ --trunk trunk/java/pps --trunk import/java-pps -A authors.txt --ignore-paths=$filter latexdoclet

这并不起作用,第一个--trunk在这里被忽略了,并且它在提交2305之前有效(在移动之前)。 (它还包含许多空提交。)
我目前的尝试是导入整个存储库,过滤掉任何不需要的内容:
filter='/xcb-src/|_00|src/resources|dclj/faq|dclj/paul/([^l]|l[^t])|/esperanto|finanzen|diverses|homepage|konfig|lua|prog-aufgaben|CVSROOT|latex|tags/'
git svn clone svn+ssh://mathe-svn/ -A authors.txt --ignore-paths=$filter latexdoclet-neu

转换仍在进行中,但肯定有很多提交我根本不想要。
编辑:转换已完成 - 我现在有2658个提交(git中的3176个对象),只有大约36个提交具有一些有趣的树更改,如果我正确配置了我的gitk过滤器。(+还有3个被错误地过滤掉,因为我们的latex源文件首先在“latex”目录中。)
  • 有没有更好的方法来做这件事情?
  • 我是不是应该先导入整个代码库,然后使用git filter-branch挑选出我想要的文件和提交记录?
2个回答

4

以下是我参考的操作步骤。


在Dustin给出的答案之后,我首先使用以下命令将整个svn存储库转换为git:

 git svn clone -A authors.txt svn+ssh://mathe-svn/ all-projects

这使我得到了一个非常庞大的 Git 仓库,包含24241个对象和24MB(压缩后),而原来的Git仓库大小为45MB。正如评论中已经说过的,两者都有2658次提交记录,但线性历史不会丢失。

然后我开始筛选...在 git filter-branch 提供的过滤器中,--index-filter 显得最有用,因为它不需要检出任何内容(与 --tree-filter 相比),而且我只想删除不需要的文件,不需要重写元数据。

此外,--prune-empty 也很有用。我还使用了 -d /dev/shm/ebermann/git-work/tmp 将工作目录放在 tmpfs 中,但我不知道这是否真的有影响,因为我没有在这里进行核对。我使用了 --original 选项来保留原始的 master 引用名称。 (为什么 filter-branch 不允许简单地创建一个新分支并保持旧分支不变呢?)

我的树过滤器是 git rm --cached -r --ignore-unmatch,我通过 xargs 提供了一组文件和目录列表。

因此,我进行了多次调用

git filter-branch           \
  -d /dev/shm/ebermann/git-work/tmp  \
   --index-filter "
xargs -a ~/projektoj/git-conversion/remove-liste-5.txt git rm --cached -r --ignore-unmatch 
"        \
   --original "step8"       \
   master

and

git filter-branch \
  -d  /dev/shm/ebermann/git-work/tmp  \
  --prune-empty \
  --original "step9" \
  master

在此期间,我使用 gitk 查看创建的分支,寻找我之前忘记的文件。

首先,我从 svn ls svn+ssh://mathe-svn/path 的输出中创建了一个文件列表,删除了我想保留的文件/目录。后来,我不得不对旧版本重复这个过程,因为有些文件在之前被重命名(更确切地说,整个目录树被移动),所以旧名称没有显示出来。此外,有些文件在当前版本之前就已经被删除了。

现在我的 master 分支只剩下 40 个版本,我的 HEAD 包含 39 个文件和目录。

这个仓库(只克隆了这个分支到一个新仓库)现在只有 180 KB 大小(带有 288 KB 的工作树)。我现在会清理提交注释(它们经常与这个项目无关),然后将其发布在 github 上。


下一次,是否有一些命令可以创建一个列表,其中包含存储在我的仓库中的所有文件路径(无需检查所有修订版并针对每个版本调用 find 或类似命令)?(Git 或 SVN 都可以。)


3

是的,在转换后学习filter-branch并进行所有编辑。您可以逐步执行并在每个步骤中进行反向操作,以防出错。


好的,明天再做吧...(我应该学会如何提出问题,让回答不仅仅是“是”或“否”。)谢谢! - Paŭlo Ebermann
整个导出到 Git 的存储库有 24241 个对象,大约为 24 MB。那么让我们看看过滤会给我们带来什么。 - Paŭlo Ebermann
SVN仓库有45 MB大小...但两者都有2658个修订版本/提交,所以看起来我已经拥有了所有内容。 - Paŭlo Ebermann
你不能真正比较大小。git通常会更小。你可以使用git rev-list --all | wc -l计算提交的数量,但如果你删除了一些文件并压缩了空提交,你可能会有更少的提交数。 - Dustin
经过几个小时的工作(使用filter-branch),我现在只剩下了我真正想要的40个提交。(我将在另一个答案中描述这个过程。) - Paŭlo Ebermann

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接