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

例子:

分支机构(本地和远程)

主人原始/主起源/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 branch --merged | grep -v "*" | grep -v "master" | xargs git branch -d

这将删除所有已从“源”引用的远程存储库中删除的分支,但仍在“远程/源”中本地可用。

git remote prune origin

其他回答

这里有一个解决方法,我用它来处理鱼壳。在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。

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

还有一个答案,因为没有一个解决方案符合我对优雅和跨平台的需求:

删除不在远程上的本地分支的命令:

for b in $(git for-each-ref --format='%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)' refs/heads); do git branch -d $b; done

要将其与gitconfig集成,以便可以使用git branch prune运行:

Bash

git config --global alias.branch-prune '!git fetch -p && for b in $(git for-each-ref --format='\''%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)'\'' refs/heads); do git branch -d $b; done'

PowerShell(PowerShell)

git config --global alias.branch-prune '!git fetch -p && for b in $(git for-each-ref --format=''%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)'' refs/heads); do git branch -d $b; done'

(需要帮助查找PowerShell和bash的通用命令)

为什么这个答案是最好的?

提供了一个完整的解决方案:向git添加一个git branch prune命令在Windows PowerShell中工作正常核心思想是@jason.rickman对每个裁判使用git的防弹方法分析和过滤是使用--filter完成的,因此不需要外部依赖项

说明:

在~\.gitconfig中添加新别名。执行此操作后,只需执行git分支修剪在此别名中:使用--prune标志获取分支,该标志“修剪不再位于远程的远程跟踪分支”对每个ref和--filter使用git,以获取分支列表(无远程)循环此列表并安全删除分支

这对我有用:

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

另一个答案,大量借鉴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。

因为有些答案不能防止意外删除

git fetch-p&&LANG=c git branch-vv|awk'/:gone]/&&/^\*/{print$1}‘|xargs git branch-d

过滤掉第一列中有*的分支是很重要的。