如何修剪远程不再存在的本地跟踪分支


767

随着git remote prune origin我可以删除本地分支机构不在遥控器上的任何更多。

但是我还想删除从那些远程分支创建的本地分支(检查它们是否未合并将是不错的选择)。

我怎样才能做到这一点?



1
一线交叉平台看起来不像猫睡在键盘上:( npx git-removed-branches干运转)或npx git-removed-branches --prune(真实)。您需要已经有node.js的安装。有关详细信息,请参见下面答案
Cristian Diaconescu

Answers:


888

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

这行应该可以解决问题(需要bashzsh,不适用于标准的Bourne shell):

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),然后获取该输出的第一列,即分支名称。最后,将所有分支名称传递给delete分支命令。

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

还记得你需要运行的git fetch --prune 第一,否则git branch -r仍然会看到远程分支。


12
这非常适合我。不知何故,git fetch -p并不总是足够?
Stefan Hendriks 2013年

16
不幸的是,这在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 有任何想法吗?
2014年

37
要将其添加为别名: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 '16

125
对于将来的git版本,是否有任何建议的命令可以做到这一点?这个命令看起来像我的猫一直在我的笔记本电脑上
Bron Davies

5
git branch -D在命令末尾使用,对我们来说效果更好,因为我们倾向于压缩合并时的提交,因此The branch x is not fully merged在运行时会出错-d
Mateus Gondim'3

429

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

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

更多信息


4
我认为做得完美!谁能解释这个答案与接受的答案有什么不同吗?
安德鲁

11
轻微改进:使用xargs -r git branch -d该方法,以便在没有要删除的分支的情况下不执行任何操作。请注意,该-r标志可能并非在任何地方都可用
Jacob Wang

8
由于grep可能由于git颜色而导致不匹配:git branch --merged master --no-color | grep -v '^* master$' | xargs -n1 -r git branch -d
Mike D

5
@NickRes很好地看到了您的要求,git branch --merged master列出了合并到master中的分支,然后中间的grep部分排除了master本身(我们不想删除master!),最后一个xargs部分git branch -d在每一个上执行(删除分支)结果。或者,您也可以阅读答案中提供的“更多信息”链接;)
jackocnr

14
改进:git branch --merged master | egrep -v '^\s*\*?\s*master$' | xargs git branch -d。检出master时,git v2.10.1的输出将显示“ * master”。无论有没有星号,我都会摆脱掌握。
埃斯特万(Esteban)

162

在中提供的信息中git help fetch,有一个小项目:

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

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

编辑:好的,对于那些在事实发生三年后仍在争论这个答案的人,这里有更多关于我为什么提出这个答案的信息。

首先,OP表示他们希望“也删除从那些远程分支[不再在远程]上创建的本地分支”。在中,这并非不可能git。这是一个例子。

假设我在中央服务器上有一个存储库,它有两个分支,分别称为AB。如果我将该存储库克隆到本地系统,则我的克隆将具有称为origin/A和的本地引用(尚未有实际分支)origin/B。现在,让我说以下:

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

这里的相关事实是,由于某种原因,我选择了在本地存储库中创建一个名称与原始名称不同的分支,并且我也有一个本地分支(尚未)存在于原始存储库中。

现在,假设我同时删除了远程仓库中的AB分支,并更新了本地仓库(git fetch某种形式),这会导致本地引用origin/Aorigin/B消失。现在,我的本地回购有三大分支的是,AZ,和C。这些都没有在远程仓库上有相应的分支。其中两个是“从...远程分支创建的”,但是即使我知道曾经有一个B起源调用过的分支,我也无法知道它Z是从...创建的B,因为在此过程中将其重命名,可能有充分的理由。因此,实际上,如果没有任何外部过程来记录分支原始元数据,或者没有一个知道历史的人员,就无法确定OP的目标是删除三个分支中的哪个(如果有)。如果没有一些git不会自动为您维护的外部信息,这些信息将git fetch -p尽可能地接近您,并且任何自动尝试OP请求的自动方法都可能会删除过多的分支,或者会丢失OP否则会丢失的分支要删除。

同样,还有其他场景,例如,如果我创建了三个单独的分支origin/A来测试三种不同的方法,然后origin/A消失了。现在,我有三个分支,显然不能全部按名称匹配,但是它们是从创建的origin/A,因此要对OPs问题进行字面解释,则需要删除所有三个分支。但是,如果您甚至可以找到一种可靠的方式来匹配它们,那可能就不那么理想了……


107
这不会删除本地分支,只会删除指向分支的远程指针
Jaap 2013年

4
它仅删除这些本地分支,而这些分支在远程中不存在,并且您从未对其进行检出。
Jarek Jakubowski15年

15
如Jaap所述,您应该更仔细地阅读问题。投票支持该答案的人们还应该阅读该问题的实质。
索伦·布森(SørenBoisen)

4
是的,这实际上正是我想要做的!@SørenBoisen我希望在过去的两年中您有时间重新审视您的意见...如果SO上发布的内容始终仅与有时真正令人困惑的OP提出的要求有关,我们将删除很多信息。除官方指南外,请勿以其他方式指导人们如何使用本网站,并且他们显然不会阻止正交但有用的答案。
费利克斯·加侬-格雷尼尔

6
@FélixGagnon-Grenier这是我关于这个答案的问题:1)这个问题很明确,OP显然不感到困惑。2)这个答案没有提到它没有回答问题!3)该问题已经说明了修剪不再存在的远程跟踪分支的方法,因此它添加了零值。
索伦Boisen

117

这将删除已修剪了远程跟踪分支的本地分支。(确保您在master分支机构!)

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

细节:

  • git branch -vv 显示已删除远程分支的本地分支的“已消失”。

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

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

15
您甚至可以使用git branch -vv | awk '/: gone]/{print $1}' | xargs git branch -d
chiborg

4
只是指出在执行此操作之前您应该是master上的,因为git branch -d比较分支与HEAD
史蒂夫·贝内特

优秀的!我看着并寻找了这个。我希望在我自己弄清答案之前,已经看过你的答案。这样可以节省我几分钟。这里是我的其他答案:stackoverflow.com/questions/15661853/...
卡尔·威尔伯

1
我最终得到了一个相似的git别名,由于awk由于某些原因无法使用,因此使用了cut:prunelocal = !sh -c \"git checkout -q master && git fetch -q --prune && git branch -vv | git grep ': gone]' | cut -d' ' -f3 | xargs git branch -d\"
Zitrax '16

3
噢,伙计... wisbucky,您需要更新您的答案,以告诉人们他们应该成为大师。只是从另一个分支进行的。@ stevebennet2感谢您提供的
有益

53

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

git config --global fetch.prune true

调用时git fetchgit pull之后,对已删除的远程分支的引用将自动删除。


5
这不会删除本地分支,而只是引用它们,对不对?
克林特·伊斯特伍德

@ClintEastwood它仅删除对远程分支的引用。您可以使用列出对远程分支的引用git branch -r
wedesoft

52

有一个简洁的NPM软件包可以为您完成(它应该跨平台工作)。

通过以下方式安装: npm install -g git-removed-branches

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

更多信息在这里。


1
这确实应该有更多的支持。感谢您使生活变得轻松,无论平台如何。
加密

方便的小扩展。在Windows 10上已安装并运行良好。需要注意的是:它认为非合并分支是可修剪的(运行--prune时出错,尽管调用了branch -d)。显示清单。
user2864740

1
这是我最喜欢的答案。npx git-removed-branches像梦一样工作。
Drazisil

是!这应该有更多的支持!cli的新手这么简单直观的解决方案
geoseong

从git的角度概述该工具的功能将很有用。
ryanwebjackson

41

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

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


很好的例子。或者使用git remote prune origin,select-string似乎与最新版本的git不匹配。考虑使用ConvertFrom-String -TemplateContent
Bernie White

3
看起来最新版本的git增加了一些尾随空格,因此Split无法获得分支名称。执行.toString()。Trim()。Split(“”),它将
克里斯·海因斯

这是我的:git checkout master; git pull; git remote prune origin; git branch --merged | select-string -notmatch "master" | % { $_.toString().Trim().Split(" ")[0]} | % {git branch -d $_}
Omzig

@Omzig有什么不同?你能给个解释吗?
chris313​​89 '19

@ chris313​​89,我可以从那里获取从master丢失的所有内容,并且我将分支更改为--merged而不是master,我想确保只删除--merged分支。这只是让我感觉更好;)
Omzig

27

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

$ git remote prune origin --dry-run

如果要取消引用未跟踪的本地分支

$ git remote prune origin

19
这不能回答问题,这是OP已经知道的。
肯·威廉姆斯

2
我也同意,但是当您搜索“如何修剪不再存在于远程的本地跟踪分支”时,这是顶部链接,并且此答案与标题匹配(如果没有阅读有问题的完整说明,则不是)是投票的原因:)
027

这不会删除本地分支。运行此命令后仍在那里
Xin

@Xin尝试在不带--dry-run参数的情况下运行该命令,因为它实际上不会执行该命令,但会告诉您它将发生什么变化。
Torsten Ojaperv '18

18

正如@tzacks所提到的...有一个npm软件包很方便。做就是了:

npx git-removed-branches --prune

(我会发表评论,但声誉不足)


1
华丽。没有任何麻烦。很高兴这是一个完整的答案!
丹·雷森

1
这应该在顶部。也可以在Windows中使用。
tomtastico

14

如果使用Windows和Powershell,则可以使用以下命令删除已合并到当前检出的分支中的所有本地分支:

git branch --merged | ? {$_[0] -ne '*'} | % {$_.trim()} | % {git branch -d $_}

说明

  • 列出当前分支和已合并到其中的分支
  • 筛选出当前分支
  • git为其余的每个分支名称清除输出中的任何前导或尾随空格
  • 删除合并的本地分支

值得git branch --merged首先单独运行,以确保它只会删除您期望的内容。

(从http://railsware.com/blog/2014/08/11/git-housekeeping-tutorial-clean-up-outdated-branches-in-local-and-remote-repositories/移植/自动化)。


10

更短更安全的单线:

git branch -d $(git branch --merged | cut -c 3- | grep -v master)

在运行它之前,请确保签出到尚未合并的分支。因为您无法删除当前已签入的分支。


3
这还会删除您的“主人”吗?
dcsan

2
如果您当前已
登录

1
要跳过主语言,您可以通过管道传递到grep并选择反函数,如下所示 git branch -d $(git branch --merged | cut -c 3- | grep -v master)
mozillalives

这是不安全的,将来有人会在不知不觉中删除其主分支
jasonseminara 19'Aug

1
@jasonseminara #dcsan我已经更新了代码段,因此它跳过了master分支。#mozillalives感谢
FelikZ

9

我想要一种能够清除所有正在跟踪远程分支的本地分支的方法,该分支位于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'

注意:使用-D标志git branch可能非常危险。因此,在上面的config命令中,我使用-d选项git branch而不是-D; 我-D在实际配置中使用。我-D之所以使用,是因为我不想听到Git抱怨合并的分支,我只是希望它们消失。您可能还需要此功能。如果是这样,只需在config命令的末尾使用-D而不是即可-d


8

删除远程分支:

$git remote prune origin

要删除已经合并的本地分支:

$git branch -D $(git branch --merged)

为我工作。谢谢。
AndroidRuntimeException

2
(git branch --merged)也为我返回“ master”。以及尚未删除的其他分支。
汤姆G

8
这删除了我的主分支。
格雷格

5

似乎没有一个安全的单行代码,没有太多的边缘情况(例如分支中以“ master”作为其名称的一部分,等等)。最安全的步骤如下:

  1. git branch -vv | grep 'gone]' > stale_branches.txt
  2. 查看文件并删除要保留的分支的行(例如master分支!);您不需要编辑任何行的内容
  3. awk '{print $1}' stale_branches.txt | xargs git branch -d

5

根据以上答案,我正在使用这种较短的衬管:

git remote prune origin | awk 'BEGIN{FS="origin/"};/pruned/{print $2}' | xargs -r git branch -d

另外,如果您已经修剪了树枝并在本地悬挂了树枝,则可以清理它们:

git branch -vv | awk '/^ .*gone/{print $1}' | xargs -r git branch -d

1
如果您的分支机构名称中包含a /,则
不起作用

4

不知道如何一次完成所有操作,但是git git branch -d <branchname>仅在完全合并后才删除本地分支。注意小写字母d。

git branch -D <branchname> (请注意,大写字母D)将删除本地分支机构,无论其合并状态如何。


在Windows上,其他答案对我不起作用。通过简单的-D开关使用此答案即可(即使该分支已被“删除”)。

我们可以一次为所有分支机构做到吗?
Teoman shipahi

3

您可以使用以下命令:

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

Git Clean:删除已合并的分支,包括分解命令


您实际上并不需要过滤掉任何分支(例如master)。如果它是“合并的”,则意味着它将删除您的本地副本,但是“ git checkout dev”将从远程创建一个本地分支(如果尚不存在的话)
csga5000

但是即使合并了本地分支机构列表,它们仍然存在。该命令将删除已从远程删除的这些分支。
sendon1982 '18

开头的星号表示当前分支,当您在其他分支上运行该命令时效果不佳
OzzyCzech

2

根据上面的答案,我提供了一种解决方案:

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

2

在@wisbucky的答案上使用变体,我在~/.gitconfig文件中添加了以下内容作为别名:

pruneitgood = "!f() { \
    git remote prune origin; \
    git branch -vv | perl -nae 'system(qw(git branch -d), $F[0]) if $F[3] eq q{gone]}'; \
}; f"

这样,一个简单的操作git pruneitgood就可以清除合并后不再需要的本地和远程分支。


2

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

git branch --merged master | %{ if($_ -notmatch '\*.*master'){ git branch -d "$($_.Trim())" }}

当您位于master分支上时,这将删除已合并到master中的所有本地分支

git checkout master 换成。


1

Schleis的变体对我不起作用(Ubuntu 12.04),所以让我提出我的(清晰::)变体:

变体1(我希望使用此选项):

git for-each-ref --format='%(refname:short) %(upstream)' refs/heads/ | awk '$2 !~/^refs\/remotes/' | xargs git branch -D 

形式2:

一个。空运行:

comm -23 <( git branch | grep -v "/" | grep -v "*" | sort ) <( git br -r | awk -F '/' '{print $2}' | sort ) | awk '{print "git branch -D " $1}'

b。删除分支:

comm -23 <( git branch | grep -v "/" | grep -v "*" | sort ) <( git br -r | awk -F '/' '{print $2}' | sort ) | xargs git branch -D

1

以下是Windows用户对@wisbucky答案的改编:

for /f "tokens=1" %i in ('git branch -vv ^| findstr ": gone]"') DO git branch %i -d

我使用posh-git,不幸的是PS不喜欢for裸机,所以我创建了一个简单的'ol命令脚本,名为PruneOrphanBranches.cmd:

@ECHO OFF
for /f "tokens=1" %%i in ('git branch -vv ^| findstr ": gone]"') DO CALL :ProcessBranch %%i %1

GOTO :EOF

:ProcessBranch
IF /I "%2%"=="-d" (
    git branch %1 %2
) ELSE (
    CALL :OutputMessage %1
)
GOTO :EOF

:OutputMessage
ECHO Will delete branch [%1] 
GOTO :EOF

:EOF

不带参数调用以查看列表,然后以“ -d”调用以执行实际的删除操作,或以“ -D”调用未完全合并但仍要删除的任何分支。


这对我不起作用,无论如何,in :: (带空格)findstr每次都与所有内容匹配-我几乎删除了master。但是,使用正则表达式效果很好:git branch -vv ^| findstr /R " \[origin/[0-9]+: gone\] "
乔什(Josh)2015年

1

在git bash中尝试此操作,以获取和删除对已删除分支的引用,然后修剪正在跟踪已删除分支的本地分支:

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

切记先签出一个不会被删除的分支,这样才不会阻止该分支的删除。



0

我到达此页面,寻求“如何删除不再具有上游分支的本地检出分支”的答案

我也不在乎本地分支是否已经合并,因为管道git branch -d将简单地发出警告,而不是删除未合并的本地分支。

git branch -a | grep origin | tr -s ' ' | cut -d '/' -f3 | egrep -v -f /dev/fd/0 <(git branch -a | grep -v origin) | grep branch_prefix_that_I_care_about | xargs git branch -d

# translation
# git branch -a | grep origin | tr -s ' ' | cut -d '/' -f3
## this finds all remote branch names minus the "remote/origin/" part
#
# <(git branch -a | grep -v origin)
## this finds all local branch names and redirects it into the previous command
#
# egrep -v -f /dev/fd/0 STUFF
## this is doing some weird magic that I'm grokking as "take the set difference from whatever was piped in"
#
#
# overall translation: (STUFF TO CONSIDER) | egrep magic <(STUFF TO REMOVE FROM CONSIDERATION) | do cool things with resulting stuff


0

这是我的解决方案:

git fetch -p
git branch -vv | grep ": gone" | awk '{print $1}' | xargs git branch -d
  • -p将删除远程上不再存在的任何远程跟踪引用。因此,第一步将删除对远程分支的引用。

  • -vv用于显示每个头的sha1和commit主题行,以及与上游分支的关系(如果有)。第二步将获取所有本地分支,而grep命令将筛选出已删除的分支。



-3

我很确定那git remote prune origin是您想要的。

您可以将其运行git remote prune origin --dry-run以查看它做什么而无需进行任何更改。


12
这实际上并不会删除本地分支本身。
Taytay 2014年

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.