如何修剪本地跟踪分支,这些分支在远程不存在了?

1322

使用git remote prune origin可以删除本地不再追踪的远程分支。

但是我也想删除从这些远程分支创建的本地分支(检查它们是否未合并会很好)。

我应该怎么做?


12
可能是「删除不在远程的本地分支」的重复问题。 - kolen
6
一句话介绍:跨平台的命令行工具,不会让人觉得像猫睡在你的键盘上一样混乱。要使用此工具,请先安装_node.js_。使用npx git-removed-branches(干运行) 或 npx git-removed-branches --prune(真实运行)。详细信息请参见以下答案 - Cristian Diaconescu
我通常认为这些事情应该是有意识地完成,而不是自动化的,否则你会面临删除你不想删除的东西的风险。因此,我会坚持使用 git branch -d localBranchName 和 git push origin --delete remoteBranchName。 - Epirocks
3
对于使用IntelliJ的用户,以下插件正好满足您的需求:https://plugins.jetbrains.com/plugin/10059-git-branch-cleaner - Daniel
40个回答

1430

修剪之后,您可以使用git branch -r获取远程分支列表。可以使用git branch -vv检索具有其远程跟踪分支的分支列表。因此,使用这两个列表,您可以查找不在远程列表中的远程跟踪分支。

这行代码应该可以解决问题(需要bashzsh,在标准Bourne shell下无法工作):

git fetch -p ; git branch -r | awk '{print $1}' | egrep -v -f /dev/fd/0 <(git branch -vv | grep origin) | awk '{print $1}' | xargs git branch -d

这个字符串获取远程分支列表并将其通过标准输入传递给 egrep。过滤具有远程跟踪分支的分支 (使用 git branch -vv 并过滤那些具有 origin 的分支),然后获取该输出的第一列,即分支名称。最后将所有分支名称传递到删除分支命令中。

由于它使用了 -d 选项,因此当您运行此命令时,它不会删除未合并到您所在分支的分支。


25
这对我完美地起了作用。不知何故,git fetch -p有时候并不足够? - Stefan Hendriks
28
很不幸,在Windows上的Git Bash无法正常工作。提示信息为: sh.exe": cannot make pipe for process substitution: Function not implemented sh.exe": egrep -v -f /dev/fd/0: No such file or directory fatal: branch name required 你有什么想法吗? - Ludder
56
将其添加为别名:alias git-remove-untracked='git fetch --prune && git branch -r | awk "{print \$1}" | egrep -v -f /dev/fd/0 <(git branch -vv | grep origin) | awk "{print \$1}" | xargs git branch -d' - bryant1410
238
未来的git版本中是否有任何提议的命令可以实现这一点?这个命令看起来就像我的猫在我的笔记本电脑上乱按键。 - Bron Davies
45
在命令的末尾使用 git branch -D 对我们来说效果更好,因为我们倾向于在合并时压缩提交记录,如果带有 -d 参数运行,则会出现“分支 x 没有完全合并”的错误提示。 - Mateus Gondim
显示剩余32条评论

639

如果您想要删除所有已经合并到主分支的本地分支,可以使用以下命令:

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

如果您使用 main 分支作为主分支,您应该相应地修改命令:

git branch --merged main | grep -v '^[ *]*main$' | xargs git branch -d

更多信息


6
我认为它完美地发挥了作用!有人能解释一下这个答案是否与被接受的答案有所不同吗? - Andrew
13
小改进:使用 xargs -r git branch -d 命令,以便在没有要删除的分支时不运行任何命令。请注意,-r 标志可能不是在所有地方都可用 - Jacob Wang
8
由于git的颜色可能导致grep无法匹配:git branch --merged master --no-color | grep -v '^* master$' | xargs -n1 -r git branch -d - Mike D
6
既然你这么客气地问了,git branch --merged master 会列出已经合并到主分支的分支,中间的 grep 部分排除了主分支本身(我们不希望删除主分支!),最后的 xargs 部分对结果中的每个分支执行 git branch -d 命令来删除它。或者您也可以阅读答案中提供的“更多信息”链接 ;) - jackocnr
19
改进后的命令是:git branch --merged master | egrep -v '^\s*\*?\s*master$' | xargs git branch -d。在使用git版本2.10.1时,如果当前分支是master,则命令输出会显示 "* master"。不论是否有星号,上述命令均可删除master分支。 - Esteban
显示剩余15条评论

268

git help fetch 提供的信息中,有这么一项:

 -p, --prune
        After fetching, remove any remote-tracking branches which no longer exist on the remote.

那么,也许 git fetch -p 就是你要找的东西?

编辑:好吧,对于那些在三年后仍然争论这个答案的人,我会提供一些更多关于为什么我提出这个答案的信息...

首先,原帖作者说他们想要“删除那些从那些不再存在于远程的分支创建的本地分支”,但这在 git 中并非毫无歧义的。以下是一个例子。

假设我有一个托管在中央服务器上的 repo,它有两个分支,叫做 AB。如果我将该 repo 克隆到我的本地系统上,我的克隆将具有称为 origin/Aorigin/B 的本地引用(尚未是实际的分支)。现在假设我执行以下操作:

git checkout -b A origin/A
git checkout -b Z origin/B
git checkout -b C <some hash>

这里需要注意的是,我出于某种原因选择在本地repo上创建一个与它的源不同名的分支,并且我还有一个本地分支在源repo上(尚未)存在。

现在假设我删除远程repo上的AB分支,并更新我的本地repo(某种形式的git fetch),这将导致我的本地引用origin/Aorigin/B消失。现在,我的本地repo仍然有三个分支,AZ,和C。它们中没有一个对应于远程repo上的分支。其中两个分支是“从...远程分支创建”的,但即使我知道原来在源上有一个名为B的分支,我也无法知道Z是从B创建的,因为在此过程中已将其重命名,很可能是有充分理由的。因此,实际上,如果没有记录分支来源元数据的外部过程或者知道历史的人,就无法确定OP要删除的这三个分支中的哪一个(如果有)。没有一些git不能自动维护的外部信息,git fetch -p是你能得到的最接近的东西,而任何试图实现OP所要求的字面意义的自动方法都存在删除太多分支或错过一些OP原本想要删除的分支的风险。

还有其他情况,例如我从origin/A创建了三个单独的分支来测试三种不同的方法,然后origin/A消失了。现在我有了三个分支,显然它们不可能都匹配名称,但它们是从origin/A创建的,因此对于OP问题的字面解释要求删除所有三个分支。然而,如果你甚至能找到可靠的方法将它们匹配起来,这可能并不可取...


135
这不会删除本地分支,只会删除指向这些分支的远程指针。 - Jaap
7
它仅会删除那些本地分支,这些分支不存在于远程并且您从未在它们上面进行过checkout操作。 - Jarek Jakubowski
18
正如Jaap所指出的那样,你应该更仔细地阅读问题。投票支持这个答案的人也应该阅读问题真正关注的内容。 - Søren Boisen
12
是的,这确实是我想做的!@SørenBoisen,我希望在过去的两年里你有时间重新审视你的那个观点…如果在SO上发布的内容总是只与一些让OP困惑的问题相关,我们将删除很多信息。请不要假定以除官方指南外的方式告诉人们如何使用此网站,而且这些指南显然并不会阻止正交但有用的答案。 - Félix Adriyel Gagnon-Grenier
9
这是我的问题:1)问题非常明确,OP显然没有困惑。2)这个答案没有提到它没有回答问题!3)问题已经说明了一种修剪不再存在的远程跟踪分支的方法,因此它没有任何附加价值。 - Søren Boisen
显示剩余4条评论

206

有一个很好的npm包可以为您完成这项任务(它应该可以跨平台使用)。

安装方法:npm install -g git-removed-branches

然后,git removed-branches将向您显示所有过时的本地分支,git removed-branches --prune将实际删除它们。

更多信息在此处。


7
这篇文章应该得到更多的赞。感谢你让生活变得更加简单,不管使用哪个平台。 - Encryption
16
这是我最喜欢的答案。npx git-removed-branches 就像梦一样好用。 - Drazisil
5
是的!这应该有更多的赞!对于命令行界面新手来说,这是一个非常简单和直观的解决方案。 - geoseong
8
从 Git 的角度概述一下该工具正在做什么会很有用。 - ryanwebjackson
2
@ryanwebjackson 该项目在Github上:https://github.com/nemisj/git-removed-branches - flowerpowerdad
显示剩余3条评论

177

这将删除已经被远程跟踪分支修剪过的本地分支。(确保你在master分支上!)

git checkout master
git branch -vv | grep ': gone]' | awk '{print $1}' | xargs git branch -d

细节:

  • 当远程分支已被修枝时,git branch -vv 会显示本地分支为 "gone"。


mybranch abc1234 [origin/mybranch: gone] commit comments
  • -d 会检查是否已合并(-D 则无论如何都会删除它)。

  • error: The branch 'mybranch' is not fully merged.
    

    20
    您甚至可以使用 git branch -vv | awk '/: gone]/{print $1}' | xargs git branch -d 命令缩短操作。 - chiborg
    11
    提醒一下,在执行此操作之前,请确保你已经切换到主分支(master),因为git branch -d命令是将当前分支与HEAD进行比较的。 - Steve Bennett
    5
    哦,伙计... wisbucky你需要更新你的答案告诉人们他们应该在主分支上。我刚从另一个分支合并到主分支。@stevebennet2感谢你的有益评论。 - GrayedFox
    2
    : gone] 部分是本地化字符串。对于法语版本,您必须使用 : disparue] - alexandre-rousseau
    3
    对于决定使用 xargs git branch -D 的任何人,请注意 -D 标志本质上是“强制删除”,但在删除远程分支被压缩合并或重新基础的分支时是必要的,因此作为一个好的中间地带,我建议在每次删除之前提示用户确认(更安全);使用 xargs -p git branch -D - ksgj1
    显示剩余6条评论

    95

    Windows 解决方案

    对于微软 Windows Powershell:

    git checkout master; git remote update origin --prune; git branch -vv | Select-String -Pattern ": gone]" | % { $_.toString().Trim().Split(" ")[0]} | % {git branch -d $_}
    

    解释

    git checkout master 切换到主分支

    git remote update origin --prune 清理远程分支

    git branch -vv 获取所有分支的详细信息 (git reference)

    Select-String -Pattern ": gone]" 只获取已从远程删除的记录。

    % { $_.toString().Split(" ")[0]} 获取分支名称

    % {git branch -d $_} 删除分支


    4
    似乎最新版本的Git会添加一些尾随空格,因此Split无法获取分支名称。执行.toString().Trim().Split(" ")即可解决问题。 - Chris Hynes
    @Omzig 这个有什么不同的作用?你能解释一下吗? - chris31389
    1
    @chris31389,我已经拉取了所有从主分支缺失的内容,并将分支更改为--merged而不是master,我想确保我只删除--merged分支。这样做让我感觉更好 ;) - Omzig
    1
    这对于PowerShell Core非常有效,即它是一个跨平台的解决方案。 - Robb Vandaveer
    1
    我得到了以下错误信息:error: 分支 'bugfix/foobar' 没有完全合并。 如果您确定要删除它,请运行 'git branch -D bugfix/foobar'。',所以我在结尾处使用了大写字母 D {git branch -D $_},这对我起作用了。 - Kraego
    显示剩余3条评论

    69

    可以配置Git在获取时自动删除已删除远程分支的引用:

    git config --global fetch.prune true
    

    在调用git fetchgit pull之后,对已删除的远程分支的引用会被自动移除。


    19
    这不会移除本地分支,只是移除对它们的引用,对吗? - Clint Eastwood
    @ClintEastwood 它只删除对远程分支的引用。您可以使用git branch -r列出对远程分支的引用。 - wedesoft

    59

    正如@tzacks所指出的...有一个方便的npm包可用于此。只需执行以下操作:

    npx git-removed-branches --prune
    

    (我的声望不够,否则我会留下评论的)


    3
    华丽,毫无麻烦。很高兴这是一个完整的答案! - Dan Rayson
    4
    这应该放在顶部。在Windows中也适用。 - tomtastico
    2
    如果不需要使用npx,这个程序应该会很容易。 - Ashish Padakannaya

    52

    它将列出本地分支,其远程跟踪分支从远程中已被删除

    $ git remote prune origin --dry-run
    

    如果你想从本地删除那些未被跟踪的本地分支引用

    $ git remote prune origin
    

    27
    这并不回答问题,这是提问者已经知道的内容。 - Ken Williams
    6
    我同意这个观点,但是当你搜索“如何修剪本地跟踪分支,而这些分支在远程上不存在了”时,这个链接是排在第一位的,并且这个答案与标题相符(尽管如果有人阅读了问题的完整描述就不一定相符),这也是得到赞成票的原因。 - 027
    这不会删除本地分支。运行后仍然存在。 - Xin
    1
    @Xin 尝试不带 --dry-run 参数运行该命令,这样它将不会实际执行命令,而是展示它将会改变什么。 - Torsten Ojaperv
    这正是我所需要的。我有一个旧分支在本地显示为远程分支,但在服务器上并不存在。 - EmpathicSage

    24
    如果使用 Windows 和 Powershell,您可以使用以下命令删除所有已合并到当前检出分支的本地分支:
    git branch --merged | ? {$_[0] -ne '*'} | % {$_.trim()} | % {git branch -d $_}
    
    列出当前分支以及已合并到当前分支的分支列表,过滤掉当前分支,清除每个剩余分支名中的前导或尾随空格,并删除已经合并的本地分支。强烈建议先单独运行git branch --merged命令,以确保它只会删除您期望删除的内容。 (本段内容来源:http://railsware.com/blog/2014/08/11/git-housekeeping-tutorial-clean-up-outdated-branches-in-local-and-remote-repositories/.)

    这将删除所有已合并的分支,而不仅仅是在远程标记为已删除的分支。如果您有已合并但希望保留的环境或发布分支(如uat prod等),则可能不希望这样做。 - Shanerk

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接