如何删除已合并的分支?我可以一次删除所有分支,而不是逐个删除每个分支吗?


当前回答

为了避免意外地从master以外的任何其他分支运行命令,我使用以下bash脚本。否则,从已合并非主分支的分支运行git branch--merged |grep-v“\*”|xargs-n 1 git branch-d可能会删除主分支。

#!/bin/bash

branch_name="$(git symbolic-ref HEAD 2>/dev/null)" ||
branch_name="(unnamed branch)"     # detached HEAD
branch_name=${branch_name##refs/heads/}

if [[ $branch_name == 'master' ]]; then
   read -r -p "Are you sure? [y/N] " response
   if [[ $response =~ ^([yY][eE][sS]|[yY])$ ]]; then
       git branch --merged | grep -v "\*" | xargs -n 1 git branch -d
   fi
else
   echo "Refusing to delete branches that are not merged into '$branch_name'. Checkout master first."
fi

其他回答

我已经用亚当的答案很多年了。也就是说,在某些情况下,它的行为并没有达到我的预期:

包含单词“master”的分支被忽略,例如“notmaster”或“masterful”,而不仅仅是master分支包含单词“dev”的分支被忽略,例如“dev test”,而不仅仅是dev分支删除可从当前分支的HEAD(即,不一定是主分支)访问的分支在分离HEAD状态下,删除当前提交中可访问的每个分支

1和2很容易解决,只需更改正则表达式。3取决于所需内容的上下文(即仅删除尚未合并到主分支或当前分支的分支)。如果您无意中在分离的HEAD状态下运行,4可能会造成灾难(尽管可以使用git-relog恢复)。

最后,我希望这一切都在一个不需要单独(Bash|Ruby|Python)脚本的一行中。

TL;博士

创建一个接受可选-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

or:

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

酒吧发展食品*船长,船长有驾驭能力的非主人翁

期望的行为:选择所有合并的分支,但主分支、开发分支或当前分支除外

原始正则表达式缺少分支“masterful”和“notmaster”:

git checkout foo
git branch --merged | egrep -v "(^\*|master|dev)"

酒吧

使用更新的正则表达式(现在不包括“develop”而不是“dev”):

git branch --merged | egrep -v "(^\*|^\s*(master|develop)$)"

酒吧有驾驭能力的非主人翁

切换到分支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”还没有合并到master中,它也会包含在内:

git branch --merged | egrep -v "(^\*|^\s*(master|develop)$)"

酒吧食品有驾驭能力的非主人翁

但是,如果我在master上运行相同的命令,则不包含分支“foo”:

git checkout master && git branch --merged | egrep -v "(^\*|^\s*(master|develop)$)"

酒吧有驾驭能力的非主人翁

这仅仅是因为如果没有另外指定,gitbranch--merged默认为当前分支的HEAD。至少对于我的工作流程来说,我不想删除本地分支,除非它们已合并到主分支,所以我更喜欢使用git-rev-parse的以下变体:

git checkout foobar
git branch --merged $(git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)"

酒吧有驾驭能力的非主人翁

分离的HEAD状态

依赖gitbranch的默认行为--merged在分离HEAD状态下会产生更严重的后果:

git checkout foobar
git checkout HEAD~0
git branch --merged | egrep -v "(^\*|^\s*(master|develop)$)"

酒吧食品脚踏板有驾驭能力的非主人翁

这会删除我刚才打开的分支,“foobar”和“foo”,这几乎肯定不是理想的结果。然而,通过我们修改的命令:

git branch --merged $(git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)"

酒吧有驾驭能力的非主人翁

一行,包括实际删除

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

删除了分支条(为9a56952)。删除了分支masterful(为9a56952)。删除了分支notmaster(为9a56952)。

git sweep -f

已删除分支foo(为2cea1ab)。

注意:如果您的工作流可能将master和dev作为祖先,则可以添加其他分支以排除它们。通常我从“sprint-start”标签分支出来,master、dev和qa都不是祖先。


首先,列出在远程中合并的本地跟踪分支(考虑使用-r标志列出所有远程跟踪分支)。

git branch --merged

您可能会看到一些不想删除的分支。我们可以添加一些参数来跳过我们不想删除的重要分支,比如master或develop。下面的命令将跳过master分支和其中包含dev的任何内容。

git branch --merged| egrep -v "(^\*|master|main|dev)"

如果要跳过,可以将其添加到egrep命令中,如下所示。不会删除分支skip_branch_name。

git branch --merged| egrep -v "(^\*|master|main|dev|skip_branch_name)"

要删除已合并到当前签出分支的所有本地分支,请执行以下操作:

git branch --merged | egrep -v "(^\*|master|main|dev)" | xargs git branch -d

您可以看到master和dev被排除在外,以防它们是祖先。


您可以通过以下方式删除合并的本地分支:

git branch -d branchname

如果未合并,请使用:

git branch -D branchname

要从远程使用中删除它,请执行以下操作:

git push --delete origin branchname

git push origin :branchname    # for really old git

从远程删除分支后,可以通过以下方式进行修剪以消除远程跟踪分支:

git remote prune origin

或者如另一个答案所示,通过以下方式修剪单独的远程跟踪分支:

git branch -dr branchname

我最喜欢的简单脚本:

git branch --merged | grep -E -v "(master|main|develop|other)" | xargs git branch -d

要删除远程上已合并的所有分支,请执行以下操作:

git branch -r --merged | grep -v master | sed 's/origin\//:/' | xargs -n 1 git push origin

在Git的最新版本中

git branch -r --merged | grep -v master | sed 's/origin\///' | xargs -n 1 git push --delete origin

UPDATE(通过@oliver;因为不适合注释,但已经有足够的答案了):如果您在分支ABC上,那么ABC将出现在git branch-r--merged的结果中,因为未指定分支,所以分支默认为当前分支,分支始终符合自身合并的条件(因为分支和自身之间没有区别!)。

因此,指定分支:

git branch -r --merged master | grep -v master ...

OR第一个结账主机:

git checkout master | git branch -r --merged | grep -v ...

如果您希望删除已合并的本地分支以及删除它们的远程控制器,这里是我更喜欢的一行代码:

git branch --merged | xargs -I_br -- sh -c 'git branch -d _br; git push origin --delete _br'