2010-12-29 6 views
7

簡易版でコミットを削除するにはgitのフィルタ分岐を使用した:私はブランチ「FOO-555」を持っている場合のようなメッセージとコミットの束と、彼らのメッセージをコミット

  • FOO 555:何とか
  • FOO 123:何とか何とか
  • FOO 555:何とか何とか何とか
  • FOO 321:blahblah

"foo 555:"で始まらないコミットをすべて削除したいのですが、git filter-branch(またはその他のツール)を使用する方法はありますか?

オリジナルバージョン(より詳細な):

Redmineの#555::SOME_MESSAGE

私たちのリポジトリに

我々は、すべてのメッセージが一定のパターンで始まるコミット規則を持っています

また、特定の問題のブランチに潜在的なリリースブランチの変更を反映させるために少しリベースします。つまり、私はブランチ "foo-555"を持っているかもしれませんが、 "pre-release"ブランチにマージする前に、プレリリースでfoo-555がないというコミットを得る必要があります(foo- 555は、早送りしてプレリリースにマージすることができます)。

しかし、プレリリースが時々変更されるため、プレリリースからコミットを取り込む状況が発生することがありますが、そのコミットは後にプレリリースから削除されます。プレリリースから来たコミットは、コミットメッセージの番号がブランチ番号と一致しないため、簡単に識別できます。例えば、私がfoo-555ブランチで "Redmine#123:..."を見ると、私はブランチではないことを知っています。

ここで質問します。「ブランチに属していない」コミットをすべて削除したいと思います。

  • は私のfoo-555支店にされていますが、いないプレリリースブランチで(前release..foo-555)
  • 「doesnのコミットメッセージを持っている:他の言葉では、いずれかのことをコミット"Redmine#555"から始まります。

もちろん、 "555"はブランチによって異なります。これを達成するためにfilter-branch(または他のツール)を使用する方法はありますか?現在私が見ることができる唯一の方法は、対話型のrebase( "git rebase -i")を実行して、すべての "悪い"コミットを手動で削除することです。

+0

あなたは桜、関連するブランチにしたいコミットを選ぶことができませんか? –

+0

私たちは*できますが、10 555のコミットと10の他のコミットがあるとしましょう。私はリセットして、10個のチェリーピックをしなければならないでしょう(もしそうなら、1つのフィルターブランチコマンドに対して)。 – machineghost

答えて

4

Redmine #555で行を削除するスクリプトを書く:もちろん

#!/bin/sh 

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

をあなたが(例えばechoedへのコマンドのスクリプト)欲しいしかしそれを行うことができます。

その後スクリプトにEDITORセットであなたのリベースを起動します。もちろん

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

をまだ完了することが保証されることはありません - リビジョンを残すことによって引き起こされリベース中にエラーがあるかもしれません。修正することはできますが、git rebase --continueを手動で実行してください。

+0

これはうまくいくようですが、Git(シェルスクリプトなし)を使って "git filter-branch --commit-filter"でプロセスを自動化する方法はありませんか? – machineghost

+1

'--commit-filter'のヘルプは、' skip_commit'がコミットを取り除いて**変更を**していないと言い、代わりに 'git-rebase'を使うと言います。 'filter-branch'はあなたのリビジョンを状態のシーケンスと見なし、各コミットを置換することができますが、変更は子に伝播しません。 'rebase'はあなたのリビジョンをパッチのスタックとみなし、midstream *の変更は将来のリビジョンに伝播します。しかし、それが失敗を引き起こす可能性があるため、完全に自動化することはできません。 –

+0

Ahhhhhhh。ありがとう! – machineghost

8

ここでは、リベースの代わりにfilter-branchを使用する高速なソリューションがあります。インタラクティブ性や競合を解決する必要はありません。

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

あなたはおそらく、その後でクリーンアップすることをお勧めします:

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

多くのコミットを含む大きなリポジトリの場合、これにはしばらく時間がかかることがあります(例えば、何十万というコミットを持つFreeBSDの '-CURRENT'ではコミットフィルタごとに数秒かかる)。 'git rev-list --all [...]'条件のはるかに速い代替案は 'git show $ GIT_COMMIT | grep -c "" ' – trombonehero

関連する問題