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

例子:

分支机构(本地和远程)

主人原始/主起源/bug-fix-a起源/bug-fix-b起源/bug-fix-c

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

分支机构(本地和远程)

主人bug-fix-abug-fix-b型原始/主起源/bug-fix-a起源/bug-fix-b起源/bug-fix-c

现在我有本地分支机构master,bug-fix-a,bug--fix-b。主分支维护者将把我的更改合并到主分支中,并删除他已经合并的所有分支。

因此,当前状态为:

分支机构(本地和远程)

主人bug-fix-abug-fix-b型原始/主起源/bug-fix-c

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

它类似于现有命令git remote prune origin,但更类似于git local prune origin。


当前回答

这将删除本地不存在的所有远程分支(在ruby中):

bs = `git branch`.split; bs2 = `git branch -r | grep origin`.split.reject { |b| bs.include?(b.split('/')[1..-1].join('/')) }; bs2.each { |b| puts `git  push origin --delete #{b.split('/')[1..-1].join('/')}` }

解释:

# local branches
bs = `git branch`.split
# remote branches
bs2 = `git branch -r | grep origin`.split
# reject the branches that are present locally (removes origin/ in front)
bs2.reject! { |b| bs.include?(b.split('/')[1..-1].join('/')) }
# deletes the branches (removes origin/ in front)
bs2.each { |b| puts `git  push origin --delete #{b.split('/')[1..-1].join('/')}` }

其他回答

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

$ 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结合了修剪和列出“goned”分支:

$ 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]”,其中$BRANCH通常是源代码。如果您的Git输出本地化为法语等,这可能不会起作用。Sebastian Wiesner还为Windows用户将其移植到Rust。那个也叫git gone。

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

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

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

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

git remote prune origin
git branch -d bug-fix-a bug-fix-b

使用脚本执行此操作的风险在此处解决:https://stackoverflow.com/a/47939403/4592031

另一个答案。

如果你正在寻找一些新奇的东西,这里是我在fzf中使用的别名。

LANG=C git for-each-ref --sort=-committerdate --format '%(refname:short) %(upstream:track)' refs/heads \
  | awk '$2 == "[gone]" {print $1}' \
  | fzf --multi --bind ctrl-a:select-all,ctrl-t:toggle-all \
        --preview='git log --color=always --graph --format=compact {1}' \
        --header='Select [gone] branch to remove' \
        --header-first --reverse \
  | xargs --no-run-if-empty git branch -d

解释:

强制LANG=C以避免[gone]模式上的本地化对每个引用使用git,以避免git分支中的任何格式更改使用awk过滤。我尝试使用--format=“%(if:equals=[gone])%…”,但这意味着要管理空行。使用fzf选择要删除的分支。添加快捷键:[ctrl-a]选择全部,[ctrl-t]反转选择([tab]照常选择)。您可以使用[enter]进行验证,也可以使用[esc]中止。我使用这个分支选择器作为确认阶段。在右侧显示所选分支的日志(以记住日期和内容…)。我使用下面列出的紧凑格式。您可以使用任何(不太宽)日志格式。--如果为空,则不运行。它不是强制性的,有助于避免在中止进程时出错(与没有分支名称的gitbranch-d相关)。

别名可能看起来很糟糕:

[alias]
      gone = "!f() { LANG=C git for-each-ref --sort=-committerdate --format '%(refname:short) %(upstream:track)' refs/heads | awk '$2 == \"[gone]\" {print $1}' | fzf --multi --bind ctrl-a:select-all,ctrl-t:toggle-all --preview='git log --color=always --graph --format=compact {1}' --header='Select [gone] branch to remove' --header-first --reverse | xargs --no-run-if-empty git branch -d ; }; f"
[pretty]
      compact = %Cred%h%Creset%C(auto)%d%Creset%n  Author: %an <%aE>%n  Date:  %cd%n     %s

(与上文相同,“)

看来每个人都有解决办法。好吧,如果你喜欢一个带有TUI(基于文本的用户界面)的交互式工具,我写了一个叫做gitxcleaner的工具。它可以找到合并的分支、重新基础的分支(使用相同的提交消息提交)、修剪的分支或手动选择的分支。

https://github.com/lzap/git-xcleaner