我已经使用亚当的答案多年了。就是说,在某些情况下,它的行为不符合我的预期:
- 包含单词“ master”的分支被忽略,例如“ notmaster”或“ masterful”,而不仅仅是master分支
- 包含单词“ dev”的分支将被忽略,例如“ dev-test”,而不仅仅是dev分支
- 删除当前分支的HEAD可以访问的分支(即不一定是主节点)
- 在分离的HEAD状态下,从当前提交中删除每个可到达的分支
1和2很容易解决,只是对正则表达式进行了更改。3取决于您想要的上下文(即,仅删除尚未合并到master或当前分支中的分支)。git reflog
如果您无意中以分离的HEAD状态运行此命令,则4可能会造成灾难性的后果(尽管可以使用恢复)。
最后,我希望所有这些都在一个单一的代码中,不需要单独的(Bash | Ruby | Python)脚本。
TL; DR
创建一个git别名“ sweep”,它接受一个可选-f
标志:
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 repo并提交以测试正确的行为:
一次提交即可创建一个新的git repo
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
期望的行为:选择所有合并的分支,除了:母版,开发版或当前版
原始正则表达式会错过分支“ masterful”和“ notmaster”:
git checkout foo
git branch --merged | egrep -v "(^\*|master|dev)"
bar
使用更新的正则表达式(现在不包括“开发”而不是“开发”):
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,如果我重新运行以上命令以列出要删除的分支,则即使没有将其合并到master中,也将包括分支“ foo”:
git branch --merged | egrep -v "(^\*|^\s*(master|develop)$)"
bar
foo
masterful
notmaster
但是,如果我在master上运行相同的命令,则不包括分支“ foo”:
git checkout master && git branch --merged | egrep -v "(^\*|^\s*(master|develop)$)"
bar
masterful
notmaster
这仅仅是因为git branch --merged
如果没有另外指定,则默认为当前分支的HEAD。至少对于我的工作流,除非本地分支已合并到master分支,否则我不希望删除它们,因此我更喜欢以下变体:
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
一行,包括实际删除
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
标志。默认行为是仅删除已合并到master的-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
删除任何分支(无论是否已合并)。