私は何年もの間、アダムの答えを使いました。とは言っても、期待どおりに動作しない場合がいくつかあります。
- マスターブランチだけではなく、「マスター」という単語を含むブランチ(たとえば、「notmaster」や「masterful」)は無視されました。
- 「dev」という単語を含むブランチ、たとえば「dev-test」は、devブランチだけではなく無視されました
- 現在のブランチ(つまり、必ずしもマスターではない)のHEADから到達可能なブランチを削除する
- デタッチされたHEAD状態では、現在のコミットから到達可能なすべてのブランチを削除します
1と2は、正規表現を変更しただけで、簡単に対処できました。3は、必要なコンテキストに応じて異なります(つまり、マスターにマージされていない、または現在のブランチに対してマージされていないブランチのみを削除します)。4は、git reflog
デタッチされたHEAD状態で意図せずにこれを実行した場合、(で回復可能ですが)悲惨な可能性があります。
最後に、これをすべて個別の(Bash | Ruby | Python)スクリプトを必要としないワンライナーにしたかったのです。
TL; DR
オプションの-f
フラグを受け入れるgitエイリアス「sweep」を作成します。
git config --global alias.sweep '!git branch --merged $([[ $1 != "-f" ]] \
&& git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)" \
| xargs git branch -d'
そしてそれを呼び出す:
git sweep
または:
git sweep -f
長く詳細な答え
いくつかのブランチとコミットを使用して正しい動作をテストするサンプルgitリポジトリを作成するのが最も簡単でした。
単一のコミットで新しいgitリポジトリを作成する
mkdir sweep-test && cd sweep-test && git init
echo "hello" > hello
git add . && git commit -am "initial commit"
新しいブランチをいくつか作成します
git branch foo && git branch bar && git branch develop && git branch notmaster && git branch masterful
git branch --list
bar
develop
foo
* master
masterful
notmaster
望ましい動作:マスター、開発、または現在を除くすべてのマージされたブランチを選択します
元の正規表現では、「マスターフル」と「ノットマスター」のブランチがありません。
git checkout foo
git branch --merged | egrep -v "(^\*|master|dev)"
bar
更新された正規表現を使用すると(「dev」ではなく「develop」が除外されます):
git branch --merged | egrep -v "(^\*|^\s*(master|develop)$)"
bar
masterful
notmaster
ブランチfooに切り替え、新しいコミットを作成してから、fooに基づいて新しいブランチfoobarをチェックアウトします。
echo "foo" > foo
git add . && git commit -am "foo"
git checkout -b foobar
echo "foobar" > foobar
git add . && git commit -am "foobar"
私の現在のブランチはfoobarです。削除するブランチを一覧表示するために上記のコマンドを再実行すると、マスターにマージされていなくてもブランチ「foo」が含まれています。
git branch --merged | egrep -v "(^\*|^\s*(master|develop)$)"
bar
foo
masterful
notmaster
ただし、同じコマンドをマスターで実行すると、ブランチ「foo」が含まれません。
git checkout master && git branch --merged | egrep -v "(^\*|^\s*(master|develop)$)"
bar
masterful
notmaster
これはgit branch --merged
、特に指定されていない場合、デフォルトで現在のブランチのHEADに設定されているためです。少なくとも私のワークフローでは、マスターにマージされていない限り、ローカルブランチを削除したくないので、次のバリアントを使用します。
git checkout foobar
git branch --merged $(git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)"
bar
masterful
notmaster
切り離されたHEAD状態
のデフォルトの動作に依存すると、git branch --merged
デタッチされたHEAD状態にさらに重大な影響があります。
git checkout foobar
git checkout HEAD~0
git branch --merged | egrep -v "(^\*|^\s*(master|develop)$)"
bar
foo
foobar
masterful
notmaster
これは、私がちょうどいたブランチである "foobar"と "foo"を削除していたでしょう。ただし、改訂されたコマンドでは、次のようになります。
git branch --merged $(git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)"
bar
masterful
notmaster
実際の削除を含む1行
git branch --merged $(git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)" | xargs git branch -d
すべてがgitエイリアス「sweep」にまとめられています。
git config --global alias.sweep '!git branch --merged $([[ $1 != "-f" ]] \
&& git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)" \
| xargs git branch -d'
エイリアスはオプションの-f
フラグを受け入れます。デフォルトの動作では、マスターにマージされたブランチのみが削除されますが、-f
フラグは現在のブランチにマージされたブランチを削除します。
git sweep
Deleted branch bar (was 9a56952).
Deleted branch masterful (was 9a56952).
Deleted branch notmaster (was 9a56952).
git sweep -f
Deleted branch foo (was 2cea1ab).
git branch -D
すると、マージされているかどうかに関係なく、ブランチが削除されます。