我有很多 Git 分支。如何删除已经合并的分支?有没有一种简单的方法可以将它们全部删除而不是一个一个删除?
git branch -D
删除任何分支,无论它是否已合并。
master
之前/之后的距离。但是,如果您运行 git branch -a
,您的本地客户端仍会列出旧分支;使用 git fetch --prune
删除它们(根据 this answer )。
git delete-merged --doit origin
或 git delete-merged --doit --local
rm -fr work && git clone http://example.com/work.git
多年来已成为使用 git 摆脱困境的最简单方法。
更新:
如果您的工作流将这些分支作为可能的祖先,您可以添加其他分支以排除,例如 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 -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
更新(@oliver;因为不适合评论,但已经有足够的答案):如果您在分支 ABC 上,那么 ABC 将出现在 git branch -r --merged
的结果中,因为未指定分支,所以分支默认为当前分支,并且分支总是有资格合并到自身(因为分支和自身之间没有区别!)。
所以要么指定分支:
git branch -r --merged master | grep -v master ...
或第一个结帐大师:
git checkout master | git branch -r --merged | grep -v ...
dev
,所以我必须更改它
grep -v master
之后添加 | grep origin
以防止将其他遥控器的分支推送到原点。强烈建议使用 git branch -r --merged | grep -v master | grep origin | sed 's/origin\//:/' | xargs -n 1 echo
事先测试输出
develop
分支。 git branch -r --merged | grep -v master | grep -v develop | sed 's/origin\///' | xargs -n 1 git push --delete origin
。现在这竟然是我的别名。
-r
论点,我在其他任何地方都没有提到过。人们理所当然地认为,只有当地的分支机构才值得做一些家务。但是遥控器也充满了垃圾。
myFeatureBranch
上,它将擦除 origin/myFeatureBranch
。可能最好先git checkout master
。
只是扩展亚当的答案一点:
通过运行 git config -e --global
将其添加到您的 Git 配置中
[alias]
cleanup = "!git branch --merged | grep -v '\\*\\|master\\|develop' | xargs -n 1 -r git branch -d"
然后您可以通过简单的 git cleanup
删除所有本地合并的分支。
git branch --merged master
,因为您想查看已合并到 master 中的内容,而不是当前已签出的分支?
develop
或 dev
,在这种情况下,命令将因 fatal: malformed object name
而失败,最好有一个通用命令,您有责任运行它
-r
添加到 xargs
将防止在多次运行此别名或没有要删除的分支时出现不必要的错误 (branch name required
)。我的别名如下所示:cleanup = "!git branch --merged | grep -v -P '^\\*|master|develop' | xargs -n1 -r git branch -d"
您需要排除 master
、main
和develop
这些命令的分支。
本地 git 清除:
git branch --merged | grep -v '\*\|master\|main\|develop' | xargs -n 1 git branch -d
远程 git 清除:
git branch -r --merged | grep -v '\*\|master\|main\|develop' | sed 's/origin\///' | xargs -n 1 git push --delete origin
同步远程分支的本地注册表:
git fetch -p
git config --global --add fetch.prune true
在获取或拉取时自动修剪。
git branch -r --merged | grep -v '\*\|master\|develop' | grep '^\s*origin/' | sed 's/origin\///' | tr "\n" " " | xargs git push --delete origin
这也适用于删除除 master 之外的所有合并分支。
git branch --merged | grep -v '^* master$' | grep -v '^ master$' | xargs git branch -d
master
的分支。尝试 grep -v ^master$
作为中间。
| grep -v '^\*'
避免删除当前分支
grep -v '^ master$'
中有两个空格。如果您自己输入并漏掉了一个,如果您不在上面,您将删除 master
。
git branch
将在新行中列出每个分支名称,并在左侧有两个空格。您基本上保证了运行此命令的任何人都会删除他们的主分支,除非它是当前签出的分支。
对于那些在 Windows 上并且更喜欢 PowerShell 脚本的人,这里有一个删除本地合并分支的脚本:
function Remove-MergedBranches
{
git branch --merged |
ForEach-Object { $_.Trim() } |
Where-Object { $_ -NotMatch "^\*" } |
Where-Object { -not ( $_ -Like "*master" -or $_ -Like "*main" ) } |
ForEach-Object { git branch -d $_ }
}
或简短版本:
git branch --merged | %{$_.trim()} | ?{$_ -notmatch 'dev' -and $_ -notmatch 'master' -and $_ -notmatch 'main'} | %{git branch -d $_.trim()}
git branch --merged | ?{-not ($_ -like "*master")} | %{git branch -d $_.trim()}
for /f "usebackq" %B in (``git branch --merged^|findstr /v /c:"* " /c:"master"``) do @git branch -d %B
(叹气,用单引号替换双反引号,我不知道如何格式化包含反引号的文字)
我多年来一直使用亚当的答案。也就是说,在某些情况下它的行为并不像我预期的那样:
包含单词“master”的分支被忽略,例如“notmaster”或“masterful”,而不仅仅是包含单词“dev”的master分支被忽略,例如“dev-test”,而不仅仅是dev分支删除从当前分支的 HEAD 可到达的分支(即不一定是 master)处于分离 HEAD 状态,删除从当前提交可到达的每个分支
1& 2 很容易解决,只需更改正则表达式。 3 取决于您想要的上下文(即仅删除尚未合并到主分支或当前分支的分支)。如果您无意中以分离的 HEAD 状态运行它,则 4 可能会造成灾难性的后果(尽管可以使用 git reflog
恢复)。
最后,我希望这一切都在一个不需要单独的(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
或者:
git sweep -f
长而详细的答案
对我来说,创建一个带有一些分支和提交的示例 git repo 来测试正确的行为是最简单的:
使用单个提交创建一个新的 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
酒吧开发 foo * 高手 高手 非大师
期望的行为:选择所有合并的分支,除了:master、develop 或 current
原来的正则表达式错过了分支“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,如果我重新运行上面的命令来列出我要删除的分支,即使它还没有合并到 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)$)"
酒吧大师
这仅仅是因为 git branch --merged
如果没有另外指定,则默认为当前分支的 HEAD。至少对于我的工作流程,我不想删除本地分支,除非它们已合并到主分支,所以我更喜欢以下变体 using git rev-parse:
git checkout foobar
git branch --merged $(git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)"
酒吧大师
分离的 HEAD 状态
依赖 git branch --merged
的默认行为在分离 HEAD 状态下会产生更严重的后果:
git checkout foobar
git checkout HEAD~0
git branch --merged | egrep -v "(^\*|^\s*(master|develop)$)"
bar foo foobar 高超的 notmaster
这将删除我刚才所在的分支,“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
标志。默认行为是只删除已合并到 master 的分支,但 -f
标志将删除已合并到当前分支的分支。
git sweep
删除了分支栏(原为 9a56952)。删除了 masterful 分支(原为 9a56952)。删除了分支 notmaster(原为 9a56952)。
git sweep -f
删除了分支 foo(原为 2cea1ab)。
git config
不是原子的吗?
!f(){ git branch ...
。这是一个函数声明,对吧?为什么不直接从 git branch ...
开始?
git checkout master && git branch -d `git branch --merged` && git checkout -
除了它会删除 develop
,但可能是一种更简单的方法。
使用 Git 2.5.0 版:
git branch -d `git branch --merged`
master
分支顺便说一句!
master
上时才使用它。
git branch -d $(git branch --merged | grep -v master)
如果您使用的是 Windows,则可以使用带有 Out-GridView 的 Windows Powershell 或 Powershell 7 来获得一个不错的分支列表,然后用鼠标选择要删除的分支:
git branch --format "%(refname:short)" --merged | Out-GridView -PassThru | % { git branch -d $_ }
https://i.stack.imgur.com/78H7G.png
您可以将提交添加到 --merged 选项。这样,您可以确保只删除合并到的分支,即源/主
以下命令将从您的来源中删除合并的分支。
git branch -r --merged origin/master | grep -v "^.*master" | sed s:origin/:: |xargs -n 1 git push origin --delete
您可以测试将删除哪些分支,将 git push origin --delete 替换为 echo
git branch -r --merged origin/master | grep -v "^.*master" | sed s:origin/:: |xargs -n 1 echo
我使用以下 Ruby 脚本来删除我已经合并的本地和远程分支。如果我正在为具有多个遥控器的存储库执行此操作并且只想从一个中删除,我只需在遥控器列表中添加一个 select 语句以仅获取我想要的遥控器。
#!/usr/bin/env ruby
current_branch = `git symbolic-ref --short HEAD`.chomp
if current_branch != "master"
if $?.exitstatus == 0
puts "WARNING: You are on branch #{current_branch}, NOT master."
else
puts "WARNING: You are not on a branch"
end
puts
end
puts "Fetching merged branches..."
remote_branches= `git branch -r --merged`.
split("\n").
map(&:strip).
reject {|b| b =~ /\/(#{current_branch}|master)/}
local_branches= `git branch --merged`.
gsub(/^\* /, '').
split("\n").
map(&:strip).
reject {|b| b =~ /(#{current_branch}|master)/}
if remote_branches.empty? && local_branches.empty?
puts "No existing branches have been merged into #{current_branch}."
else
puts "This will remove the following branches:"
puts remote_branches.join("\n")
puts local_branches.join("\n")
puts "Proceed?"
if gets =~ /^y/i
remote_branches.each do |b|
remote, branch = b.split(/\//)
`git push #{remote} :#{branch}`
end
# Remove local branches
`git branch -d #{local_branches.join(' ')}`
else
puts "No branches removed."
end
end
remote_branches
行的拒绝语句的开头有一个额外的 \/
。这是一个错字还是有目的?
b.split(/\//)
行
如何在 PowerShell 控制台中删除合并的分支
git branch --merged | %{git branch -d $_.Trim()}
如果您想排除 master 或任何其他分支名称,您可以像这样使用 PowerShell Select-String 管道并将结果传递给 git branch -d
:
git branch -d $(git branch --merged | Select-String -NotMatch "master" | %{$_.ToString().Trim()})
* master
:)
我最喜欢的简单脚本:
git branch --merged | grep -E -v "(master|develop|other)" | xargs git branch -d
git branch | grep -E -v "(master|develop|other)" | xargs git branch -D
kuboon 的回答错过了删除分支名称中包含 master 一词的分支。以下改进了他的答案:
git branch -r --merged | grep -v "origin/master$" | sed 's/\s*origin\///' | xargs -n 1 git push --delete origin
当然,它不会删除“master”分支本身:)
注意:我对以前的答案不满意,(不是在所有系统上工作,不在远程工作,没有指定 --merged 分支,没有精确过滤)。所以,我添加我自己的答案。
主要有两种情况:
当地的
您想要删除已经合并到另一个本地分支的本地分支。在删除过程中,您希望保留一些重要的分支,例如 master、develop 等。
git branch --format "%(refname:short)" --merged master | grep -E -v '^master$|^feature/develop$' | xargs -n 1 git branch -d
笔记:
git branch output --format ".." 是去除空格并允许精确的grep匹配
grep -E 用于代替 egrep,因此它也适用于没有 egrep 的系统(即:用于 Windows 的 git)。
grep -E -v '^master$|^feature/develop$' 是指定我不想删除的本地分支
xargs -n 1 git branch -d:执行本地分支的删除(对远程分支不起作用)
当然,如果您尝试删除当前签出的分支,则会出现错误。所以,我建议提前切换到master。
偏僻的
您想要删除已经合并到另一个远程分支的远程分支。在删除过程中,你希望保留一些重要的分支,如 HEAD、master、releases 等。
git branch -r --format "%(refname:short)" --merged origin/master | grep -E -v '^*HEAD$|^*/master$|^*release' | cut -d/ -f2- | xargs -n 1 git push --delete origin
笔记:
对于远程,我们使用 -r 选项并提供完整的分支名称:origin/master
grep -E -v '^*HEAD$|^*/master$|^*release' 是为了匹配我们不想删除的远程分支。
cut -d/ -f2- :删除不需要的 'origin/' 前缀,否则由 git branch 命令打印出来。
xargs -n 1 git push --delete origin :执行远程分支的删除。
我用这个:
git branch --delete $(git branch --format '%(refname:short)' --merged | grep --invert-match 'main\|master\|branch-to-skip')
它以指定的格式列出所有合并的分支,然后将该列表提供给 git branch --delete。
Git 中没有命令会自动为您执行此操作。但是您可以编写一个使用 Git 命令的脚本来满足您的需求。这可以通过多种方式完成,具体取决于您使用的分支模型。
如果您需要知道分支是否已合并到 master 中,如果 myTopicBranch 已合并,则以下命令将不产生任何输出(即您可以将其删除)
$ git rev-list master | grep $(git rev-parse myTopicBranch)
您可以使用 Git 分支命令并解析出 Bash 中的所有分支并在所有分支上执行 for
循环。在此循环中,您可以使用上述命令检查是否可以删除分支。
git branch --merged | grep -Ev '^(. master|\*)' | xargs -n 1 git branch -d
将删除除当前签出分支和/或 master
之外的所有本地分支。
对于希望了解这些命令的人来说,这是一篇很有帮助的文章:Git Clean: Delete Already Merged Branches, by Steven Harman。
您可以使用 git-del-br
tool。
git-del-br -a
您可以使用 pip
安装它
pip install git-del-br
PS:我是该工具的作者。欢迎任何建议/反馈。
我使用 git-flow esque 命名方案,所以这对我来说非常安全:
git branch --merged | grep -e "^\s\+\(fix\|feature\)/" | xargs git branch -d
它主要查找以字符串 fix/
或 feature/
开头的合并提交。
在安装了 git bash 的 Windows 上 egrep -v 将不起作用
git branch --merged | grep -E -v "(master|test|dev)" | xargs git branch -d
其中 grep -E -v
等价于 egrep -v
使用 -d
删除已 合并 分支或使用 -D
删除 未合并 分支
如果您想删除所有已合并到您当前所在分支的本地分支,那么我根据之前的答案提出了一个安全命令:
git branch --merged | grep -v \* | grep -v '^\s*master$' | xargs -t -n 1 git branch -d
此命令不会影响您当前的分支或您的主分支。它还会使用 xargs 的 -t 标志在执行此操作之前告诉您它在做什么。
Adam's updated answer 的别名版本:
[alias]
branch-cleanup = "!git branch --merged | egrep -v \"(^\\*|master|dev)\" | xargs git branch -d #"
此外,有关转义复杂别名的便捷提示,请参阅 this answer。
公认的解决方案非常好,但有一个问题是它还会删除尚未合并到远程的本地分支。
如果您查看输出,您会看到类似
$ git branch --merged master -v
api_doc 3a05427 [gone] Start of describing the Java API
bla 52e080a Update wording.
branch-1.0 32f1a72 [maven-release-plugin] prepare release 1.0.1
initial_proposal 6e59fb0 [gone] Original proposal, converted to AsciiDoc.
issue_248 be2ba3c Skip unit-for-type checking. This needs more work. (#254)
master be2ba3c Skip unit-for-type checking. This needs more work. (#254)
分支 bla
和 issue_248
是将被静默删除的本地分支。
但是您也可以看到单词 [gone]
,它表示已推送到远程的分支(现在已消失),因此表示可以删除分支。
因此,原始答案可以更改为(拆分为多行以缩短行长)
git branch --merged master -v | \
grep "\\[gone\\]" | \
sed -e 's/^..//' -e 's/\S* .*//' | \
xargs git branch -d
保护尚未合并的分支。也不需要主人保护它的grepping,因为它在原点有一个遥控器并且不会显示为消失。
下面的查询对我有用
for branch in `git branch -r --merged | grep -v '\*\|master\|develop'|awk 'NR > 0 {print$1}'|awk '{gsub(/origin\//, "")}1'`;do git push origin --delete $branch; done
这将过滤 grep 管道中的任何给定分支。
在 http 克隆上运行良好,但对 ssh 连接不太好。
尝试以下命令:
git branch -d $(git branch --merged | grep -vw $(git rev-parse --abbrev-ref HEAD))
通过使用 git rev-parse
将得到 the current branch name 以排除它。如果您收到错误消息,则意味着没有要删除的本地分支。
要对远程分支执行相同操作(将 origin
更改为您的远程名称),请尝试:
git push origin -vd $(git branch -r --merged | grep -vw $(git rev-parse --abbrev-ref HEAD) | cut -d/ -f2)
如果您有多个遥控器,请在 cut
之前添加 grep origin |
以仅过滤 origin
。
如果上述命令失败,请先尝试删除合并的远程跟踪分支:
git branch -rd $(git branch -r --merged | grep -vw $(git rev-parse --abbrev-ref HEAD))
然后再次git fetch
遥控器并再次使用之前的git push -vd
命令。
如果您经常使用它,请考虑将其作为别名添加到您的 ~/.gitconfig
文件中。
如果您错误地删除了某些分支,请使用 git reflog
查找丢失的提交。
根据其中一些答案,我做了my own Bash script to do it too!
它使用 git branch --merged
和 git branch -d
删除已合并的分支,并在删除前提示您输入每个分支。
merged_branches () {
local current_branch=$(git rev-parse --abbrev-ref HEAD)
for branch in $(git branch --merged | cut -c3-)
do
echo "Branch $branch is already merged into $current_branch."
echo "Would you like to delete it? [Y]es/[N]o "
read REPLY
if [[ $REPLY =~ ^[Yy] ]]; then
git branch -d $branch
fi
done
}
截至2018.07
将此添加到 ~/.gitconfig
的 [alias]
部分:
sweep = !"f() { git branch --merged | egrep -v \"(^\\*|master|dev)\" || true | xargs git branch -d; }; f"
现在您只需调用 git sweep
即可执行所需的清理工作。
git branch --merged | %{$_.trim()} | ?{$_ -notmatch 'develop' -and $_ -notmatch 'master'} | %{git branch -d $_}
fatal: branch name required
。为避免这种情况,您可以将-r
传递给xargs
,这样如果 stdin 为空,它就不会运行git branch -d
。 (根据手册页,这是一个 GNU xargs 扩展)。