删除不再位于远程的跟踪分支

有一种简单的方法可以删除所有不再具有远程等效项的跟踪分支吗?

例:

分支机构(本地和远程)

  • 起源 / 主人
  • 起源 / 错误修复
  • 原点 / 错误修复 - b
  • 原点 / 错误修复 - C

在本地,我只有一个 master 分支。现在,我需要处理bug-fix-a ,因此我将其检出,对其进行处理,然后将更改推送到远程计算机。接下来,我对bug-fix-b 进行同样的操作

分支机构(本地和远程)

  • 错误修复
  • 错误修复 - b
  • 起源 / 主人
  • 起源 / 错误修复
  • 原点 / 错误修复 - b
  • 原点 / 错误修复 - C

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

因此,当前状态为:

分支机构(本地和远程)

  • 错误修复
  • 错误修复 - b
  • 起源 / 主人
  • 原点 / 错误修复 - C

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

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

答案

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

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

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

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

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

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

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 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

这些答案大多数都没有真正回答原始问题。我做了很多挖掘工作, 是我找到的最干净的解决方案。这是该答案的更为详尽的版本:

  1. 签出您的默认分支。通常是git checkout master
  2. 运行git fetch -p && git branch -vv | awk '/: gone]/{print $1}' | xargs git branch -d

说明:

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

笔记:

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

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

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

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

进一步阅读:


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

  • git fetch --prune (或git fetch -p ,这是一个别名,或git prune remote origin ,它在不获取的情况下执行相同的操作,并且可能不是大多数时候想要的)。
  • 请注意报告为已删除的所有远程分支。或者,要稍后找到它们,可以使用git branch -v (任何孤立的跟踪分支都将标记为 “[gone]”)。
  • 每个孤立跟踪分支上的git branch -d [branch_name]

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

如果您想编写一个解决方案的脚本,那么for-each-ref是您的起点,就像Mark Longair在这里的回答以及对另一个问题的回答一样 ,但是如果不编写 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仍然包含孤立的跟踪信息,所以它也具有识别以前已完全合并的跟踪分支的信息。 (毕竟,它可以为提供使您可以自己进行操作的信息。)

git branch --merged | grep -v "\*" | xargs -n 1 git branch -d
git branch --merged | grep -v "\*" | grep -v "YOUR_BRANCH_TO_KEEP" | xargs -n 1 git branch -d
git branch --merged | grep -v "\*" | grep -v "master" | grep -v "develop" | grep -v "staging" | xargs -n 1 git branch -d
alias gbpurge='git branch --merged | grep -v "\*" | grep -v "master" | grep -v "develop" | grep -v "staging" | xargs -n 1 git branch -d'
. ~/.bashrc
. ~/.zshrc

Windows 解决方案

对于 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切换到 master 分支

git remote update origin --prune修剪远程分支

git branch -vv获取所有分支的详细输出( git reference

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

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

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

删除所有已合并到 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 checkout master 分支

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

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

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

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