【问题标题】:Delete folder contents from Git history except for a set of files从 Git 历史记录中删除文件夹内容,但一组文件除外
【发布时间】:2020-06-06 23:48:51
【问题描述】:

我希望从 git 历史记录中删除文件夹的内容(可以递归地拥有文件夹)。但是,一些较旧的提交甚至没有该文件夹,而一些较新的提交在该文件夹中有我想要保留的文件。

假设文件夹是 foo(在路径 /path/to/foo 中),要保留的文件称为 bar1bar2(例如,/path/to/foo/bar1)。

我意识到这个问题并不新鲜。在this question 中,使用了一个冗长且难以阅读(至少对于初学者而言)的脚本。 This question 是最新的并使用 git filter-branch 但我不明白最终的解决方案是什么。最后,this question 可能是最相似的,但对于没有 git 高级知识的人来说,答案并不是“剖析”,所以我没有信心尝试这些命令。

据我所见,目前 git 2.17 的方法是为每个分支使用git filter-branch。然后使用tree-filterindex-filter (从文档中我无法看到用例的差异)。最后是一个git rm 命令,其正则表达式与foo 的内容匹配,bar 除外。正则表达式的第一部分可能很简单 (/path/to/foo/*),但我不确定如何添加例外。

如果有人能在提供解决此问题的命令时将这一切分解,我将不胜感激。

【问题讨论】:

    标签: git git-filter-branch


    【解决方案1】:
    git filter-branch --index-filter '
            dir=path/to/folder
            git rm -qr --cached --ignore-unmatch $dir
            git reset $GIT_COMMIT -- $dir/file1 $dir/file2 $dir/file3
    '
    

    索引过滤器和树过滤器之间的唯一区别是,树过滤器从提交中加载所有内容的树,然后通过将树中的所有内容与目录中列出的内容进行比较来为您更新索引index,更新索引以匹配新的树内容。这很容易,只是很慢而且通常是不必要的。

    【讨论】:

    • 首先非常感谢您的回答和解释。让我检查一下我是否理解了命令的其余部分:首先从$dir 中删除所有内容,然后重置我想要保留的文件,基本上在删除它们之后将它们从名为$GIT_COMMIT 的提交中恢复。我必须用提交哈希或 HEAD 替换它。此外,这一次只适用于一个分支,所以我必须检查每个分支并运行每个分支的命令,对吗?
    • 不,您不必进行替换,这是 shell 代码,请参阅 filter-branch 文档。您可以一次完成整个历史记录,将 -- --all 添加到 args 的末尾,在最后一个过滤器之后,请参阅 filter-branch 文档。仅删除索引条目,最简单的方法是清除一个子树然后恢复您想要的内容,但无论您做什么,它都不会变得更便宜,每个需要恢复的条目复制大约 100 个字节将是负载比对整个树中的每个条目运行复杂的正则表达式便宜。
    • 我明白了,filter-branch 命令会自动设置$GIT_COMMIT 变量。从文档中,我可能还应该添加(在-- --all 之前)--prune-empty 以删除空提交和--tag-name-filter cat 以更新标签。
    • 现在你明白了。就是这张票。
    • 谢谢!我保证这是最后一个问题:在运行命令之后,在推送之前,我如何在本地检查它是否有效?
    猜你喜欢
    • 2012-04-21
    • 1970-01-01
    • 2018-01-13
    • 1970-01-01
    • 2014-06-19
    • 2020-03-20
    • 1970-01-01
    • 1970-01-01
    • 2017-10-01
    相关资源
    最近更新 更多