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

Ale*_*lex 671 git

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

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

我怎样才能做到这一点?

Sch*_*eis 798

修剪后,您可以获取远程分支列表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 branch命令.

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

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

  • 是否有任何建议的命令用于将来执行此操作的git版本?这个命令看起来像我的猫已经在我的笔记本电脑上 (92认同)
  • 要将其添加为别名:`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'` (30认同)
  • 不幸的是,这在Windows上的Git Bash中不起作用.`sh.exe":无法为进程替换管道:函数未实现sh.exe":egrep -v -f/dev/fd/0:没有这样的文件或目录致命:需要分支名称`有什么想法吗? (15认同)
  • 这对我很有用.不知何故,````git fetch -p```并不总是足够的? (11认同)
  • 为什么没有像“git delete-untracked-branches”这样的东西,为什么我们需要学习这些令人费解的废话。 (4认同)
  • 致命:需要分支名称 (3认同)
  • @mani_jena 我会谨慎使用`-D`。它可能会删除一些您在本地尚未推送到 `origin` 的主题分支工作! (3认同)
  • 这是由于windows中的stdout不存在`/ dev/fd/0`,我不确定它的等价物是什么. (2认同)
  • 伟大的命令。如您所说,未完全合并的分支不会被删除。如果这些分支与您的案例无关,则在`git branch -D`中使用-D代替最终的`git branch -d`将很有帮助。 (2认同)
  • 对于 Windows 上的用户,@wisbucky 的答案中提出的方法对我有用:http://stackoverflow.com/a/30494276/315702 (2认同)
  • 我收到一个错误:运行此命令时`egrep:bracket([])not balanced`? (2认同)
  • 这似乎对我不起作用。就我而言,它缺少一些分支。在我看来,`branch -vv` 为远程跟踪分支已被修剪删除的分支写了`[origin/some_branch:gone]`?所以,以下似乎对我有用:`git branch -vv | grep -e ": 不见了]" | awk '{print $1}' | xargs git branch -d` (2认同)
  • 将选项“-r”添加到“xargs”,以在没有要删除的分支时忽略。 (2认同)
  • 在命令末尾使用`git branch -D`对我们来说效果更好,因为我们倾向于压缩合并时的提交,这使我们在`-d`中运行时分支x未完全合并`错误。 (2认同)
  • 我收到“错误:分支 my_local_test_branch 未完全合并”。所以,我添加了`-D`而不是`-d`来清理_unmerged_`my_local_branch`完整的命令:`git branch -r | awk '{print $1}' | egrep -v -f /dev/fd/0 &lt;(git branch -vv | grep origin) | awk '{print $1}' | xargs git branch -D` (2认同)
  • 我只是不希望本地分支跟踪不再存在的远程分支,这是我使用的别名: `alias git_branch_cleanup="git fetch -p &amp;&amp; git Branch -v | grep '[gone]' | awk ' {print $1}' | xargs git 分支 -D"` (2认同)
  • 现在在 Windows 版 Git Bash 中运行良好。看来之前存在的问题已经解决了。 (2认同)

jac*_*cnr 387

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

git branch --merged master | grep -v '^[ *]*master$' | xargs git branch -d
Run Code Online (Sandbox Code Playgroud)

更多信息.

  • 改进:`git branch --merged master | egrep -v'^\s*\*?\ s*master $'| xargs git branch -d`.检出主设备时,git v2.10.1的输出将显示"*master".无论是否有星号,我都摆脱了主人. (14认同)
  • 小改进:使用`xargs -r git branch -d`,这样如果没有要删除的分支就不会运行任何内容.请注意,`-r`标志[可能无处不在](http://stackoverflow.com/questions/18812766/dont-call-xargs-if-the-previous-command-doesnt-return-anything) (9认同)
  • 由于git颜色,grep可能不匹配:`git branch --merged master --no-color | grep -v'^*master $'| xargs -n1 -r git branch -d` (7认同)
  • @NickRes看到你问得这么好,`git branch --merged master`列出了合并为master的分支,然后中间的grep部分排除了master本身(我们不想删除master!),以及最后的xargs部分对每个结果执行`git branch -d`(删除分支).或者您可以阅读答案中提供的更多信息链接;) (4认同)
  • 我认为工作完美!谁能解释这个答案是否与接受的答案有什么不同? (3认同)
  • @mgcdanny(以及其他感兴趣的人):为了使它成为全局`git`别名,您需要做(在〜/ .gitconfig`或其他配置文件中):`cleaner =!git branch --merged master | grep -v'^ [*] * master $'| xargs git branch -d` (2认同)

twa*_*erg 149

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

 -p, --prune
        After fetching, remove any remote-tracking branches which no longer exist on the remote.
Run Code Online (Sandbox Code Playgroud)

那么,也许,git fetch -p你正在寻找什么?

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

首先,OP表示他们想要"删除那些从那些远程分支创建的本地分支[在远程分支上不再存在]".这并非毫无疑问是可能的git.这是一个例子.

假设我在中央服务器上有一个repo,它有两个分支,叫做AB.如果我克隆了一个回购协议,以我的本地系统,我的克隆将具有本地裁判(不是实际的分支机构还)叫origin/Aorigin/B.现在让我们说我做了以下事情:

git checkout -b A origin/A
git checkout -b Z origin/B
git checkout -b C <some hash>
Run Code Online (Sandbox Code Playgroud)

这里的相关事实是我出于某种原因选择在我的本地仓库上创建一个分支,其名称与其来源不同,并且我还有一个本地分支,但尚未存在于原始仓库中.

现在让我说我删除远程仓库上的AB分支并更新我的本地仓库(git fetch某种形式),这会导致我的本地参考origin/Aorigin/B消失.现在,我的本地回购有三大分支的是,A,Z,和C.这些都没有在远程仓库上有相应的分支.其中两个是"从...远程分支创建的",但即使我知道曾经有一个分支B在原点上调用,我也无法知道它Z是从B,因为它在这个过程中被重命名,可能是有充分理由的.因此,实际上,如果没有一些外部过程记录分支起源元数据,或者知道历史记录的人,就不可能分辨出哪三个分支(如果有的话)OP正在瞄准去除.如果没有一些git不能为你自动维护的外部信息,git fetch -p就会尽可能接近,并且任何自动尝试OP所要求的方法都会冒着删除过多分支的风险,或者错过一些OP否则想要删除.

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

  • 这不会删除本地分支,只会删除分支的远程指针 (102认同)
  • 正如Jaap所说,你应该更仔细地阅读这个问题.投票给这个答案的人也应该阅读问题的真正含义. (14认同)
  • 它只删除这些本地分支,这些分支在远程AND中不存在,您从未对它们进行检查. (4认同)
  • 是的,这实际上就是我想要做的!@SørenBoisen我希望在过去的两年里你有时间重新审视你的意见......如果发布在SO上的内容应该只与OP有时真正混淆的内容有关,我们会删除很多信息.除了官方指南之外,请不要假设指导人们如何使用本网站,并且他们显然不会阻止正交但有用的答案. (4认同)
  • @FélixGagnon-Grenier这是我对这个答案的问题:1)问题很明确,OP显然不会混淆.2)这个答案没有提到它没有回答这个问题!3)这个问题已经说明了一种修剪不再存在的远程跟踪分支的方法,因此它增加了零值. (4认同)
  • 答案不仅仅是操作。近一百人发现这很有用。当然是增值啦!! (2认同)
  • 即使本地分支名称与上游分支不匹配,Git 仍会跟踪这些分支跟踪上游分支,这可用于删除分支。在`.git/config` 中,每个这样的分支及其上游名称都有条目。因此,Git 可以使用这些信息来修剪本地分支。这只是一个缺失的功能。 (2认同)

wis*_*cky 105

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

git checkout master
git branch -vv | grep ': gone]' | awk '{print $1}' | xargs git branch -d
Run Code Online (Sandbox Code Playgroud)

细节:

  • 您甚至可以使用`git branch -vv |缩短命令 awk'/:gone]/{print $ 1}'| xargs git branch -d` (15认同)
  • 在执行此操作之前,请指出您应该在master上,因为`git branch -d`将分支与`HEAD`进行比较. (4认同)
  • 哦伙计...... wisbucky你需要更新你的答案,告诉别人他们应该掌握.刚从另一个分支做到这一点.@ stevebennet2感谢您提供丰富的评论 (3认同)
  • 对于决定使用“xargs gitbranch -D”的任何人,请注意“-D”标志本质上是“强制删除”,但对于删除远程分支被挤压合并或重新基址的分支是必要的,因此作为一个很好的中间立场,我建议在每次删除之前提示用户确认(更安全);使用“xargs -p git分支-D” (3认同)
  • `: gone]` 部分是本地化字符串。对于法语版本,您必须使用 `: disparue]`。 (2认同)

wed*_*oft 47

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

git config --global fetch.prune true
Run Code Online (Sandbox Code Playgroud)

在呼叫时git fetchgit pull之后,对已删除的远程分支的引用会自动删除.

  • 这不会删除本地分支,只是引用它们,对吗? (4认同)

tza*_*chs 33

有一个简洁的NPM包为你做(它应该跨平台工作).

安装它: npm install -g git-removed-branches

然后git removed-branches将向您展示所有陈旧的本地分支,并git removed-branches --prune实际删除它们.

更多信息在这里.

  • 这是我最喜欢的答案。`npx git-removed-branches` 就像做梦一样。 (7认同)
  • 是的!这应该有更多的赞成票!对于 cli 新手来说如此简单直观的解决方案 (5认同)
  • 这确实应该得到更多的支持。感谢您让生活变得轻松,无论平台如何。 (4认同)
  • 从 git 的角度概述该工具正在做什么将会很有用。 (3认同)
  • @ryanwebjackson 该项目位于 Github 上:https://github.com/nemisj/git-removed-branches (2认同)

chr*_*389 29

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引用)

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

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

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

  • 看起来最新版本的git会添加一些尾随空格,因此Split无法获取分支名称.做.toString().修剪().分割("")它会 (3认同)

027*_*027 24

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

$ git remote prune origin --dry-run
Run Code Online (Sandbox Code Playgroud)

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

$ git remote prune origin
Run Code Online (Sandbox Code Playgroud)

  • 这不回答问题,这是OP已经知道的. (16认同)
  • 我也同意,但是当你搜索"如何修剪遥控器上不存在的本地跟踪分支"时,这是顶部链接,这个答案与标题匹配(如果有人阅读了相关的完整描述),是投票的原因:) (2认同)

Gna*_*nat 14

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

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

说明

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

git branch --merged首先值得自己运行,以确保它只会删除你的预期.

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


S'c*_*ock 11

这是我的解决方案:

git fetch -p
git branch -vv | grep ": gone" | awk '{print $1}' | xargs git branch -d
Run Code Online (Sandbox Code Playgroud)
  • -p是删除远程上不再存在的任何远程跟踪引用。所以第一步将删除对远程分支的引用。

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


Kar*_*bur 8

我想要一些东西可以清除跟踪远程分支的所有本地分支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
Run Code Online (Sandbox Code Playgroud)

这是一个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'
Run Code Online (Sandbox Code Playgroud)

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


Oli*_*ver 8

似乎没有一个安全的单线,太多的边缘情况(例如一个分支将“master”作为其名称的一部分等)。最安全的是这些步骤:

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


Mac*_*ane 8

此命令和下面的脚本可在 Linux 和 Windows 中使用 Git Bash (MinGW) 运行。

最好使用 git 的内部命令,这样注释或名称就不会意外匹配并删除您不想删除的分支。有许多内部“原子”可以与git for-each-ref的 format 选项一起使用来输出所需的信息。这样我们就不必依赖管道awkgrep检查输出上可能包含不必要信息的正则表达式。

下面的命令仅使用 的git for-each-ref内部低级命令来仅列出孤立的本地分支。一旦你有了这些,你就可以通过管道连接到git branch -D. 另外,不要忘记首先修剪并获取远程引用,否则它将找不到任何匹配项:

git fetch -p
git for-each-ref --format '%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)' 'refs/heads/**' | xargs -r git branch -D
Run Code Online (Sandbox Code Playgroud)

这是一个细分:

git fetch -p- 修剪删除的引用并从远程获取新的引用

git for-each-ref --format- 列出使用特定输出格式的所有引用。

%(if:equals=[gone])%(upstream:track)- 仅当上游跟踪分支为“[gone]”时输出。

%(then)%(refname:short)%(end)- 输出分支名称(当跟踪消失时)。

refs/heads/**- 限制头部引用(为了效率)。

| xargs -r git branch -D- 管道输出作为删除参数。表示-r忽略空白输入。


就其本身而言,这个解决方案很长,打字起来很荒谬,而且很难记住。幸运的是,向 git 添加自定义命令很容易。下面是一个使用上面相同命令的脚本,但它允许用户查看将使用选项选择哪些分支--dry-run

我命名了我的文件git-prune-local并将其放入我的PATH. 它还需要执行权限(chmod 755 git-prune-local)。

Git 自动查找可执行文件,例如git-[command]. 这样,您只需键入git prune-local要删除的正确分支即可。

git-prune-本地

#!/bin/sh

if [ $# -gt 1 ] || ([ ! -z $1 ] && [ $1 != "--dry-run" ])
then
    echo "Usage: git prune-local [--dry-run]"
    exit
fi

git fetch -p --quiet
branchesToDelete=$(git for-each-ref --format '%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)' 'refs/heads/**')

while read -r branch
do
    if [ ! -z $branch ]
    then
        if [ ! -z $1 ]
        then
            echo $branch
        else
            git branch -D $branch
        fi
    fi
done <<< "$branchesToDelete"
Run Code Online (Sandbox Code Playgroud)


Eve*_*t_B 8

您可以使用该--no-contains选项来避免master在使用分支时删除分支--merged

单独运行看起来像

$ git branch --no-contains master --merged master
    old-branch1
    old-branch2
    old-branch3
Run Code Online (Sandbox Code Playgroud)

要在 Unix shell 中删除分支,请使用xargs

git branch --no-contains master --merged master | xargs git branch -d
Run Code Online (Sandbox Code Playgroud)

使用管道删除 Powershell 中的分支

git branch --no-contains master --merged master `
   | % { $_.toString().Trim().Split(" ")[0] } `
   | % { git branch '-d' $_ }
Run Code Online (Sandbox Code Playgroud)


Fel*_*ikZ 7

更短更安全的单线:

git branch -d $(git branch --merged | cut -c 3- | grep -v master)
Run Code Online (Sandbox Code Playgroud)

在运行之前,请务必签出尚未合并的分支.因为您无法删除当前签入的分支.

  • 这还会删除你的'主人'吗? (3认同)
  • 如果您当前已登录母版,则否,否则 (2认同)
  • 要跳过 master,您可以通过管道连接到 grep 并选择相反的部分,就像这样 - `git branch -d $(git branch --merged | cut -c 3- | grep -v master)` (2认同)
  • @jasonseminara #dcsan 我已经更新了代码片段,因此它跳过了 master 分支。#mozillalives 谢谢 (2认同)

小智 6

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

npx git-removed-branches --prune
Run Code Online (Sandbox Code Playgroud)

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

  • 这应该在顶部。也适用于 Windows。 (4认同)
  • 华丽的。没有任何麻烦。很高兴这是一个完整的答案! (3认同)
  • 零麻烦!如果不需要 npx,它会位于顶部 (2认同)

Raú*_*udo 6

在Powershell中:

git branch -D (git branch --merged |% { $_.trim() } )
Run Code Online (Sandbox Code Playgroud)


hid*_*isk 5

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

git remote prune origin | awk 'BEGIN{FS="origin/"};/pruned/{print $2}' | xargs -r git branch -d
Run Code Online (Sandbox Code Playgroud)

此外,如果您已经修剪并有本地悬垂的分支,那么这将清理它们:

git branch -vv | awk '/^ .*gone/{print $1}' | xargs -r git branch -d
Run Code Online (Sandbox Code Playgroud)


小智 5

删除远程分支

$git remote prune origin
Run Code Online (Sandbox Code Playgroud)

删除已经合并的本地分支

$git branch -D $(git branch --merged)
Run Code Online (Sandbox Code Playgroud)

  • 这删除了我的主分支。 (31认同)
  • (git Branch --merged) 也为我返回“master”。以及远程上尚未删除的其他分支。 (6认同)

Chu*_*Tey 5

在 OS X 上,支持cut -w

git branch -d $(git branch -vv | grep ': gone]' | cut -w -f 2 )
Run Code Online (Sandbox Code Playgroud)

解释

删除以下分支
git branch -d ...
Run Code Online (Sandbox Code Playgroud)

显示已删除的分支

$ git branch -vv | grep ': gone]'
  chore/TECH-456   a4bdac8ac8 [origin/TECH-456: gone] chore: syntax error
  feature/TECH-678 0342f8e277 [origin/feature/TECH-678: gone] Added IsGross in new Income Details
Run Code Online (Sandbox Code Playgroud)

保留分支名称

$ git branch -vv | grep ': gone]' | cut -w -f 2
chore/TECH-456
feature/TECH-678
Run Code Online (Sandbox Code Playgroud)