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

例子:

分支机构(本地和远程)

主人原始/主起源/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 remote prune origin

然后运行:

diff <(git branch | sed -e 's/*/ /g') <(git branch -r | sed -e 's/origin\///g') | grep '^<'

这将显示所有不在(gitbranch-r)而是在(git branch)中的分支

此方法有一个问题,它还将在本地显示以前未推送的分支

其他回答

我使用了一个简短的方法来完成这项任务,我建议你也这样做,因为这样可以节省一些时间,并提高你的可见度

只需将以下代码段添加到.bashrc(macos上的.bashprofile)中。

git-cleaner() { git fetch --all --prune && git branch --merged | grep -v -E "\bmaster|preprod|dmz\b" | xargs -n 1 git branch -d ;};

获取所有遥控器仅从git中获取合并的分支从此列表中删除“受保护/重要”分支删除其余部分(例如,清理和合并的分支)

您必须编辑grep正则表达式以满足您的需要(这里,它防止删除master、prepod和dmz)

最安全的方法是对每个ref使用带有插值变量%(upstream:track)的“管道”命令git,当分支不再位于远程时,该变量将消失:

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

这种方法比使用“瓷”命令更安全,因为不会有意外匹配提交消息部分的风险。下面是一个使用“瓷”git命令的版本:

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

这种工作方式是在命令之后

git fetch -p

运行时删除远程引用

git branch -vv

它将显示“已离开”作为远程状态。例如

$ 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

这是脚本迭代的内容。

列出远程分支现在已消失的所有本地分支

#!/bin/sh
LC_ALL=C git for-each-ref --format='%(refname:short) %(upstream:track)' refs/heads/ |\
    sed -n '/ *\[gone\].*$/{s@@@;p}'

然后通过管道将其导入xargs git分支-D或-D。

此解决方案应与POSIX兼容。没有特定于shell的东西,只有POSIX兼容的sed/xargs。

LC_ALL=C通过强制英语使脚本语言保持中立对于每个引用,使用管道命令--format='%(refname:short)%(upstream:track)输出分支名称跟踪信息参考/仅负责本地分支机构sed-n'/*\[gone\].*$/匹配跟踪信息[gone],该信息不是有效分支名称的一部分,因此无需担心{s@@@;p}删除跟踪部分并仅打印这些行

nb:分支不能包含空格,因此我们不需要对xargs进行任何清理。

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

我已经用GitPython编写了一个Python脚本来删除远程不存在的本地分支。

    import git
    import subprocess
    from git.exc import GitCommandError
    import os

    def delete_merged_branches():
        current_dir = input("Enter repository directory:")
        repo = git.Repo(current_dir)
        git_command = git.Git(current_dir)

        # fetch the remote with prune, this will delete the remote references in local.
        for remote in repo.remotes:
            remote.fetch(prune=True)
        
        local_branches = [branch.name for branch in repo.branches]
        deleted_branches = []

        # deleted_branches are the branches which are deleted on remote but exists on local.
        for branch in local_branches:
            try:
                remote_name = 'origin/'+ branch
                repo.git.checkout(remote_name)
            except GitCommandError:
            # if the remote reference is not present, it means the branch is deleted on remote.
                deleted_branches.append(branch)
            
        for branch in deleted_branches:
            print("Deleting branch:"+branch)
            git_command.execute(["git", "branch", "-D",branch])

    
        # clean up the work flow.
        repo.git.checkout('master')
        repo.git.pull()

    if __name__ == '__main__':
        delete_merged_branches()

希望有人觉得它有用,如果我错过了什么,请添加评论。