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

mac*_*ost 9 git

简单版本:

如果我有一个分支"foo-555",有一堆提交消息,如:

  • foo 555:等等
  • foo 123:等等等等
  • foo 555:等等等等
  • 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")并手动删除所有"不良"提交.

Gin*_*ngi 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
Run Code Online (Sandbox Code Playgroud)

你可能想要用以下方法清理:

git reflog expire --expire=now
git gc --prune=now
Run Code Online (Sandbox Code Playgroud)

  • 对于具有大量提交的大型存储库,这可能需要一段时间(例如,在FreeBSD`CURRENT`上每个提交过滤器几秒钟,其具有数十万次提交).`git rev-list --all [...]`条件的一个更快的替代方法是`git show $ GIT_COMMIT | grep -c"<log-pattern>"`. (3认同)

Ben*_*son 5

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

#!/bin/sh

mv $1 $1.$$
grep -v 'Redmine #555' < $1.$$ > $1
rm -f $1.$$
Run Code Online (Sandbox Code Playgroud)

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

然后使用EDITORset脚本启动你的rebase :

EDITOR=/path/to/script git rebase -i REVISION
Run Code Online (Sandbox Code Playgroud)

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