运行git filter-branch子目录过滤器也可以删除其他子目录历史记录

时间:2016-10-10 10:53:27

标签: git git-filter-branch

我们有一个大型存储库,其子文件夹为platforms

sdk/
    .git/
    android/
    ios/
    unity/
    windows/

我们现在要打破自己的存储库。保留所有历史和那里的分支。

我已经运行了命令

git filter-branch -f --prune-empty --subdirectory-filter android -- --all

看起来它已经运行了我想要的,促使子文件夹android成为这个新存储库的根目录,然后我将其推送到新的远程源(在GitHub上)

执行此操作时,我收到一条错误消息,指出文件太大而无法推送到远程,但此文件的路径为

 unity/QAApp/...

其他子文件夹的历史记录中存在我认为不会filter-branch --subdirectory-filter采用的文件。

我正在考虑运行手册

git filter-branch -f --prune-empty --tree-filter \
'git rm -rf --ignore-unmatch ios unity windows && rm -rf ios unity windows' \
-- --all

但似乎这是我理解filter-branch subdirectory-filter应该做的双重工作。这是预期的行为,还是我错误地运行了一个或另一个命令?

1 个答案:

答案 0 :(得分:1)

在使用git邮件列表的人员后退一点,看起来这似乎是filter-branch的一个问题。这里的主要问题是filter-branch只与与你指定的子目录交互的分支进行交互。如果你有一些从未做过的分支,命令就不会靠近它们,让你在你的回购中留下你可能不想要的历史记录。

获得我想要的第一种方法是清除所有不与子目录交互的分支,在本例中为android

path=android/
git for-each-ref --format='%(refname)' |
while read ref; do
  if test "$(git rev-list --count "$ref" -- "$path")" = 0; then
    echo "delete $ref"
  fi
done | git update-ref --stdin

此代码段会遍历您的git repo所具有的每个分支引用,检查它是否具有对您子目录的引用,如果没有,则将其删除。

接下来更改filter-branch命令

git filter-branch -f --prune-empty --tag-name-filter cat --subdirectory-filter android -- --all

在命令中添加--tag-name-filter cat会重做标记并阻止标记分支保留不需要的历史记录。

最后要做的就是擦拭保持备份的历史记录,

git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d

过滤器分支存储与其交互的每个分支的备份。这是正确和正确的行为,但为此目的,当您想要重写所有历史记录并了解您正在做的事情的后果时,删除备份是正确的,也可以。

在这之后,你得到一个正确的重做repo,只有该子目录中的历史记录,其他一切都被丢弃,包括从未与该子目录交互过的分支。