git 删除不再远程的跟踪分支

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7726949/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-10 12:02:44  来源:igfitidea点击:

Remove tracking branches no longer on remote

gitgit-branch

提问by Mailo Světel

Is there a simple way to delete all tracking branches whose remote equivalent no longer exists?

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

Example:

例子:

Branches (local and remote)

分支机构(本地和远程)

  • master
  • origin/master
  • origin/bug-fix-a
  • origin/bug-fix-b
  • origin/bug-fix-c
  • 掌握
  • 起源/主人
  • 起源/错误修复-a
  • 起源/错误修复-b
  • 起源/错误修复-c

Locally, I only have a master branch. Now I need to work on bug-fix-a, so I check it out, work on it, and push changes to the remote. Next I do the same with bug-fix-b.

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

Branches (local and remote)

分支机构(本地和远程)

  • master
  • bug-fix-a
  • bug-fix-b
  • origin/master
  • origin/bug-fix-a
  • origin/bug-fix-b
  • origin/bug-fix-c
  • 掌握
  • 错误修复-a
  • 错误修复-b
  • 起源/主人
  • 起源/错误修复-a
  • 起源/错误修复-b
  • 起源/错误修复-c

Now I have local branches master, bug-fix-a, bug-fix-b. The Master branch maintainer will merge my changes into masterand delete all branches he has already merged.

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

So the current state is now:

所以现在的状态是:

Branches (local and remote)

分支机构(本地和远程)

  • master
  • bug-fix-a
  • bug-fix-b
  • origin/master
  • origin/bug-fix-c
  • 掌握
  • 错误修复-a
  • 错误修复-b
  • 起源/主人
  • 起源/错误修复-c

Now I would like to call some command to delete branches (in this case bug-fix-a, bug-fix-b), which are no longer represented in the remote repository.

现在我想调用一些命令来删除分支(在这种情况下是bug-fix-abug-fix-b),这些分支不再出现在远程存储库中。

It would be something like the existing command git remote prune origin, but more like git local prune origin.

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

回答by aubreypwd

git remote prune originprunes tracking branches not on the remote.

git remote prune origin修剪不在遥控器上的跟踪分支。

git branch --mergedlists branches that have been merged into the current branch.

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

xargs git branch -ddeletes branches listed on standard input.

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

Be careful deleting branches listed by git branch --merged. The list could include masteror other branches you'd prefer not to delete.

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

To give yourself the opportunity to edit the list before deleting branches, you could do the following in one line:

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

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

回答by jason.rickman

After the command

命令后

git fetch -p

removes the remote references, when you run

运行时删除远程引用

git branch -vv

it will show 'gone' as the remote status. For example,

它将显示“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

So you can write a simple script to remove local branches that have gone remotes:

所以你可以编写一个简单的脚本来删除已经远程的本地分支:

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

Note that the above uses the "porcelain" command git branchto get the upstream status.

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

Another way to obtain this status is to use the "plumbing" command git for-each-refwith the interpolation variable %(upstream:track), which will be [gone]just like above.

获得这种状态的另一种方法是使用“管道”命令git for-each-ref与所述内插变量%(upstream:track),这将是[gone]一样的上方。

This approach is somewhat safer, because there is no risk of accidentally matching on part of the commit message.

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

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

回答by dlsso

Most of these answers do not actually answer the original question. I did a bunch of digging and thiswas the cleanest solution I found. Here is a slightly more thorough version of that answer:

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

  1. Check out your default branch. Usually git checkout master
  2. Run git fetch -p && git branch -vv | awk '/: gone]/{print $1}' | xargs git branch -d
  1. 查看您的默认分支。通常git checkout master
  2. git fetch -p && git branch -vv | awk '/: gone]/{print $1}' | xargs git branch -d

Explanation:

解释:

Works by pruning your tracking branches then deleting the local ones that show they are "gone" in git branch -vv.

通过修剪您的跟踪分支然后删除显示它们在git branch -vv.

Notes:

笔记:

If your language is set to something other than English you will need to change goneto the appropriate word. Branches that are local only will not be touched. Branches that have been deleted on remote but were not merged will show a notification but not be deleted on local. If you want to delete those as well change -dto -D.

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

回答by Andrew Spencer

I wouldn't normally answer a question that already has 16 answers, but all the other answers are wrong, and the right answer is so simple. The question says, "Is there a simple way to delete all tracking branches whose remote equivalent no longer exists?"

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

If "simple" means deleting them all in one go, not fragile, not dangerous, and without reliance on tools that not all readers will have, then the right answer is: no.

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

Some answers are simple, but they don't do what was asked. Others do what was asked, but are not simple: all rely on parsing Git output through text-manipulation commands or scripting languages, which may not be present on every system. On top of that, most of the suggestions use porcelain commands, whose output is not designed to be parsed by script ("porcelain" refers to the commands intended for human operation; scripts should use the lower-level "plumbing" commands).

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

Further reading:

进一步阅读:



If you want to do this safely, for the use case in the question (garbage-collect tracking branches which have been deleted on the server but still exist as local branches) and with high-level Git commands only, you have to

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

  • git fetch --prune(or git fetch -p, which is an alias, or git prune remote originwhich does the same thing without fetching, and is probably not what you want most of the time).
  • Note any remote branches that are reported as deleted. Or, to find them later on, git branch -v(any orphaned tracking branch will be marked "[gone]").
  • git branch -d [branch_name]on each orphaned tracking branch
  • git fetch --prune(或者git fetch -p,这是一个别名,或者git prune remote origin在不获取的情况下执行相同的操作,并且可能在大多数情况下不是您想要的)。
  • 请注意报告为已删除的任何远程分支。或者,为了稍后找到它们,git branch -v(任何孤立的跟踪分支都将被标记为“[gone]”)。
  • git branch -d [branch_name]在每个孤立的跟踪分支上

(which is what some of the other answers propose).

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

If you want to script a solution, then for-each-refis your starting point, as in Mark Longair's answerhere and this answer to another question, but I can't see a way to exploit it without writing a shell script loop, or using xargs or something.

如果你想编写一个解决方案,那么for-each-ref你的起点就是你的起点,就像Mark Longair在这里的回答另一个问题的回答一样,但我看不到一种方法来利用它而不编写 shell 脚本循环,或者使用 xargs 或其他东西.



Background explanation

背景说明

To understand what's happening, you need to appreciate that, in the situation of tracking branches, you have not one branch, but three. (And recall that "branch" means simply a pointer to a commit.)

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

Given a tracking branch feature/X, the remote repository (server) will have this branch and call it feature/X. Your local repository has a branch remotes/origin/feature/Xwhich means, "This is what the remote told me its feature/X branch was, last time we talked," and finally, the local repository has a branch feature/Xwhich points to your latest commit, and is configured to "track" remotes/origin/feature/X, meaning that you can pull and push to keep them aligned.

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

At some point, someone has deleted the feature/Xon the remote. From that moment, you are left with your local feature/X(which you probably don't want any more, since work on feature X is presumably finished), and your remotes/origin/feature/Xwhich is certainly useless because its only purpose was to remember the state of the server's branch.

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

And Git will let you automatically clean up the redundant remotes/origin/feature/X-- that's what git fetch --prunedoes -- but for some reason, it doesn't let you automatically delete your own feature/X... even though your feature/Xstill contains the orphaned tracking information, so it has the information to identify former tracking branches that have been fully merged. (After all, it can give youthe information that lets you do the operation by hand yourself.)

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

回答by karlingen

I found the answer here: How can I delete all git branches which have been merged?

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

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

Make sure we keep master

确保我们保持主人

You can ensure that master, or any other branch for that matter, doesn't get removed by adding another grepafter the first one. In that case you would go:

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

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

So if we wanted to keep master, developand stagingfor instance, we would go:

因此,如果我们想继续保持masterdevelopstaging举例来说,我们会去:

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

Make this an alias

将此设为别名

Since it's a bit long, you might want to add an alias to your .zshrcor .bashrc. Mine is called gbpurge(for git branches purge):

由于它有点长,您可能需要为您的.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'

Then reload your .bashrcor .zshrc:

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

. ~/.bashrc

or

或者

. ~/.zshrc

回答by chris31389

Windows Solution

视窗解决方案

For Microsoft Windows Powershell:

对于 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 | Select-String -Pattern ": gone]" | % { $_.toString().Trim().Split(" ")[0]} | % {git branch -d $_}

Explaination

说明

git checkout masterswitches to the master branch

git checkout master切换到主分支

git remote update origin --pruneprunes remote branches

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

git branch -vvgets a verbose output of all branches (git reference)

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

Select-String -Pattern ": gone]"gets only the records where they have been removed from remote.

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

% { $_.toString().Trim().Split(" ")[0]}get the branch name

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

% {git branch -d $_}deletes the branch

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

回答by Patrick Quirk

The pattern matching for "gone" in most of the other solutions was a little scary for me. To be safer, this uses the --formatflag to pull out each branch's upstream tracking status.

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

I needed a Windows-friendly version, so this deletes all branches that are listed as "gone" using Powershell:

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

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

The first line lists the name of local branches whose upstream branch is "gone". The next line removes blank lines (which are output for branches that aren't "gone"), then the branch name is passed to the command to delete the branch.

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

回答by cs01

Remove all branches that have been merged into master, but don't try to remove master itself:

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

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 --merged | grep master -v)

or add an alias:

或添加别名:

alias gitcleanlocal="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)"

Explanation:

解释:

git checkout mastercheckout master branch

git checkout master结帐主分支

git pull origin masterensure local branch has all remote changes merged

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

git fetch -premove references to remote branches that have been deleted

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

git branch -d $(git branch master --merged | grep master -v)delete all branches that have been merged into master, but don't try to remove master itself

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

回答by ckirksey3

git fetch -p

This will pruneany branches that no longer exist on the remote.

这将修剪远程上不再存在的任何分支。

回答by bxm

Yet-another-answer for the pile, drawing heavily from Patrick's answer(which I like because it seems to do away with any ambiguity about where gone]will match in the git branchoutput) but adding a *nix bent.

一堆的另一个答案,大量借鉴了帕特里克的答案(我喜欢它,因为它似乎消除了关于输出中gone]匹配位置的任何歧义git branch),但添加了 *nix 弯曲。

In its simplest form:

以其最简单的形式:

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

I have this wrapped up in a git-gonescript on my path:

我将它封装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 "" in
      (-[dD] | --delete) DELETE=true ;;
    esac
    shift
  done
  get_gone | action
}

main "${@}"

NB - The --formatoption seems to be fairly new; I needed to upgrade git from 2.10.something to 2.16.3 to get it.

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

EDIT: tweaked to include suggestion about refname:shortfrom Benjamin W.

编辑:调整以包含refname:short来自Benjamin W.

NB2 - I've only tested in bash, hence the hashbang, but probably portable to sh.

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