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

例子:

分支机构(本地和远程)

主人原始/主起源/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。


当前回答

我不确定要用多久,但我现在确实使用git-up,这可以解决这个问题。

我做了git,它开始跟踪新的分支并删除旧的分支。

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

顺便说一句,它还藏着脏树,只需把它捡起来就可以重新放回原处。

希望对某人有用

其他回答

虽然上面的答案涵盖了如何手动修剪树枝,但这个答案增加了解决这一问题的自动化。git现在有了一个新设置,可以在每次提取操作中删除不再位于远程的过时分支。这很好,因为我们不再需要在每次删除分支时手动调用远程prune(git pull也调用git fetch)。

为每次提取启用修剪行为

要在全局配置中启用此功能,请执行以下操作:

git config --global fetch.prune true

让事情自动发生意味着你可以忘记在新机器上添加此设置。它只是起作用。

对特定远程设备上的每次提取启用修剪行为

git config --global remote.<name>.prune true

本地自动修剪

我们也可以在不使用--global标志的情况下对局部修剪应用相同的命令。

.git配置

上面的命令适用于global和local.gitconfig,如下所示:

...
[fetch]
    prune = true

我可以建议将其添加到一个可靠的配置中或添加到您的dotfiles存储库(.gitconfig)中,以便将来自动进行设置。

配置设置在每次提取时调用以下命令:

git remote prune <remote name>

总结

要将引用作为正常工作流的一部分进行删减而不需要记住运行,请全局或远程设置fetch.prune<name>.在配置中对每个远程进行修剪。请参阅git-config。

另一个答案,大量借鉴Patrick的答案(我喜欢这个答案,因为它似乎消除了任何关于去哪儿的歧义),将在git分支输出中匹配),但添加了*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才能获得它。

编辑:修改为包含参考名的建议:来自Benjamin W。

NB2-我只在bash中进行了测试,因此有了hashbang,但可能可以移植到sh。

这里有一个解决方法,我用它来处理鱼壳。在Mac OS X 10.11.5、fish 2.3.0和git 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\|\*\)”。它确保您不会删除主分支或基本分支。

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

一种简单的测试方法是用echo“将删除$f”替换gitbranch-d$f。

我想我还应该补充一句:使用风险自负!

这将删除本地不存在的所有远程分支(在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('/')}` }

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

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

有些答案很简单,但他们没有按照要求做。其他人按照要求做,但并不简单:所有人都依赖于通过文本操作命令或脚本语言解析Git输出,这可能不是每个系统都有的。除此之外,大多数建议都使用瓷命令,其输出不被脚本解析(“瓷”是指用于人类操作的命令;脚本应该使用较低级别的“管道”命令)。

进一步阅读:

为什么不应该在脚本中解析git分支输出。跟踪分支以及git remote prune、git prune和git fetch--prune之间的差异


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

git fetch--prune(或git fetch-p,它是一个别名,或git prune remote origin,它在不获取的情况下执行相同的操作,并且可能不是您大多数时候想要的)。注意报告为已删除的任何远程分支。或者,为了稍后找到它们,可以使用gitbranch-v(任何孤立的跟踪分支都将标记为“[gone]”)。每个孤立跟踪分支上的gitbranch-d[分支名称]

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

如果你想编写一个解决方案的脚本,那么每个ref都是你的出发点,就像Mark Longair在这里的回答和对另一个问题的回答一样,但我看不出不编写shell脚本循环或使用xargs之类的方法来利用它。


背景说明

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

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

有时,有人删除了遥控器上的功能/X。从那一刻起,您就剩下了本地功能/X(您可能不想再使用它了,因为功能X的工作大概已经完成了)和远程/原点/功能/X,这肯定是无用的,因为它的唯一目的是记住服务器分支的状态。

Git将允许您自动清理冗余的remotes/origin/feature/X,这就是gitfetch-prime所做的,但由于某些原因,它不允许您自动删除自己的功能/X。。。即使您的feature/X仍然包含孤立的跟踪信息,因此它具有识别已完全合并的前跟踪分支的信息。(毕竟,它可以为您提供信息,让您自己动手操作。)