使用现有目录结构的Git子目录过滤器

13

我正在使用filter-branch的--subdirectory-filter选项来分离一个Git存储库,它可以很好地工作,但是它会将所有东西都拉到存储库的根目录下面。

我目前有:

ABC
  - DEF
      - GHI
      - JKL
  - MNO

执行该命令的结果是:

git filter-branch -f --subdirectory-filter ABC/DEF --prune-empty -- --all

生成这个:

GHI
JKL

我真正想要的是这个:

ABC
  - DEF
      - GHI
      - JKL

我在Git文档中找不到显示保留(或设置)目录结构的过滤选项,而且我也找不到一个命令可以在过滤之后重新映射结构以达到我想要的效果。

这是否可能?

4个回答

3
我发现了一个答案(链接在此),可以解决这个问题。
命令如下:
git filter-branch -f --index-filter 'git ls-files -s \
| sed "s-\t-&ABC/DEF/-" \
| GIT_INDEX_FILE=$GIT_INDEX_FILE.new git update-index --index-info \
&& mv $GIT_INDEX_FILE.new $GIT_INDEX_FILE'

运行完美。

1
对我也完美地起作用了。感谢您的发布。我应该补充说明,这个命令并不替换 --subdirectory-filter 命令;你仍然需要执行那个命令。这个命令替换了其他文档推荐的 git mv * ... 命令。但是没有了 git mv 会生成的丑陋的大量提交。 - Edward Falk
很不幸,这对我不起作用。我在Windows上运行git-bash,它失败了,说找不到index.new ($GIT_INDEX_FILE.new)。我希望我能使用这个解决方案。 - Berin Loritsch
@BerinLoritsch $GIT_INDEX_FILE是一个环境变量,大多数我使用的工具都会为您设置;包括MsysGit、CygWin以及几个Windows上的git bash替代品。你的确切设置是什么? - JRoughan
它在Windows上使用位操作技术。它的行为不像完整的Unix系统那样。 - Berin Loritsch
在Windows git-bash中,这似乎会创建一个新的子目录(“ABC/DEF”),然后将所有文件移动到该子目录中,因此您最终得到的是包含现有存储库的“ABC/DEF/”,同时将所有内容移动到该子目录中而不删除任何内容。 - EKW

2

我只是进行了简单的测试,但我认为您可以使用git filter-branch--tree-filter来重写分支,但是除了子目录ABC/DEF中的文件之外,删除所有文件,例如以下内容:

git filter-branch --tree-filter \
    'find . -path ./ABC/DEF -prune -o -type f -print0 | xargs -0 rm -f' \
    --prune-empty HEAD

请注意,find 命令只会删除文件,而不是目录。但由于 Git 不存储空目录,因此这仍将产生您想要的结果。

谢谢你的回答。由于这个代码库的规模,我确实需要使用索引(index-filter)而不是树过滤器(tree-filter)。你的回答肯定是正确的方向,但在我的情况下可能会非常慢。我找到了一个答案,但我不确定是否应该接受自己的答案,因为这可能适用于大多数情况。 - JRoughan
鼓励自问自答,如果你的问题得到了解决,也应该接受自己的答案。不过你需要等待48小时。我测试过的--tree-filter版本命令确实非常慢,但通常使用filter-branch只需要一次性操作,所以如果需要整夜运行,我也不介意。 - Mark Longair
这是我能找到的唯一答案,它 a) 保留了现有的目录结构,并且 b) 真正过滤掉了不在目标目录中的所有内容。虽然花费了很长时间,但当我要求它过滤“/ABC”时,我实际上得到的是“/ABC/file.name”,而不是“/file.name”或“/ABC/ABC/file.name”,这才是最重要的。 - EKW

0

使用:

git filter-branch -f --to-subdirectory-filter ABC/DEF --prune-empty -- --all

虽然这段代码可能回答了问题,但建议解释一下它在做什么以及如何解决问题。 - dan1st

0

2020年+: 考虑到git filter-branch或BFG在Git 2.22(2019年第四季度)或更高版本后已过时,更好的选择是使用git filter-repo(基于Python,需要先安装):

git filter-repo --path ./ABC/DEF

这将保留目录结构。

请注意:git filter-repo强制你先进行备份, 然后继续更改正在过滤的本地仓库历史记录。


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