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


1168

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

例:

分支机构(本地和远程)

  • 起源/主人
  • 起源/错误修复
  • 原点/错误修复-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

Answers:


1277

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

17
合并分支的第一行在* master我的系统上。以下命令为我工作:git branch -d $(git branch --merged |tail -n +2)
Trendfischer 2015年

99
如果我打开,developgit branch --merged包括master!您可能(肯定!)不想删除它。我也认为应该是git branch -d小写的-d意思是“安全删除”,例如只有合并后才删除。
thom_nic 2015年

11
似乎在那里提供了一种改进的解决方案。
谢尔盖·布鲁诺夫

34
删除合并很有用,但与“删除不在远程的分支”不同。
dlsso

11
只需使用grep即可排除主服务器:git branch --merged | grep -v "master" >/tmp/merged-branches && vi /tmp/merged-branches && xargs git branch -d </tmp/merged-branches
geniass

587

命令后

git fetch -p

运行时删除远程引用

git branch -vv

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

$ 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来获取上游状态。

获取此状态的另一种方法是将“ plumbing”命令git for-each-ref与插值变量一起使用%(upstream:track)[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

8
@KrzysztofWende-在Solaris和某些BSD和某些OS X上
不可用

4
看起来这还将删除最后一个提交消息中所有已“消失”的分支。
dlsso

11
@dlsso如果最后的提交消息包含字符串“:done]”,则是的,它也会被删除。您可以通过额外的awk / gawk剥离提交消息来以简化为代价使其更强大。git branch -vv | gawk '{print $1,$4}' | grep 'gone]' | gawk '{print $1}'
jason.rickman

2
在回答我之前的评论(问题)时,当前分支的第一字段为*。如果它也恰好在“去”分支的列表中,则将为$ 1分配*并将其解释为具有awk吐出文件名和文件夹名的filespec。我消除了grep的表达,并AWK的所有过滤的:awk '/: gone]/{if ($1!="*") print $1}'。现在这可以按预期工作。
rhaben

5
@ahmedbhs,因为该命令使用单引号',所以您需要使用双引号“将整个命令括起来。而且,作为shell命令的git别名(像这样)在开始时需要!。对我test = "!git fetch -p && for branch in `git branch -vv | grep ': gone]' | awk '{print $1}'`; do git branch -D $branch; done"
有用

305

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

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

说明:

通过修剪跟踪分支,然后删除表明它们在中已消失的本地分支来工作git branch -vv

笔记:

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


2
对于法国操作系统的消失,必须通过改变来改变
Mohamed EL HABIB

4
应该在git分支之前添加LANG = en_US强制使用英语:git fetch --prune && LANG = en_US git branch -vv | awk'/:消失] / {print $ 1}'| xargs git branch -d
Mohamed EL HABIB

3
我将git checkout master && ...在命令的开头添加。
iarroyo

2
当您在应该删除的分支上时,这很危险-在这种情况下,第一列为'*',然后将其传递给xargs。为了改善这一点,请在将输出传递到awk之前添加'*'字符:sed -e's / ^ * //'
meeee

6
小心!有一个极端的情况会导致删除所有本地分支:如果您当前正在远程删除的分支上,的输出git branch -vv将以星号开头,最终将执行git branch -d *。这是一个补丁版本,将忽略带星号的行:git branch -vv | grep ': gone]'| grep -v "\*" | awk '{ print $1; }' | xargs -r git branch -d
kcm

209

我通常不会回答已经有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,这意味着:“这是遥控器上次告诉我的,它告诉我它的功能/ X分支是”。最后,本地存储库有一个分支feature/X,指向您的最新提交,并配置为“ track” 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仍然包含孤立的跟踪信息,因此它也具有该信息以确定以前已完全合并的跟踪分支。(毕竟,它可以为提供使您可以自己进行操作的信息。)


3
这是一个更安全的答案。此外,如果您使用“挤压并合并”工作流,它将与选定的答案不同,这将起作用。
杰克·莱维特

3
这实际上仅回答了问题的最简单部分“如何找到消失的分支”(以及与jason.rickman在2015年发布的命令相同的命令),然后告诉您手动删除所有分支,这正是OP不想做。
Voo

4
@Voo这就是答案的重点:不是告诉你怎么做(这只是一个奖励),而是告诉你答案是没有简单的方法来做到这一点。这是对提出的问题的正确答案。
安德鲁·斯宾塞

1
“如果您想安全地执行此操作,请使用问题中的用例。”-否定了第一段的大部分要求。“ [Git]可以为您提供使您可以自己进行操作的信息”-我们是程序员,因此,将这些信息作为列表显示(如所示),任务仍然很简单(例如xargs)。还git alias简化了许多情况。
user2864740

2
@ user2864740有些读者可能会认为编写小型bash脚本属于其“简单”的定义,这是完全可以辩驳的立场,但是我在第二段中对“简单”给出了自己的解释,其余答案是一致的用它。为了捍卫我公认的限制性解释,并不是所有的Git用户都拥有xargsbash或bash,他们可能不是在这里寻找微编码挑战,以至于他们可以安全地快速应用答案而不会分散自己的实际目标。
Andrew Spencer

52

我在这里找到了答案: 如何删除所有已合并的git分支?

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

确保我们保持主人

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

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

因此,如果我们想保留masterdevelop并且staging举例来说,我们会去:

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

将此设为别名

由于它有点长,您可能要为.zshrc或添加一个别名.bashrc。我的被​​称为gbpurgegit 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

8
有用,但与“删除不在远程的分支”不同
dlsso

马丽娟答案@karlingen,我有这个永久的所有我开发环境gbpurge
彼得·多兰

50

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

git remote update origin --prune 修剪偏远的分支机构

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

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

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

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


3
为此,尽管我必须添加一个.Trim()after .toString()以便删除分支名称前的两个空格。
马修

2
感谢您的命令。我不得不将更git branch -d改为git branch -D其他,但我收到错误消息,表明分支未完全合并。
markieo

1
@markieo您可能已经知道这一点,但是对于其他任何人- git branch -D具有破坏性,将删除您尚未推送的本地工作。-d始终是安全的,请注意-D
Nate Barbettini

33

在大多数其他解决方案中,“去”的模式匹配对我来说有点吓人。为了安全起见,它使用该--format标志提取每个分支的上游跟踪状态

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

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

第一行列出了上游分支为“ gone”的本地分支的名称。下一行删除空白行(非“行”分支的输出),然后将分支名称传递给命令以删除分支。


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

2
这是迄今为止最好的解决方案。一种建议是使用refname:short。然后您可以删除该行% { $_ -replace '^refs/heads/', '' }
ioudas '18

2
这是Windows的绝佳解决方案。我这样使用它,因为它更易读git branch --list --format "%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)" | where { $_ -ne "" } | foreach { git branch -d $_ }也可以-d代替使用-D。对于不再位于远程的分支,不必强制删除。
Rubanov

31

删除所有已合并到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本身


3
请注意,这非常有帮助,但它也将删除那些从未推送到远程的分支。仅列出差异,然后将您真正要删除的内容复制到git branch -D命令中
-Zefiryn 2014年

只是为了澄清起见,Zefiryn指的是使用-D选项,它不是单行代码的一部分。
cs01

1
或使用小写字母git branch -d,这应该发出有关未推送分支的警告。
acme

16
git fetch -p

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


64
这将删除远程引用,但不会删除本地分支本身。虽然这是一个有用的命令,但我认为这不能回答OP的问题。
thataustin 2014年

什么?这会为我删除本地分支。
亚历克斯·霍尔

1
@AlexHall远程存储库有一个分支X;你git checkout X; 现在您的存储库有一个(本地)跟踪分支X和一个远程分支origin/X;远程库删除X; 你git fetch-p; 在本地存储库中,不仅已删除,origin/X而且X已删除。那是你的意思吗
安德鲁·斯宾塞

16

然而,又有另一个答案,这很大程度上是从Patrick的答案中得出的(我喜欢这个答案,因为它似乎消除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才能得到它。

编辑:调整以包括有关建议refname:short本杰明W.

bashNB2- 我只是在进行了测试,因此进行了hashbang,但可能可以移植到sh


您不能通过在第一行中sed使用来跳过零件%(refname:short)吗?
本杰明·

似乎为我工作,现在我已经把它当作一个整洁的Git别名–这里是所有解决方案中最干净的解决方案!
本杰明W.19年

2.13介绍--format。跳过sed零件的另一种方法是使用git update-ref -d。请注意,这可能有点不安全,git for-each-ref此处使用更加安全(给定--shell)。
gsnedders '19

很好的答案,这在我自己挣扎时帮助我回答了自己的问题--format。只是一个问题:为什么#!bashsh对我而言,这里的一切看起来都很便携。
Toby Speight

那只是我的普通样板,并且没有在其他地方进行测试。
bxm

15

对某些简单的行可能有用,以清除除主控和开发之外的所有本地分支

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

很棒的答案!我喜欢'git branch | grep -v "master" | grep -v "develop"在添加命令的删除部分之前如何轻松地玩弄这些东西。👏😊–
finneycanhelp

但这不能回答上面的问题。即使远程服务器仍然存在,这也会删除分支。
Jim.B

13

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

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 --mergedby 代替git branch -vv以显示状态(消失),因为前一个git branch --merged也可以显示母版
jpmottin

13

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

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

当您使用时-d,git将拒绝删除该分支,除非该分支已完全合并到HEAD其上游或远程跟踪分支中。因此,您始终可以遍历的输出git for-each-ref并尝试删除每个分支。这种方法的问题在于,我怀疑您可能不希望bug-fix-d仅因为origin/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

警告:我尚未测试此脚本-请谨慎使用...


我可以自由地编辑脚本。仍然不会提供任何保证,但是,它可以运行并且现在可以正常工作。
fwielstra 2014年

13

TL; DR:

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

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 将打印本地分支,修剪后的分支将被标记为 gone
  • grep ': gone]' 只选择已消失的分支
  • awk '{print $1}' 过滤输出以仅显示分支的名称
  • xargs git branch -D 将遍历所有行(分支)并强行删除此分支

为什么git branch -D,而不是git branch -d其他人,你将有分支机构未完全合并。

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

1
您想说遥控而不是主人吗?
tinos

8

您可以这样做:

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

7

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

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

它将删除所有': gone] '位于远程的本地分支。


1
看起来这还将删除最后一个提交消息中所有已“消失”的分支。
dlsso

它还将删除gone名称中任何位置的任何分支。
bfontaine

3
“ git branch -D git branch -vv | grep':消失]'| awk'{print $ 1}'| xargs`”这为我完成了工作。
Muthu Ganapathy Nathan

7
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为强制删除所有
Shoaib

如果您的任何分支名称碰巧在子字符串中的gone任何位置(例如usingonefunction)都非常危险。
Toby Speight

7

这些都不适合我。我想要清除所有跟踪远程分支的本地分支的方法,该分支位于origin已删除(gone)的远程分支上。我不想删除从未设置为跟踪远程分支的本地分支(即:我的本地dev分支)。我还想要一个仅使用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关于合并分支的抱怨。您可能还需要此功能。如果是这样,只需在config命令的末尾使用-D而不是即可-d


我喜欢git别名方法。快速问题:为什么要git branch -vv: gone]而做而不是为git branch -vgrep做[gone]
lalibi

@lalibi,好问题。我不记得了 我怀疑只有一件事情不会出现v。如果git branch -v | grep '[gone]'适合您,那就去吧。看起来确实有点干净。
Karl Wilbur

4

基于Git提示:删除旧的本地分支,它看起来类似于jason.rickman的解决方案,为此,我使用Bash 实现了一个自定义命令git goed

$ 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 -d或拉动扳机git gone -D

笔记

  • 我使用的正则表达式通常在"$BRANCH/.*: gone]"哪里$BRANCHorigin。如果您的Git输出已本地化为法语等,则可能无法正常工作。
  • Sebastian Wiesner还将其移植到Windows用户的Rust中。那个也叫git goted

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

4

从大量图纸数量 其他 的答案在这里,我已经结束了与以下(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参数来获取正确的转义输出(这使我们不必担心ref名称中的任何字符)。


它对我有用,但是如果您可以解释命令中的其他步骤正在做什么,那也很好。例如,我不知道这[ ! -z "$ref" ]意味着什么。我认为多班轮会有所帮助。但是仍然感谢您的输入!
KevinH

4

还有一个答案,因为这些解决方案都不符合我对优雅和跨平台性的需求:

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

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 branch-prune向git 添加命令
  • 从Windows PowerShell正常运行
  • 核心思想是@ jason.rickman防弹方法,使用git for-each-ref
  • 解析和过滤--filter无需任何外部依赖即可完成

说明:

  • 为您的添加新别名~\.gitconfig。执行此操作后,您只需git branch-prune
  • 在此别名内:
    • 使用提取分支 --prune标志的标志“修剪不再位于远程的远程跟踪分支”
    • 使用git for-each-ref--filter来获取分支的列表[gone](不是远程的)
    • 循环浏览此列表并安全删除分支

1
谢谢@ jerry-wu,它改善了此解决方案对无穷大的意义。
Himura

@ jerry-wu和您对git config命令的最后编辑在PowerShell中不起作用((
Himura

1

我想出了这个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
}

1

我使用了一种简短的方法来解决问题,我建议您执行相同的操作,因为这样可以节省一些时间并提高可见度

只需将以下代码段添加到您的.bashrc中(在macOS上为.bashprofile)。

git-cleaner() { git fetch --all --prune && git branch --merged | grep -v -E "\bmaster|preprod|dmz\b" | xargs -n 1 git branch -d ;};
  1. 获取所有遥控器
  2. 仅从git获取合并的分支
  3. 从此列表中删除“受保护的/重要的”分支
  4. 删除其余部分(例如,清理并合并分支)

您必须编辑grep regex以满足您的需求(此处可防止删除master,preprod和dmz)


git fetch --all --prune做到了。谢谢!
LeOn-韩立

1

这为我工作:

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

哦,我把这个贴了两次……在查看帖子时刚刚看到了这个。但是您确实可以指向提供此命令的人,而不是以此为己任!
Dwza

我把它从一个论坛,不要自作聪明只取答案,或者忽略它
法里德Alnamrouti

甚至比您可以...无论如何...没来这里与您讨论此事。如您所说...接受我的评论或忽略它;)
Dwza

0

我不确定要持续多长时间,但是我现在确实使用git-up,它可以解决这一问题。

我这样做git up,它开始跟踪新分支并删除旧分支。

只是为了清楚起见,它不是现成的git命令-https: //github.com/aanand/git-up

顺便说一句,它也隐藏了肮脏的树,并使得仍然可以用just进行重新设置git up

希望对某人有用


2
这不会删除服务器上不存在的本地分支。
阿什利

0

这是我用于鱼壳的解决方案。在测试了Mac OS X 10.11.5fish 2.3.0git 2.8.3

function git_clean_branches
  set base_branch develop

  # work from our base branch
  git checkout $base_branch

  # remove local tracking branches where the remote branch is gone
  git fetch -p

  # find all local branches that have been merged into the base branch
  # and delete any without a corresponding remote branch
  set local
  for f in (git branch --merged $base_branch | grep -v "\(master\|$base_branch\|\*\)" | awk '/\s*\w*\s*/ {print $1}')
    set local $local $f
  end

  set remote
  for f in (git branch -r | xargs basename)
    set remote $remote $f
  end

  for f in $local
    echo $remote | grep --quiet "\s$f\s"
    if [ $status -gt 0 ]
      git branch -d $f
    end
  end
end

一些注意事项:

确保设置正确base_branch。在这种情况下,我develop用作基础分支,但是可以是任何东西。

这部分非常重要:grep -v "\(master\|$base_branch\|\*\)"。它确保您不删除master或base分支。

git branch -d <branch>用作额外的预防措施,以免删除尚未与上游或当前HEAD完全合并的任何分支。

一种简单的测试方法是替换git branch -d $fecho "will delete $f"

我想我还应该补充:使用您自担风险!


0

我已经使用GitPython编写了Python脚本来删除远程上不存在的本地分支。

    import git
    import subprocess
    from git.exc import GitCommandError
    import os

    def delete_merged_branches():
        current_dir = input("Enter repository directory:")
        repo = git.Repo(current_dir)
        git_command = git.Git(current_dir)

        # fetch the remote with prune, this will delete the remote references in local.
        for remote in repo.remotes:
            remote.fetch(prune=True)

        local_branches = [branch.name for branch in repo.branches]
        deleted_branches = []

        # deleted_branches are the branches which are deleted on remote but exists on local.
        for branch in local_branches:
            try:
                remote_name = 'origin/'+ branch
                repo.git.checkout(remote_name)
            except GitCommandError:
            # if the remote reference is not present, it means the branch is deleted on remote.
                deleted_branches.append(branch)

        for branch in deleted_branches:
            print("Deleting branch:"+branch)
            git_command.execute(["git", "branch", "-D",branch])


        # clean up the work flow.
        repo.git.checkout('master')
        repo.git.pull()

    if __name__ == '__main__':
        delete_merged_branches()

希望有人觉得它有用,如果我错过了任何事情,请添加评论。


0

如果您使用的zshOh My Zsh已安装的Shell,那么最安全的方法就是使用内置的自动完成功能。

首先确定要删除的分支:

~ git branch --merged

  branch1
  branch2
  branch3
* master

这将向您显示已合并分支的列表

知道一些要删除的信息后,输入:

~ git branch -d 

您所要做的就是点击[tab],它会向您显示本地分支机构的列表。使用制表符完成功能或仅再次单击[制表符],即可循环浏览它们以选择[输入]分支。

选项卡反复选择分支,直到拥有要删除的分支列表为止:

~ git branch -d branch1 branch2 branch3

现在,只需按Enter键即可删除您的分支机构集合。

如果您不在终端上使用zsh,请在此处获取。


0

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

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

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

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

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

-3

这是使用git客户端对我有用的简单答案:

从您的计算机上完全删除存储库,然后再次签出。

不要混入危险的脚本。


2
那我现在正在工作的分支怎么样:/
MailoSvětel19年

@MailoSvětel,如果它们在您的遥控器上,那么您可以再次将它们拉出(记住要提交并将最新的工作推送到您的遥控器上!)
Juan Carlos Ospina Gonzalez

在我的问题和大多数答案中,我们正在努力避免不必要的工作。换句话说:我需要做的就是删除分支,不再使用。对我来说,删除回购,克隆它并重新开始跟踪分支是很多不必要的工作。除此之外,某些工作可能会丢失:(
MailoSvětel19
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.