从Git仓库的历史记录中修剪空合并提交

50

我已经清理了我们的Git存储库,需要从历史记录中删除大部分内容。我是这样做的:

git filter-branch --prune-empty --tree-filter 'rm -rf some_stuff'

--prune-empty标志将删除在过程结束后留下空的提交(除了有多个父级的合并提交)。即使合并的分支绝对没有内容,而且合并也没有添加任何内容到树中。

我如何从历史记录中删除这些空的合并提交?

6个回答

51

这种方法比变基解决方案更优越,因为它可以保留原始历史的提交者信息、提交日期和非空合并

git filter-branch --prune-empty --parent-filter \
    'sed "s/-p //g" | xargs -r git show-branch --independent | sed "s/\</-p /g"'

这是受到内核邮件列表上与Lucas解决方案相同的线程启发的。但它不需要Ruby,只需一行代码即可。但是,它确实需要GNU版本的xargssed

1
对我来说最简单的解决方案,因为不需要外部脚本。 - krlmlr
7
在OSX上,sed "s/-p //g" | xargs git show-branch --independent | sed "s/^/-p /g" | tr "\n" " " 对我来说似乎可行。 - James EJ
1
不会从底部树中删除合并提交,即两个空提交(每个没有祖先)的合并。 - Tomas
3
另一个 macOS 的选择是:brew install gnu-sed findutils,这样你就可以使用 gsed 替换 sed,gxargs 替换 xargs,享受 GNU 带来的好处。 - Dave Gregory

11

在对ssokolow/profile的副本运行filter-branch以分离出ssokolow/lap后,我需要这样做。

这个命令相当不错,可以自动"折叠掉由--prune-empty留下来的任何残余内容":

git rebase --root HEAD

(我需要使用--root选项,以便用最早仍有内容的提交替换现在为空的初始提交。)


2
虽然在某些情况下可能过于复杂,但它确实很有用。值得注意的是,这种方法会将所有合并操作都展开,而不仅仅是空的合并操作。 - Joey Coleman
1
请注意,这会将GIT_COMMITTER_DATE重置为git rebase默认执行的操作。 - glen
@ElanRuusamäe:你知道避免这种情况的方法吗?(即保留原提交者信息)? - Thilo
2
@Thilo:查看git rebasegit am的文档(git rebase委托给它),我认为使用--committer-date-is-author-date应该可以。我还没有自己尝试过,但我即将尝试。 - eestrada
这个 git rebase 命令要求我修复数百个“error: could not apply”错误。有没有一种方法可以跳过它们全部? - Cœur
显示剩余2条评论

3

1
git-filter-repo中,--prune-degenerate选项可用于此操作:

[合并提交]可能会因为修剪其他提交(具有少于两个父级,将一个提交作为两个父级,或将一个父级作为另一个的祖先)而变得退化。如果这些合并提交没有文件更改,则[将被]修剪。

git filter-repo --prune-degenerate always

请记住,上述命令默认适用于整个存储库。如果您想限制影响,可以指定--refs


0

我的解决方案是将所有内容移动到子目录(历史记录),然后使用--subdirectory-filter

第一步将git存储库合并到子目录中的错误组合

我稍微修改了sh文件:

#!/bin/bash

git ls-files -s | sed "s-\t-&temp_dir/-" | GIT_INDEX_FILE="$GIT_INDEX_FILE.new" git update-index --index-info

mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE" || true

运行

git filter-branch --index-filter '~/doit.sh' HEAD

第二步

git filter-branch --subdirectory-filter temp_dir --prune-empty

并将其推送。


-2

它不起作用。从man git filter-branch:“如果您不希望保留具有单个父级且对树没有更改的提交,则可以使用git_commit_non_empty_tree“$ @”而不是git commit-tree“$ @”。但合并提交具有多个父级。因此,它与--prune-empty标志相同。我尝试了一下,它没有修剪空的合并提交。 :/ - Bjarke Freund-Hansen
啊,好的,该死。那就需要更多的研究了。马上回来。 - ralphtheninja
看看那个包装脚本。 - ralphtheninja
我无法让Perl脚本正常工作,出现了“Can't locate Chj/xperlfunc.pm in @INC ...”错误。如果我在谷歌上搜索xperlfunc,我找不到任何有用的信息。您是否成功使用过这个脚本? - Bjarke Freund-Hansen
抱歉,我忘记了一个链接:http://lists.q42.co.uk/pipermail/git-announce/2011-September/000486.html。 - ralphtheninja
嗨,是的,现在它运行得非常好。您应该编辑您的答案并包含评论中的信息,我会接受它。非常感谢。 :) - Bjarke Freund-Hansen

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