如何删除所有已合并的 Git 分支?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6127328/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-10 11:00:03  来源:igfitidea点击:

How can I delete all Git branches which have been merged?

gitgithubversion-controlbranchfeature-branch

提问by Nyambaa

I have many Git branches. How do I delete branches which have already been merged? Is there an easy way to delete them all instead of deleting them one by one?

我有很多 Git 分支。如何删除已经合并的分支?有没有一种简单的方法可以将它们全部删除而不是一个一个地删除它们?

回答by Adam Dymitruk

UPDATE:

更新:

You can add other branches to exclude like master and dev if your workflow has those as a possible ancestor. Usually I branch off of a "sprint-start" tag and master, dev and qa are not ancestors.

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

First, list all branches that were merged in remote.

首先,列出远程合并的所有分支。

git branch --merged

You might see few branches you don't want to remove. we can add few arguments to skip important branches that we don't want to delete like master or a develop. The following command will skip master branch and anything that has dev in it.

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

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

If you want to skip, you can add it to the egrep command like the following. The branch skip_branch_namewill not be deleted.

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

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

To delete all local branches that are already merged into the currently checked out branch:

删除所有已经合并到当前签出分支的本地分支:

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

You can see that master and dev are excluded in case they are an ancestor.

您可以看到 master 和 dev 在它们是祖先的情况下被排除在外。



You can delete a merged local branch with:

您可以使用以下命令删除合并的本地分支:

git branch -d branchname

If it's not merged, use:

如果未合并,请使用:

git branch -D branchname

To delete it from the remote use:

要从远程使用中删除它:

git push --delete origin branchname

git push origin :branchname    # for really old git

Once you delete the branch from the remote, you can prune to get rid of remote tracking branches with:

从远程删除分支后,您可以使用以下方法修剪以摆脱远程跟踪分支:

git remote prune origin

or prune individual remote tracking branches, as the other answer suggests, with:

或修剪单个远程跟踪分支,正如另一个答案所暗示的那样,使用:

git branch -dr branchname

Hope this helps.

希望这可以帮助。

回答by kuboon

To delete all branches on remote that are already merged:

要删除远程上已经合并的所有分支:

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

In more recent versions of Git

在更新的 Git 版本中

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

UPDATE (by @oliver; since does not fit in comment, but enough answers already): if you are on branch ABC then ABC will appear in the results of git branch -r --mergedbecause the branch is not specified, so branch defaults to current branch, and a branch always qualifies as merged to itself (because there are no differences between a branch and itself!).

更新(@oliver;因为不适合评论,但已经有足够的答案):如果您在分支 ABC 上,则 ABC 将出现在结果中,git branch -r --merged因为未指定分支,因此分支默认为当前分支,并且有一个分支始终符合与自身合并的条件(因为分支与自身之间没有区别!)。

So either specify the branch:

所以要么指定分支:

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

OR first checkout master:

或第一个结帐大师:

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

回答by real_ate

Just extending Adam's answer a little bit:

只是稍微扩展一下亚当的回答:

Add this to your Git configuration by running git config -e --global

通过运行将其添加到您的 Git 配置中 git config -e --global

[alias]
    cleanup = "!git branch --merged | grep  -v '\*\|master\|develop' | xargs -n 1 git branch -d"

And then you can delete all the local merged branches doing a simple git cleanup.

然后你可以删除所有本地合并的分支做一个简单的git cleanup.

回答by Ismael Abreu

This also works to delete all merged branches except master.

这也适用于删除除 master 之外的所有合并分支。

git branch --merged | grep -v '^* master$' | grep -v '^  master$' | xargs git branch -d

回答by Guido Bouman

You'll want to exclude the master& developbranches from those commands.

您需要从这些命令中排除master&develop分支。

Local git clear:

本地git清除:

git branch --merged | grep -v '\*\|master\|develop' | xargs -n 1 git branch -d

Remote git clear:

远程 git 清除:

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

Sync local registry of remote branches:

同步远程分支的本地注册表:

git fetch -p

回答by Klas Mellbourn

For those of you that are on Windows and prefer PowerShell scripts, here is one that deletes local merged branches:

对于那些使用 Windows 并且更喜欢 PowerShell 脚本的人,这里有一个删除本地合并分支的脚本:

function Remove-MergedBranches
{
  git branch --merged |
    ForEach-Object { $_.Trim() } |
    Where-Object {$_ -NotMatch "^\*"} |
    Where-Object {-not ( $_ -Like "*master" )} |
    ForEach-Object { git branch -d $_ }
}

回答by eddies

I've used Adam's answer for years now. That said, that there are some cases where it wasn't behaving as I expected:

我已经使用亚当的答案多年了。也就是说,在某些情况下它的行为不像我预期的那样:

  1. branches that containedthe word "master" were ignored, e.g. "notmaster" or "masterful", rather than only the master branch
  2. branches that containedthe word "dev" were ignored, e.g. "dev-test", rather than only the dev branch
  3. deleting branches that are reachable from the HEAD of the currentbranch (that is, not necessarily master)
  4. in detached HEAD state, deleting everybranch reachable from the current commit
  1. 包含单词“master”的分支被忽略,例如“notmaster”或“masterful”,而不仅仅是master分支
  2. 包含单词“dev”的分支被忽略,例如“dev-test”,而不仅仅是dev分支
  3. 删除从当前分支的 HEAD 可达的分支(即不一定是 master)
  4. 在分离的 HEAD 状态下,删除当前提交中可到达的每个分支

1 & 2 were straightforward to address, with just a change to the regex. 3 depends on the context of what you want (i.e. only delete branches that haven't been merged into master or against your current branch). 4 has the potential to be disastrous (although recoverable with git reflog), if you unintentionally ran this in detached HEAD state.

1 和 2 很容易解决,只需更改正则表达式。3 取决于您想要的上下文(即仅删除尚未合并到 master 或针对您当前分支的分支)。4 有可能是灾难性的(虽然可以用 恢复git reflog),如果你无意中在分离的 HEAD 状态下运行它。

Finally, I wanted this to all be in a one-liner that didn't require a separate (Bash|Ruby|Python) script.

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

TL;DR

TL; 博士

Create a git alias "sweep" that accepts an optional -fflag:

创建一个接受可选-f标志的 git 别名“sweep” :

git config --global alias.sweep '!git branch --merged $([[  != "-f" ]] \
&& git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)" \
| xargs git branch -d'

and invoke it with:

并使用以下命令调用它:

git sweep

or:

或者:

git sweep -f

The long, detailed answer

长而详细的答案

It was easiest for me to create an example git repo with some branches and commits to test the correct behavior:

对我来说,创建一个带有一些分支和提交的示例 git repo 来测试正确的行为是最简单的:

Create a new git repo with a single commit

使用一次提交创建一个新的 git repo

mkdir sweep-test && cd sweep-test && git init
echo "hello" > hello
git add . && git commit -am "initial commit"

Create some new branches

创建一些新分支

git branch foo && git branch bar && git branch develop && git branch notmaster && git branch masterful
git branch --list
  bar
  develop
  foo
* master
  masterful
  notmaster
  bar
  develop
  foo
* master
  masterful
  notmaster

Desired behavior: select all merged branches except: master, develop or current

期望的行为:选择所有合并的分支,除了:master、develop 或current

The original regex misses the branches "masterful" and "notmaster" :

原始正则表达式错过了分支 "masterful" 和 "notmaster" :

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

With the updated regex (which now excludes "develop" rather than "dev"):

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

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

Switch to branch foo, make a new commit, then checkout a new branch, foobar, based on foo:

切换到分支 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"

My current branch is foobar, and if I re-run the above command to list the branches I want to delete, the branch "foo" is included even though it hasn't been merged into master:

我当前的分支是 foobar,如果我重新运行上面的命令来列出我想删除的分支,即使它没有合并到 master 分支“foo”也会被包含在内:

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

However, if I run the same command on master, the branch "foo" is not included:

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

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

And this is simply because git branch --mergeddefaults to the HEAD of the current branch if not otherwise specified. At least for my workflow, I don't want to delete local branches unless they've been merged to master, so I prefer the following variant:

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

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

Detached HEAD state

分离的 HEAD 状态

Relying on the default behavior of git branch --mergedhas even more significant consequences in detached HEAD state:

依赖于的默认行为git branch --merged在分离的 HEAD 状态下会产生更显着的后果:

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

This would have deleted the branch I was just on, "foobar" along with "foo", which is almost certainly not the desired outcome. With our revised command, however:

这会删除我刚刚所在的分支,“foobar”和“foo”,这几乎肯定不是想要的结果。但是,使用我们修改后的命令:

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

One line, including the actual delete

一行,包括实际删除

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

All wrapped up into a git alias "sweep":

全部都包含在一个 git 别名“sweep”中:

git config --global alias.sweep '!git branch --merged $([[  != "-f" ]] \
&& git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)" \
| xargs git branch -d'

The alias accepts an optional -fflag. The default behavior is to only delete branches that have been merged into master, but the -fflag will delete branches that have been merged into the current branch.

别名接受一个可选-f标志。默认行为是只删除已合并到 master 中的-f分支,但该标志将删除已合并到当前分支中的分支。

git sweep
Deleted branch bar (was 9a56952).
Deleted branch masterful (was 9a56952).
Deleted branch notmaster (was 9a56952).
Deleted branch bar (was 9a56952).
Deleted branch masterful (was 9a56952).
Deleted branch notmaster (was 9a56952).
git sweep -f
Deleted branch foo (was 2cea1ab).
Deleted branch foo (was 2cea1ab).

回答by paul

Git Sweepdoes a great job of this.

Git Sweep在这方面做得很好。

回答by drautb

Using Git version 2.5.0:

使用 Git 版本 2.5.0:

git branch -d `git branch --merged`

回答by J?rn Reimerdes

You can add the commit to the --merged option. This way you can make sure only to remove branches which are merged into i.e. the origin/master

您可以将提交添加到 --merged 选项。通过这种方式,您可以确保只删除合并到 ie 中的分支,即 origin/master

Following command will remove merged branches from your origin.

以下命令将从您的源中删除合并的分支。

git branch -r --merged origin/master | grep -v "^.*master" | sed s:origin/:: |xargs -n 1 git push origin --delete 

You can test which branches will be removed replacing the git push origin --delete with echo

您可以测试哪些分支将被删除,用 echo 替换 git push origin --delete

git branch -r --merged origin/master | grep -v "^.*master" | sed s:origin/:: |xargs -n 1 echo