您确实可以使用子目录过滤器,然后使用索引过滤器将内容放回到子目录中,但是为什么要打扰,何时可以自己使用索引过滤器?
下面是从该名男子页的例子:
git filter-branch --index-filter 'git rm --cached --ignore-unmatch filename' HEAD
这只是删除一个文件名;你想要做的是删除除了给定子目录以外的所有内容。如果你要谨慎,你可以明确地列出每个路径删除,但如果你想只是去全在,你可以做这样的事情:
git filter-branch --index-filter 'git ls-tree -z --name-only --full-tree $GIT_COMMIT | grep -zv "^directory-to-keep$" | xargs -0 git rm --cached -r' -- --all
我预计可能有一个更优雅的方式;如果有人有东西,请提出建议!
对命令的几个注意事项:
- 过滤器分支内部设置GIT_COMMIT到当前提交SHA1
- 我也没有想到
--full-tree
是必要的,但显然过滤分支运行指标 - .git-rewrite/t
目录中的过滤器,而不是回购的顶层。
- grep可能是矫枉过正,但我不认为这是一个速度问题。
--all
适用于所有裁判;我想你真的想要这样。 (--
将其与筛选分支选项分开)
-z
和-0
告诉ls-tree,grep和xargs使用NUL终止来处理文件名中的空格。
编辑,很久以后:Thomas有用地建议了一种方法来删除现在空的提交,但它现在已经过时。看看编辑的历史,如果你有一个旧版本的git的,但与现代的混帐,所有你需要做的就是这个选项的策略:
--prune-empty
这将去除后是空的所有提交应用索引过滤器。
除了嵌套的单引号(我冒昧替换)之外,这个工作几乎完美。唯一的问题是空的提交到现在不存在的目录保留在日志中。我删除了这些使用'git filter-branch -f --commit-filter'if [z $ 1 = z \'git rev-parse $ 3^{tree} \'];然后skip_commit“$ @”;否则git commit-tree“$ @”; fi'“$ @”',我在http://github.com/jwiegley/git-scripts/blob/master/git-remove-empty-commits – Thomas 2010-05-10 18:43:44
@Thomas发现:托马斯:感谢您解决我粗心的错误!此外,您应该能够在与索引过滤器相同的命令中使用提交过滤器。过滤器按照文档中显示的顺序运行; commit-filter自然是在修改提交内容的过滤器之后。您可能还想使用'--remap-to-ancestor',这会导致refs指向跳过的提交将移动到最近的祖先,而不是排除它们。 – Cascabel 2010-05-10 19:01:40
@Jefromi:'index-filter'参数应该更容易表达为'git rm -r -f --cached --ignore-unmatch $(ls!(目录保留))',看我的答案http ://stackoverflow.com/a/8079852/396967和http://stackoverflow.com/a/7849648/396967 – kynan 2011-12-04 14:20:55