ChatGPT解决这个技术问题 Extra ChatGPT

不再远程删除跟踪分支

有没有一种简单的方法来删除远程等效不再存在的所有跟踪分支?

例子:

分支(本地和远程)

掌握

原产地/主人

起源/错误修复-a

起源/错误修复-b

起源/错误修复-c

在本地,我只有一个 master 分支。现在我需要处理 bug-fix-a,所以我检查它,处理它,并将更改推送到远程。接下来我对 bug-fix-b 做同样的事情。

分支(本地和远程)

掌握

错误修复-a

错误修复-b

原产地/主人

起源/错误修复-a

起源/错误修复-b

起源/错误修复-c

现在我有本地分支master,bug-fix-a,bug-fix-b。 Master 分支维护者会将我的更改合并到 master 并删除他已经合并的所有分支。

所以现在的状态是:

分支(本地和远程)

掌握

错误修复-a

错误修复-b

原产地/主人

起源/错误修复-c

现在我想调用一些命令来删除分支(在本例中为 bug-fix-a、bug-fix-b),这些分支不再在远程存储库中表示。

它类似于现有的命令 git remote prune origin,但更像 git local prune origin

措辞出色的问题,带有一个非常清晰的例子。很好!
为什么大多数答案回答:“删除已合并的分支”,而问题专门针对“不再远程的分支”。这是一个很大的区别。

S
SomeGuyOnAComputer

git remote prune origin 修剪不在远程的跟踪分支。

git branch --merged 列出已合并到当前分支的分支。

xargs git branch -d 删除标准输入中列出的分支。

小心删除 git branch --merged 列出的分支。该列表可能包括 master 或您不想删除的其他分支。

为了让自己有机会在删除分支之前编辑列表,您可以在一行中执行以下操作:

git branch --merged >/tmp/merged-branches && \
  vi /tmp/merged-branches && xargs git branch -d </tmp/merged-branches

合并分支的第一行是我系统上的 * master。以下命令对我有用:git branch -d $(git branch --merged |tail -n +2)
如果我在 develop,那么 git branch --merged 包括 master!您可能(绝对!)不想删除它。另外我认为应该是git branch -d,其中小写-d 表示“安全删除”,例如只有在合并时才删除。
似乎提供了改进的解决方案 there
删除合并很有用,但与“删除不在远程上的分支”不同。
只需使用 grep 排除 master:git branch --merged | grep -v "master" >/tmp/merged-branches && vi /tmp/merged-branches && xargs git branch -d </tmp/merged-branches
j
jason.rickman

命令后

git fetch -p

运行时删除远程引用

git branch -vv

它将显示“已离开”作为远程状态。例如,

$ git branch -vv
  master                 b900de9 [origin/master: behind 4] Fixed bug
  release/v3.8           fdd2f4e [origin/release/v3.8: behind 2] Fixed bug
  release/v3.9           0d680d0 [origin/release/v3.9: behind 2] Updated comments
  bug/1234               57379e4 [origin/bug/1234: gone] Fixed bug

因此,您可以编写一个简单的脚本来删除已远程访问的本地分支:

git fetch -p && for branch in $(git branch -vv | grep ': gone]' | awk '{print $1}'); do git branch -D $branch; done

请注意,上面使用“瓷器”命令git branch来获取上游状态。

获得此状态的另一种方法是使用带有插值变量 %(upstream:track) 的“管道”命令 git for-each-ref,就像上面一样,它将是 [gone]

这种方法更安全一些,因为不存在意外匹配部分提交消息的风险。

git fetch -p && for branch in $(git for-each-ref --format '%(refname) %(upstream:track)' refs/heads | awk '$2 == "[gone]" {sub("refs/heads/", "", $1); print $1}'); do git branch -D $branch; done

@KrzysztofWende - 不在 Solaris 和一些 BSD 和一些 OS X 上 :)
看起来这也将删除最后提交消息中“消失”的任何分支。
@dlsso 如果最后一条提交消息包含字符串“:gone]”,那么它也将被删除。您可以通过额外的 awk/gawk 去除提交消息,以牺牲简单性为代价使其更健壮。 git branch -vv | gawk '{print $1,$4}' | grep 'gone]' | gawk '{print $1}'
在回复我之前的评论(问题)时,当前分支将 * 作为第一个字段。如果它恰好也在“已消失”分支的列表中,则 $1 将被分配 * 并将被解释为带有 awk 吐出文件和文件夹名称的文件规范。我消除了 grep 表达式并让 awk 完成所有过滤:awk '/: gone]/{if ($1!="*") print $1}'。这现在按预期工作。
@ahmedbhs 因为命令使用单引号 ' 你需要使用双引号 " 来包围整个命令。此外,作为 shell 命令的 git 别名(如这个命令)需要 ! 在开头。这对我有用:test = "!git fetch -p && for branch in `git branch -vv | grep ': gone]' | awk '{print $1}'`; do git branch -D $branch; done"
d
dlsso

这些答案中的大多数实际上并未回答原始问题。我做了一堆挖掘工作,this 是我找到的最干净的解决方案。这是该答案的稍微更彻底的版本:

查看您的默认分支。通常 git checkout master 运行 git fetch -p && git branch -vv | awk '/: 消失了]/{print $1}' | xargs git 分支 -d

解释:

通过修剪您的跟踪分支然后删除显示它们在 git branch -vv 中“消失”的本地分支来工作。

笔记:

如果您的语言设置为英语以外的其他语言,您需要将 gone 更改为适当的单词。仅本地的分支不会被触及。已在远程删除但未合并的分支将显示通知但不会在本地删除。如果您还想删除它们,请将 -d 更改为 -D


应该在 git branch 之前添加 LANG=en_US 以强制英语: git fetch --prune && LANG=en_US git branch -vv | awk '/: 消失了]/{print $1}' | xargs git 分支 -d
我会在命令的开头添加 git checkout master && ...
当您在一个应该被删除的分支上时,这很危险——在这种情况下,第一列是“*”,然后将其传递给 xargs。为了改善这一点,在将输出传递给 awk 之前添加剥离 '*' 字符: sed -e 's/^*//'
@dlsso 这些说明适用于大多数人,但不适用于所有人(请参阅上面的评论)。说人们应该从意外删除的分支中学习(他们可能不容易知道如何恢复)是光顾,当您可以使说明更安全时。你,你自己在上面写道“那个确切的建议是不安全的”。我仍然认为安全比总是工作更重要。人们最好从“不工作”中学习,而不是从已删除的分支中学习。
小心!有一种极端情况会导致删除所有本地分支:如果您当前位于远程删除的分支上,则 git branch -vv 的输出将以星号开头,最终将导致执行 git branch -d *。这是一个修补版本,它将忽略带星号的行:git branch -vv | grep ': gone]'| grep -v "\*" | awk '{ print $1; }' | xargs -r git branch -d
A
Andrew Spencer

我通常不会回答一个已经有 16 个答案的问题,但其他所有答案都是错误的,而正确答案就是这么简单。问题是:“有没有一种简单的方法可以删除远程等效不再存在的所有跟踪分支?”

如果“简单”意味着一次性删除它们,不脆弱,不危险,并且不依赖并非所有读者都会拥有的工具,那么正确的答案是:不。

有些答案很简单,但他们不做被问到的事情。其他人按照要求做,但并不简单:都依赖于通过文本操作命令或脚本语言解析 Git 输出,这可能并非每个系统都存在。最重要的是,大多数建议都使用瓷器命令,其输出并非旨在由脚本解析(“瓷器”是指用于人工操作的命令;脚本应使用较低级别的“管道”命令)。

进一步阅读:

为什么不应该在脚本中解析 git 分支输出。

跟踪分支以及 git remote prune、git prune、git fetch --prune 之间的区别

如果您想安全地执行此操作,对于问题中的用例(垃圾收集跟踪已在服务器上删除但仍作为本地分支存在的分支)并且仅使用高级 Git 命令,您必须

git fetch --prune (或 git fetch -p,它是一个别名,或 git prune 远程源,它在不获取的情况下执行相同的操作,并且可能不是您大部分时间想要的)。

请注意报告为已删除的任何远程分支。或者,为了稍后找到它们, git branch -v (任何孤立的跟踪分支都将被标记为“[gone]”)。

每个孤立跟踪分支上的 git branch -d [branch_name]

(这是其他一些答案所建议的)。

如果您想编写解决方案的脚本,那么 for-each-ref 是您的起点,如此处的 Mark Longair's answerthis answer to another question,但如果不编写 shell 脚本循环或使用 xargs 或某物。

背景说明

要了解发生了什么,您需要了解,在跟踪分支的情况下,您拥有的不是一个分支,而是三个。 (回想一下,“分支”只是指向提交的指针。)

给定一个跟踪分支 feature/X,远程存储库(服务器)将拥有此分支并将其称为 feature/X。您的本地存储库有一个分支 remotes/origin/feature/X,这意味着“这是远程告诉我它的 feature/X 分支是的,上次我们谈过”,最后,本地存储库有一个分支 feature/X,它指向您最新的提交,并配置为“跟踪”remotes/origin/feature/X,这意味着您可以拉和推以保持它们对齐。

在某个时候,有人删除了遥控器上的 feature/X。从那一刻起,您只剩下本地的 feature/X(您可能不再需要它,因为功能 X 的工作可能已经完成),而您的 remotes/origin/feature/X 肯定没用,因为它的唯一目的是记住服务器分支的状态。

Git 会让你自动清理多余的 remotes/origin/feature/X——这就是 git fetch --prune 所做的——但由于某种原因,它不会让你自动删除你自己的 feature/X...即使你的 feature/X仍然包含孤立的跟踪信息,因此它具有识别已完全合并的前跟踪分支的信息。 (毕竟,它可以为提供让您自己手动操作的信息。)


这是一个更安全的答案。此外,与所选答案不同,如果您使用“Squash and Merge”工作流程,它将起作用。
这实际上只回答了“如何找到消失的分支”问题的简单部分(以及使用 jason.rickman 在 2015 年发布的相同命令),但随后告诉您手动删除所有分支,这正是 OP不想做。
@Voo 这就是答案的重点:不是告诉你怎么做(这只是一个奖励),而是告诉你答案是没有简单、简单的方法来做到这一点。这是该问题的正确答案。
@user2864740 一些读者可能认为编写一个小的 bash 脚本属于他们对“简单”的定义,这是一个完全可以辩护的立场,但我在第 2 段中给出了我自己对“简单”的解释,其余的答案是一致的用它。为了捍卫我公认的限制性解释,并非所有 Git 用户都有 xargs 或 bash,他们可能不是在这里寻找微编码挑战,而是他们可以安全地应用的快速答案,而不会进一步分散自己的注意力他们真正的目标。
我认为使用 Git 来回答“有没有简单的方法……”这个问题几乎总是否定的。
c
chris31389

视窗解决方案

对于 Microsoft 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().Trim().Split(" ")[0]} 获取分支名称

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


谢谢你,虽然我必须在 .toString() 之后添加一个 .Trim() 才能删除分支名称前的两个空格。
感谢这个命令。我必须将 git branch -d 更改为 git branch -D 否则我会收到分支未完全合并的错误。
@markieo 您可能已经知道这一点,但对其他人来说 - git branch -D 具有破坏性,并且会删除您尚未推送的本地工作。 -d 总是安全的,请小心使用 -D
C
Community

我在这里找到了答案:How can I delete all git branches which have been merged?

git branch --merged | grep -v "\*" | xargs -n 1 git branch -d

确保我们保持主人

您可以通过在第一个分支之后添加另一个 grep 来确保不会删除 master 或任何其他分支。在这种情况下,你会去:

git branch --merged | grep -v "\*" | grep -v "YOUR_BRANCH_TO_KEEP" | xargs -n 1 git branch -d

因此,如果我们想保留 masterdevelopstaging,我们会:

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

将此设为别名

由于它有点长,您可能希望为您的 .zshrc.bashrc 添加一个别名。我的叫 gbpurge(代表 git branches purge):

alias gbpurge='git branch --merged | grep -v "\*" | grep -v "master" | grep -v "develop" | grep -v "staging" | xargs -n 1 git branch -d'

然后重新加载您的 .bashrc.zshrc

. ~/.bashrc

或者

. ~/.zshrc

有用,但与“删除不在远程的分支”不同
很好的答案@karlingen,我在我的所有开发环境中都将其永久保存为 gbpurge
S
Sven Dhaens

你可以这样做:

git branch -vv | grep 'origin/.*: gone]' | awk '{print $1}' | xargs git branch -d

PS:正如Sam H.所指出的

首先执行这个:

git remote prune origin

您不必先运行 git remote prune origin 吗?
如果你想强制删除,还要传递 xargs git branch -D(大写 D)
P
Patrick Quirk

大多数其他解决方案中“gone”的模式匹配对我来说有点可怕。为了更安全,这使用 --format 标志来拉出每个分支的 upstream tracking status

我需要一个 Windows 友好的版本,所以这会删除所有使用 Powershell 列为“已消失”的分支:

git branch --list --format "%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)" | 
    ? { $_ -ne "" } | 
    % { git branch -D $_ }

第一行列出了上游分支“已消失”的本地分支的名称。下一行删除空行(这是未“消失”的分支的输出),然后将分支名称传递给命令以删除分支。


--format 选项似乎相当新;我需要将 git 从 2.10.something 升级到 2.16.3 才能获得它。这是我对 Linux 系统的修改:git branch --list --format "%(if:equals=[gone])%(upstream:track)%(then)%(refname)%(end)" | sed 's,^refs/heads/,,' | grep . | xargs git branch -D
这是迄今为止最好的解决方案。一个建议是使用 refname:short。然后您可以删除行 % { $_ -replace '^refs/heads/', '' }
这是 Windows 的一个很好的解决方案。我这样使用它是因为它更具可读性 git branch --list --format "%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)" | where { $_ -ne "" } | foreach { git branch -d $_ } 使用 -d 而不是 -D 也可能是个好主意。对于不再处于远程状态的分支,不需要强制删除。
虽然对我们中的一些人来说显而易见,但可能值得一提的是,您应该首先运行“git remote update origin --prune”。
J
Jeff Puckett

TL;博士:

删除所有不在远程的本地分支

git fetch -p && git branch -vv | grep ': gone]' | awk '{print $1}' | xargs git branch -D

删除所有不在远程 AND 上的本地分支,它们已完全合并并且未如之前许多答案中所说的那样使用。

git fetch -p && git branch --merged | grep -v '*' | grep -v 'master' | xargs git branch -d

解释

git fetch -p 将修剪远程不再存在的所有分支

git branch -vv 将打印本地分支,修剪后的分支将被标记为离开

grep ':gone]' 只选择消失的分支

awk '{print $1}' 过滤输出以仅显示分支的名称

xargs git branch -D 将遍历所有行(分支)并强制删除此分支

为什么是 git branch -D 而不是 git branch -d,否则您将拥有未完全合并的分支。

error: The branch 'xxx' is not fully merged.

你想说远程而不是主人吗?
它对我有用
c
cs01

删除所有已合并到 master 的分支,但不要尝试删除 master 本身:

git checkout master && git pull origin master && git fetch -p && git branch -d $(git branch --merged | grep master -v)

或添加别名:

alias gitcleanlocal="git checkout master && git pull origin master && git fetch -p && git branch -d $(git branch --merged | grep master -v)"

解释:

git checkout master 结帐主分支

git pull origin master 确保本地分支已合并所有远程更改

git fetch -p 删除对已删除的远程分支的引用

git branch -d $(git branch master --merged | grep master -v) 删除所有已合并到 master 的分支,但不要尝试删除 master 本身


请注意,这非常有用,但它也会删除那些从未被推送到远程的分支。仅列出差异然后将您真正要删除的内容复制到 git branch -D 命令中更安全
澄清一下,Zefiryn 指的是使用 -D 选项,它不是单行的一部分。
或者使用小写 git branch -d,它应该发出关于未推送分支的警告。
n
noraj
git fetch -p

这将修剪遥控器上不再存在的任何分支。


这会删除远程引用,但不会删除本地分支本身。虽然是一个有用的命令,但我认为这不能回答 OP 的问题。
什么?这为我删除了本地分支。
@AlexHall 远程仓库有一个分支 X;你git checkout X;现在您的存储库有一个(本地)跟踪分支 X 和一个远程分支 origin/X;远程存储库删除 X;你git fetch-p;在您的本地存储库中,不仅 origin/X 而且 X 已被删除。这就是你说的吗?
H
Himura

另一个答案,因为没有一个解决方案适合我对优雅和跨平台的需求:

删除不在远程的本地分支的命令:

for b in $(git for-each-ref --format='%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)' refs/heads); do git branch -d $b; done

要将其与 gitconfig 集成以便可以使用 git branch-prune 运行:

重击

git config --global alias.branch-prune '!git fetch -p && for b in $(git for-each-ref --format='\''%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)'\'' refs/heads); do git branch -d $b; done'

电源外壳

git config --global alias.branch-prune '!git fetch -p && for b in $(git for-each-ref --format=''%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)'' refs/heads); do git branch -d $b; done'

(在寻找 PowerShell 和 bash 的通用命令时需要帮助)

为什么这个答案是最好的?

提供一个完整的解决方案:在你的 git 中添加一个 git branch-prune 命令

在 Windows PowerShell 中运行良好

核心思想是@jason.rickman 使用 git for-each-ref 的防弹方法

解析和过滤是用 --filter 完成的,所以不需要外部依赖

解释:

为您的 ~\.gitconfig 添加一个新别名。执行此操作后,您可以简单地执行 git branch-prune

在此别名中:使用 --prune 标志获取分支,该标志“修剪远程跟踪分支不再在远程”使用 git for-each-ref 和 --filter,获取分支列表 [gone](没有remote) 循环遍历此列表并安全删除分支

使用 --prune 标志获取分支,该标志“修剪远程跟踪分支不再远程”

使用 git for-each-ref 和 --filter,获取分支列表 [gone](无远程)

循环遍历此列表并安全删除分支


感谢您,@jerry-wu 改进了这个无穷大的解决方案。
@jerry-wu 并且您上次编辑的 git config 命令在 PowerShell 中不起作用((
这是否也会删除尚未推送到远程的本地分支? (又名进行中的工作)
最简洁的答案是不。如果未合并分支,则此处使用的 git branch -d branch-name 命令不会将其删除。它将发送一个分支未合并的通知,并显示删除它的命令(即git branch -D branch-name
对我来说,这确实会报告分支未合并的错误,即使分支确实已完全合并并在合并后从远程删除。错误:分支 'feature/...' 未完全合并。 - 有什么建议么?
P
Pranav Kasetti

虽然上面的答案涵盖了如何手动修剪分支,但这个答案增加了自动化来解决这个问题。 git 现在有一个新设置,可以为每个提取操作修剪不再位于远程的陈旧分支。这很棒,因为我们不再需要在每次删除分支时手动调用 remote prunegit pull 也调用 git fetch)。

为每次提取启用修剪行为

要在全局配置中启用此功能:

git config --global fetch.prune true

使事情自动发生意味着您可以忘记在新机器上添加此设置。它只是工作。

为特定遥控器上的每次提取启用修剪行为

git config --global remote.<name>.prune true

本地自动修剪

我们也可以在没有 --global 标志的情况下应用相同的命令进行本地修剪。

.gitconfig

上述命令适用于全局和本地 .gitconfig,如下所示:

...
[fetch]
    prune = true

我可以建议将其添加到 ansible 配置或您的 dotfiles 存储库 (.gitconfig) 中,以便将来自动进行设置。

配置设置在每次提取时调用以下命令:

git remote prune <remote name>

概括

要在您的正常工作流程中修剪引用而不需要记住运行它,请在配置中全局设置 fetch.prune 或每个远程设置 remote.<name>.prune。请参阅git-config


似乎对我不起作用。执行全局设置(它也在我的 .gitconfig 中),在 github 上合并分支,然后是 git fetch + git pull。该分支仍然存在于我的本地。
b
bxm

堆的另一个答案,从 Patrick's answer 大量提取(我喜欢它,因为它似乎消除了 gone] 将在 git branch 输出中匹配的任何歧义),但添加了 *nix 弯曲。

最简单的形式:

git branch --list --format \
  "%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)" \
  | xargs git branch -D

我已将此包裹在路径上的 git-gone 脚本中:

#!/usr/bin/env bash

action() {
  ${DELETE} && xargs git branch -D || cat
}

get_gone() {
  git branch --list --format \
    "%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)"
}

main() {
  DELETE=false
  while [ $# -gt 0 ] ; do
    case "${1}" in
      (-[dD] | --delete) DELETE=true ;;
    esac
    shift
  done
  get_gone | action
}

main "${@}"

注意 - --format 选项似乎相当新;我需要将 git 从 2.10.something 升级到 2.16.3 才能获得它。

编辑:调整以包含来自 Benjamin W. 的关于 refname:short 的建议

NB2 - 我只在 bash 中测试过,因此是 hashbang,但可能可移植到 sh


您不能在第一行使用 %(refname:short) 跳过 sed 部分吗?
似乎对我有用,我现在把它作为一个整洁的 Git 别名——这里所有的最干净的解决方案!
2.13 引入了--format。跳过 sed 部分的另一种方法是使用 git update-ref -d。请注意,这可能有点不安全,在这里使用 git for-each-ref 更安全(给定 --shell)。
很好的答案,当我与 --format 自己做这件事时,它帮助我回答了我自己的问题。只有一个问题:为什么是 #!bash?对我来说,这里的所有东西看起来都像便携式 sh
那只是我的正常样板,并没有在其他地方测试过。
p
pabloa98

这将删除所有合并的本地分支,除了本地主引用和当前正在使用的分支:

git branch --merged | grep -v "*" | grep -v "master" | xargs git branch -d

这将删除所有已经从“origin”引用的远程存储库中删除的分支,但仍然在“remotes/origin”中本地可用。

git remote prune origin

git branch -vv | grep 'gone]' | grep -v "\*" | awk '{print $1}' | xargs -r git branch -d 解释:我更喜欢将 git branch --merged 替换为 git branch -vv 以显示状态(已消失),因为之前的 git branch --merged 也可以显示主
F
Francois

可能对一些有用的,简单的一行来清除除 master 和 development 之外的所有本地分支

git branch | grep -v "master" | grep -v "develop" | xargs git branch -D

真棒答案!我喜欢在承诺添加命令的删除部分之前如何轻松地使用 'git branch | grep -v "master" | grep -v "develop" 类型的东西。 👏😊
但这并不能回答上面的问题。即使远程仍然存在,这也会删除分支。
T
Toby Speight

我认为没有内置命令可以执行此操作,但执行以下操作是安全的:

git checkout master
git branch -d bug-fix-a

当您使用 -d 时,git 将拒绝删除该分支,除非它完全合并到 HEAD 或其上游远程跟踪分支中。因此,您始终可以遍历 git for-each-ref 的输出并尝试删除每个分支。这种方法的问题在于,我怀疑您可能不希望仅仅因为 origin/bug-fix-d 包含其历史记录而删除 bug-fix-d。相反,您可以创建类似于以下内容的脚本:

#!/bin/sh

git checkout master &&
for r in $(git for-each-ref refs/heads --format='%(refname:short)')
do
  if [ x$(git merge-base master "$r") = x$(git rev-parse --verify "$r") ]
  then
    if [ "$r" != "master" ]
    then
      git branch -d "$r"
    fi
  fi
done

警告:我没有测试过这个脚本 - 请谨慎使用...


我冒昧地编辑了脚本。仍然不会给出任何保证,但是,它现在运行并且似乎可以工作。
K
Karl Wilbur

这些都不适合我。我想要一些东西来清除所有跟踪远程分支的本地分支,在 origin,远程分支已被删除 (gone)。我不想删除从未设置为跟踪远程分支的本地分支(即:我的本地开发分支)。我还想要一个简单的单行程序,它只使用 git 或其他简单的 CLI 工具,而不是编写自定义脚本。我最终使用了一些 grepawk 来制作这个简单的命令。

这最终在我的 ~/.gitconfig 中结束:

[alias]
  prune-branches = !git remote prune origin && git branch -vv | grep ': gone]' | awk '{print $1}' | xargs -r git branch -D

这是一个 git config --global ... 命令,可轻松将其添加为 git prune-branches

git config --global alias.prune-branches '!git remote prune origin && git branch -vv | grep '"'"': gone]'"'"' | awk '"'"'{print $1}'"'"' | xargs -r git branch -d'

注意:在 config 命令中,我使用 -d 选项来 git branch 而不是 -D,就像我在实际配置中所做的那样。我使用 -D 是因为我不想听到 Git 抱怨未合并的分支。您可能也需要此功能。如果是这样,只需在该配置命令的末尾使用 -D 而不是 -d


我喜欢 git 别名方法。快速提问:为什么对 : gone] 执行 git branch -vv 和 grep 而对 [gone] 不执行 git branch -v 和 grep?
@lalibi,好问题。我不记得了。我怀疑只有一个 v 没有显示某些内容。如果 git branch -v | grep '[gone]' 适合你,那就去吧。它确实看起来更干净一些。
d
derekbaker783

基于 Powershell 的解决方案,我发现它比这里的许多实现更清晰。

# prune deleted remoted branches
git fetch -p

# get all branches and their corresponding remote status
# deleted remotes will be marked [gone]
git branch -v |
  #find ones marked [gone], capture branchName
  select-string -Pattern '^  (?<branchName>\S+)\s+\w+ \[gone\]' | 
  foreach-object{ 
     #delete the captured branchname.
     git branch -D $_.Matches[0].Groups['branchName']
  }

t
thiruclassic
grep gone <(git branch -v) | cut -d ' ' -f 3 | xargs git branch -d

上述命令可用于获取远程合并和删除的分支,并删除远程不再可用的本地分支


迄今为止最好的解决方案,尽管我将其更改为 grep gone <(git branch -v) | cut -d ' ' -f 3 | xargs git branch -D 以强制删除所有
如果您的任何分支名称碰巧在其中的任何位置包含子字符串 gone(例如 usingonefunction),就会很危险。
M
Michael Wyraz

因为有些答案并不能防止意外删除

git fetch -p && LANG=c git branch -vv | awk '/: gone]/&&!/^*/{print $1}' | xargs git branch -d

过滤掉第一列中有 * 的分支很重要。


对我来说最好的解决方案。我添加了 LANG=c,以便它也适用于非英语环境。
为什么要用 -vv 让它变得如此复杂并过滤掉第一列。如果没有 -vv,您只能从一列开始。
因为我正在寻找 : gone] – 但你是对的:一个 -v 就足够了。
M
Muthu Ganapathy Nathan

根据上面的信息,这对我有用:

git br -d `git br -vv | grep ': gone] ' | awk '{print $1}' | xargs`

它会删除远程上带有 ': gone] ' 的所有本地分支。


看起来这也将删除最后提交消息中“消失”的任何分支。
它还将删除名称中任何位置包含 gone 的任何分支。
"git branch -D git branch -vv | grep ':gone] ' | awk '{print $1}' | xargs`" 这对我有用。
A
Asaf

你可以使用这个:

git fetch --prune

然后

git branch -vv | egrep -v "([origin/[a-zA-Z0-9/_-]+])" | awk "{print $1}" | xargs git branch -D

它删除所有未链接到远程的本地分支


g
gsnedders

从这里的 number of other answers 大量提取,我最终得到了以下内容(我相信仅限 git 2.13 及更高版本),它应该适用于任何类 UNIX 外壳:

git for-each-ref --shell --format='ref=%(if:equals=[gone])%(upstream:track)%(then)%(refname)%(end)' refs/heads | while read entry; do eval "$entry"; [ ! -z "$ref" ] && git update-ref -d "$ref" && echo "deleted $ref"; done

这尤其是使用 for-each-ref 而不是 branch(因为 branch 是一个“瓷器”命令,专为人类可读的输出而不是机器处理而设计)并使用其 --shell 参数来获得正确转义的输出(这允许我们不用担心参考名称中的任何字符)。


它对我有用,但如果你能解释命令中的其他步骤在做什么,那也很好。例如,我不知道 [ ! -z "$ref" ] 是什么意思。我认为多班轮已经有所帮助。但仍然感谢您的意见!
E
Eugene Yokota

基于看起来类似于 jason.rickman's solutionGit Tip: Deleting Old Local Branches,我为此使用 Bash 实现了一个名为 git gone 的自定义命令:

$ git gone
usage: git gone [-pndD] [<branch>=origin]
OPTIONS
  -p  prune remote branch
  -n  dry run: list the gone branches
  -d  delete the gone branches
  -D  delete the gone branches forcefully

EXAMPLES
git gone -pn    prune and dry run
git gone -d     delete the gone branches

git gone -pn 结合了修剪和列出“已消失”的分支:

$ git gone -pn
  bport/fix-server-broadcast         b472d5d2b [origin/bport/fix-server-broadcast: gone] Bump modules
  fport/rangepos                     45c857d15 [origin/fport/rangepos: gone] Bump modules

然后您可以使用 git gone -dgit gone -D 扣动扳机。

笔记

我使用的正则表达式是“$BRANCH/.*:gone]”,其中 $BRANCH 通常是原点。如果您的 Git 输出本地化为法语等,这可能不起作用。

Sebastian Wiesner 还为 Windows 用户将其移植到 Rust。那个也叫 git gone 。


这可能应该是公认的答案 - git gone 看起来像 git branch -vv | grep 'origin/.*: gone]' | awk '{print $1}' | xargs git branch -d 的别名,它解决了 OP 的问题。
L
Laobe

可能这个命令就是你想要的。

运行后:

git remote prune origin

然后运行:

diff <(git branch | sed -e 's/*/ /g') <(git branch -r | sed -e 's/origin\///g') | grep '^<'

这将显示不在 (git branch -r) 但在 (git branch) 中的所有分支

这个方法有个问题,在本地也会显示之前没有推送过的分支


它在终端上工作,但我怎样才能把它放在 git 别名中?我正在使用 show_deleted = "diff <(git branch | sed -e 's/*/ /g') <(git branch -r | sed -e 's/origin\///g') | grep '^<'" 但它会抛出错误。
e
espaciomore

我喜欢使用管道,因为它使命令更易于阅读。

如果您想删除除 master 之外的所有分支,这是我的解决方案。

git branch | grep -v master | xargs -n 1 git branch -D

要删除与您的条件匹配的其他分支,请修改第一个和第二个块。

git branch --merged | grep feature_name | xargs -n 1 git branch -D

可以稍微简化一下:git branch --merged | grep -vE 'main|master|\\*' | xargs -n 1 git branch -D"
T
Tom Pietrosanti

对于 Windows 或其他不想/不能编写命令行脚本或不想打扰 PowerShell 的人来说,这是一个更简单的解决方案。

将分支列表转储到文件 git branch > branches.txt
(或 git branch --merged > branches.txt,如果您是腰带和吊带类型;git branch -d 将防止删除未合并的分支)

在编辑器中打开该文件并合并所有行(我使用了 sublime 文本,因此突出显示所有行并按 ctrl+j

在您的分支列表前添加 git branch -d

全选、复制并粘贴(在 windows cmd 窗口中单击鼠标右键)到命令行。


k
koppor

真正的挑战是维护者何时压缩提交。然后,使用 git 内置功能(如 --merged)的解决方案无济于事。

工具 git-delete-merged-branches 可以方便地删除分支。我特别喜欢交互模式。

安装(需要 python3):

pip install git-delete-merged-branches

然后执行

git-delete-merged-branches --effort=3

--effort=3 对于删除压扁的分支很重要。

备择方案

@teppeis/git-delete-squashed:安装 node.js 后,执行 npx @teppeis/git-delete-squashed。支持主分支。

git-delete-squashed:未维护:缺少主分支的功能。 @teppeis/git-delete-squashed 基于此。


B
BrunoLM

我想出了这个 bash 脚本。它始终保留分支 developqamaster

git-clear() {
  git pull -a > /dev/null

  local branches=$(git branch --merged | grep -v 'develop' | grep -v 'master' | grep -v 'qa' | sed 's/^\s*//')
  branches=(${branches//;/ })

  if [ -z $branches ]; then
    echo 'No branches to delete...'
    return;
  fi

  echo $branches

  echo 'Do you want to delete these merged branches? (y/n)'
  read yn
  case $yn in
      [^Yy]* ) return;;
  esac

  echo 'Deleting...'

  git remote prune origin
  echo $branches | xargs git branch -d
  git branch -vv
}