提取git子目录并保留重命名的历史记录

12
我正在将一个大的源代码树分成两个独立的组件和一个共享子模块。为了准备这次拆分,我首先将共享的内容移入单个“common”目录中,更新了所有引用,并提交了一次更改。到此为止都很顺利。现在我想将该目录提取为一个子模块。
通常我会使用
git filter-branch --subdirectory-filter

但是,在这种情况下,所有有趣的历史事件都发生在该子目录之外,因此历史记录会丢失。

我明白保留完整历史记录没有意义,因为这将不会过滤掉任何数据。但我并不是真的想要能够回到过去构建项目,我只想能够查看每个文件所属的提交记录。

有没有一种方法可以保持filter-branch的行为,同时保留各个文件的历史记录?

2个回答

4
并不完全如此。 --subdirectory-filter 是一个特殊情况,因为它实际上会显著修改树的内容(因为它将东西移动到一个或多个目录嵌套级别)。
因此,在你筛选的子目录之外的文件和可以存储为结果提交的树之间没有真正良好的映射关系。
请记住,filter-branch 正在完全重写你的历史记录 - 输出是一组全新的提交,并且没有任何与旧提交的“链接”,因此任何额外信息都必须作为新提交的一部分表达。

2
这对我来说都很有道理,但至少在原则上,我可以想象将目录中当前的文件集追溯到每个提交历史记录,并计算重命名次数。通过这种方式,每个提交对象要么涉及子目录中的文件,要么不涉及。那些不涉及它们的可以被删除,而那些涉及它们的可以被重新编写以省略其他文件。我不介意在我的历史记录顶部有一个移动提交,我只想保留所有的更改。 - Russell Mull
如果您要在子模块中git checkout其中一个“早期历史”提交,那么git会做什么?如果该文件曾经位于存储库现在的顶级目录之上,那么Git无法很好地处理它。 - Amber
1
我在这上面浪费了很多时间,但是没有任何效果... 我仍然认为有足够聪明的人可以做到。 - Russell Mull
很遗憾,这样做会丢失一些历史记录(如果文件夹本身被重命名了 :| ):| - rogerdpack

3

这是我刚刚解决类似问题的方法。我在一个准私有的“misc”仓库中开始了一个项目,重命名了一些文件,然后我想将该项目上传到GitHub上的https://github.com/kragen/aikidraw

$ git clone misc aikidraw
$ cat > aikidraw-wanted
aikidraw.js
aikidraw.html
caposketchra.html
caposketchra.js
jquery-1.2.6.js
^D
$ cd aikidraw
$ git filter-branch --tree-filter 'bash -c "comm -23 <(/bin/ls | sort) <(sort ~/devel/aikidraw-wanted) | xargs rm -rf"' HEAD

目前看来这样做还可以,除了没有删除点文件(如.git,是好的,和.gitignore,是坏的),但显然我的Git版本(1.6.0.4)没有git filter-branch --prune-empty。所以现在我克隆新的、更小的仓库(为了能更快地将其复制到网络上),并将代码库复制到另一台安装有Git 1.7.2.5的机器上:

$ time git clone aikidraw aikidraw-smaller
$ du -sh aikidraw/.git aikidraw-smaller/.git
8.6M    aikidraw/.git
1.2M    aikidraw-smaller/.git

$ time rsync -Pav aikidraw-smaller panacea.canonical.org:devel/aikidraw/
real    1m23.251s

然后在panacea.canonical.org上:

$ cd ~/devel/aikidraw/aikidraw-smaller  # Oops. I hate rsync sometimes.
$ git checkout  # otherwise I get "Cannot rewrite branch(es) with a dirty working directory."
$ git filter-branch --prune-empty HEAD
$ cd ../..
$ mv aikidraw i-hate-rsync
$ mv i-hate-rsync/aikidraw-smaller/ aikidraw

然后回到我的上网本:
$ mv aikidraw aikidraw-big
$ git clone panacea.canonical.org:devel/aikidraw
$ du -sh aikidraw/.git
268K    aikidraw/.git

现在,如果您使用的是两个目录而不是五个文件,则此时您可能希望使用git mv将剩余子目录中的所有内容重命名为存储库的根目录。在我的情况下,我已经完成了重命名。

$ git remote add github git@github.com:kragen/aikidraw.git
$ git push github master

希望这能帮到你!

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