使用git filter-branch通过提交消息删除提交

时间:2010-12-29 21:48:36

标签: git

简单版本:

如果我有一个分支“foo-555”,有一堆提交信息如下:

  • foo 555:blah
  • foo 123:blah blah
  • foo 555:blah blah blah
  • foo 321:blahblah

我希望删除所有不以“foo 555:”开头的提交,有没有办法使用git filter-branch(或其他任何工具)?

原始版本(更详细):

在我们的存储库中,我们有一个约定,其中每个提交消息都以某种模式开头:

  

Redmine#555:SOME_MESSAGE

我们还进行了一些重新定位,以便将潜在的发布分支更改引入特定问题的分支。换句话说,我可能有分支“foo-555”,但在我将它合并到分支“预发布”之前,我需要获得预发布的任何提交,foo-555没有(所以foo- 555可以快进合并到预发布。)

但是,由于预发布有时会发生变化,我们有时会遇到从预发布中引入提交的情况,但之后的提交会从预发布中删除。很容易识别来自预发布的提交,因为提交消息中的数字与分支号码不匹配;例如,如果我在我的foo-555分支中看到“Redmine#123:...”,我知道它不是我分支的提交。

现在问题是:我想删除所有“不属于”分支的提交;换句话说,任何提交:

  • 在我的foo-555分支中,但不在预发布分支中(pre-release..foo-555)
  • 具有不以“Redmine#555”
  • 开头的提交消息

但当然“555”因分支而异。有没有办法使用filter-branch(或任何其他工具)来实现这一目标?目前我能看到的唯一方法是做一个交互式rebase(“git rebase -i”)并手动删除所有“坏”提交。

2 个答案:

答案 0 :(得分:9)

这是一个使用filter-branch而不是重新定位的快速解决方案。没有交互性或需要解决冲突。

git filter-branch --commit-filter '
    if [ `git rev-list --all --grep "<log-pattern>" | grep -c "$GIT_COMMIT"` -gt 0 ]
    then
        skip_commit "$@";
    else
        git commit-tree "$@";
    fi'  HEAD

您可能希望用以下内容进行清理:

git reflog expire --expire=now
git gc --prune=now

答案 1 :(得分:5)

编写脚本以删除Redmine #555行:

#!/bin/sh

mv $1 $1.$$
grep -v 'Redmine #555' < $1.$$ > $1
rm -f $1.$$

当然你可以随心所欲地做到这一点(例如echo ed的命令脚本。

然后启动您的rebase,并将EDITOR设置为您的脚本:

EDITOR=/path/to/script git rebase -i REVISION

当然,仍然无法保证完成 - 在退出修订期间可能会出现错误。您仍然可以手动修复它们并git rebase --continue