【问题标题】:List all local branches without a remote列出所有没有远程的本地分支
【发布时间】:2013-03-17 17:04:18
【问题描述】:

问题:我想要一种方法来删除我拥有的所有没有远程的本地分支。将分支的名称通过管道传输到 git branch -D {branch_name} 很容易,但我首先如何获得该列表?

例如:

我创建了一个没有遥控器的新分支:

$ git co -b no_upstream

我列出了我所有的分支,只有一个带有遥控器

$ git branch -a
master
* no_upstream
remotes/origin/HEAD -> origin/master
remotes/origin/master

我可以运行什么命令来得到no_upstream 作为答案?

我可以运行git rev-parse --abbrev-ref --symbolic-full-name @{u},这将表明它没有遥控器:

$ git rev-parse --abbrev-ref --symbolic-full-name @{u}
error: No upstream configured for branch 'no_upstream'
error: No upstream configured for branch 'no_upstream'
fatal: ambiguous argument '@{u}': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'

但由于这是一个错误,它不会让我使用它或将它传递给其他命令。我打算将其用作别名为git-delete-unbranched 的shell 脚本,或者制作一个超级简单的Gem,例如git-branch-delete-orphans

【问题讨论】:

标签: git git-remote


【解决方案1】:

我建议使用git branch --formatgit branch 命令中指定您想要的确切输出。通过这样做,您可以只提取 refname 和上游,如下所示:

git branch --format "%(refname:short) %(upstream)"

如果存在远程分支,它会输出分支以及远程分支,格式如下:

25-timeout-error-with-many-targets
31-target-suggestions refs/remotes/origin/31-target-suggestions
54-feedback-link refs/remotes/origin/54-feedback-link
65-digest-double-publish

一旦你有了这个格式良好的输出,就很容易通过awk 得到你的列表:

git branch --format "%(refname:short) %(upstream)" | awk '{if (!$2) print $1;}'

结果如下:

25-timeout-error-with-many-targets
65-digest-double-publish

如果没有第二列,awk 部分将打印第一列。

奖励:创建别名

通过在您的全局 .gitconfig 文件(或任何位置)中创建别名来轻松运行:

[alias]
  local-branches = "!git branch --format '%(refname:short) %(upstream:short)' | awk '{if (!$2) print $1;}'"

奖励:远程过滤

如果由于某种原因您有多个用于不同分支的跟踪遥控器,那么指定要检查的遥控器就很容易了。只需将远程名称添加到 awk 模式即可。就我而言,它是origin,所以我可以这样做:

git branch --format "%(refname:short) %(upstream)" | awk '$2 !~/\/origin\// { print $1 }'

重要提示:反斜杠需要在别名中转义,否则您将获得无效的 gitconfig 文件。


上一个答案

先前的答案在功能上相似,但使用以下作为起点。随着时间的推移,评论者指出,由于提交消息中可能存在差异,正则表达式是不可靠的,所以我不再推荐这种方法。但是,这里仅供参考:

我最近发现了git branch -vv,这是git branch 命令的“非常冗长”版本。

如果存在远程分支,它会输出分支以及远程分支,格式如下:

  25-timeout-error-with-many-targets    206a5fa WIP: batch insert
  31-target-suggestions                 f5bdce6 [origin/31-target-suggestions] Create target suggestion for team and list on save
* 54-feedback-link                      b98e97c [origin/54-feedback-link] WIP: Feedback link in mail
  65-digest-double-publish              2de4150 WIP: publishing-state

一旦你有了这个格式良好的输出,就很容易通过cutawk 得到你的列表:

git branch -vv | cut -c 3- | awk '$3 !~/\[/ { print $1 }'

【讨论】:

  • WIP: 到底是什么..?这不是 stash 命令创建的内容吗?
  • @igrek 这只是我在提交消息中使用的前缀。没有特定于 git 的内容。
  • 当我执行git branch -vv 时,即使存在远程分支并且与我的本地分支匹配,我也不会在结果旁边看到[origin/branch-name]。我必须diff 两个分支列表才能真正弄清楚什么是本地的。
  • git branch -vv | grep -v origin/ 对我来说已经足够了
  • 这不会错过标记为gone的远程分支吗?
【解决方案2】:

git branch(没有任何选项)仅列出本地分支,但您不知道它们是否正在跟踪远程分支。

通常这些本地分支在合并到master 后应该被删除(如this issue of git-sweep 所示):

git branch --no-contains master --merged master | xargs git branch -d

这并不像你想要的那样完整,但它是一个开始。

使用--merged,只会列出合并到命名提交的分支(即可以从命名提交访问其提示提交的分支)。

【讨论】:

  • 如果还包括没有本地分支的远程分支,请使用git branch -a --merged
【解决方案3】:

我也有类似的问题。我想删除所有跟踪现在已删除的远程分支的本地分支。我发现git remote prune origin 不足以删除我想要的分支。删除遥控器后,我希望本地也消失。这对我有用:

来自我的~/.gitconfig

[alias]
  prune-branches = !git remote prune origin && git branch -vv | grep ': gone]' | awk '{print $1}' | xargs -r git branch -d

这是一个git config --global ... 命令,可以轻松地将其添加为git prune-branches

git config --global alias.prune-branches '!git remote prune origin && git branch -vv | grep '"'"': gone]'"'"' | awk '"'"'{print $1}'"'"' | xargs -r git branch -d'

注意:我在实际配置中将-d 更改为-D,因为我不想听到Git 抱怨未合并的分支。您可能也需要此功能。如果是这样,只需在该命令末尾使用-D 而不是-d

另外,FWIW,您的全局配置文件几乎总是~/.gitconfig

(OS X 修复)

正如所写,由于使用了xargs -r,这在 OS X 上不起作用(感谢Korny)。

-r 是为了防止xargs 在没有分支名称的情况下运行git branch -d,这将导致错误消息“fatal: branch name required”。如果您不介意错误消息,只需将 -r 参数删除到 xargs 即可。

但是,如果您不想看到错误消息(实际上,谁会责怪您),那么您将需要其他东西来检查空管道。如果您可以使用来自moreutilsifne。您将在xargs 之前插入ifne,这将阻止xargs 以空数据运行。 注意ifne 认为 anything 不为空,这包括空行,因此您可能仍会看到该错误消息。我没有在 OS X 上测试过。

这是git configifne 的行:

git config --global alias.prune-branches '!git remote prune origin && git branch -vv | grep '"'"': gone]'"'"' | awk '"'"'{print $1}'"'"' | ifne xargs git branch -d'

【讨论】:

  • 是否可以将其转换为“git config --global...”命令?从指令/how-to-wiki-for-dummies 的角度来看,它很容易传递,而不是说“找出你的 git 配置文件,使用编辑器编辑它然后运行命令”
  • 很高兴知道。我不知道 OSX 的“空时不运行”选项是什么。
【解决方案4】:

后期编辑:

更好的是

git for-each-ref  --format='%(refname:short) %(upstream)'  refs/heads \
| awk '$2 !~/^refs\/remotes/'

在 GNU/任何东西上

for b in `git branch|sed s,..,,`; do
    git config --get branch.$b.remote|sed Q1 && echo git branch -D $b
done

如果可能有多个分支,会有更好的方法,在git branch|sed|sortgit config -l|sed|sort 的输出上使用comm -23

【讨论】:

  • @nmr s/git.*Q1/test $(git config --get branch.$b.remote|sed q|wc -1) = 1/
【解决方案5】:

这对我有用:

git branch -vv | grep -v origin

(如果您的遥控器被命名为 origin 以外的任何名称,请替换它)。

这将列出所有未跟踪遥控器的分支,这听起来像您要查找的内容。

【讨论】:

  • 这将列出曾经有远程但现在没有远程的分支,即使你运行git fetch --prune
  • IMO,最好寻找“:gone]”而不是过滤掉“origin”
【解决方案6】:

我合成自己的 Git 命令来获取 origin/***: gone 分支:

git remote prune origin && git branch -vv | cut -c 3- | grep ': gone]' | awk '{print $1}' | xargs -n1 -r echo git branch -d

git remote prune origin &amp;&amp; git branch -vv 将以详细模式打印分支。

cut -c 3- 将删除第一个字符。

grep ': gone]' 将只打印 gone 远程分支。

awk '{print $1}' 将打印分支名称。

xargs -n1 -r echo git branch -d 将打印git branch -d 命令以删除分支(-n1 将每次管理一个命令,-r 将在不存在分支时避免发出命令)。

提示:删除“echo”命令以运行命令而不是仅打印,我将其留在命令中以在发出到 git 之前检查命令。 p>

提示 2: 问题 git branch -D 当且仅当您确定要删除未合并的分支时

【讨论】:

  • 从这里我做了我个人的git gone
  • 这是到目前为止我找到的最干净的解决方案,很好!我从来没有花时间研究awk,我不知道你能做到。
  • 这是唯一一个为我获得所有已合并、删除或本地其他分支的分支。
【解决方案7】:

这是我在 PowerShell 中使用 cmets 来解释它在做什么的东西。为了弄清楚发生了什么,我没有使用任何缩写的 PowerShell 命令(别名)。随意将其压缩到您想要的神秘程度:)

$verboseList = @(git branch -vv)
foreach ($line in $verboseList)
{
    # Get the branch name
    $branch = [regex]::Match($line, "\s(\S+)\s").Captures.Groups[1].Value
    # Check if the line contains text to indicate if the remote is deleted
    $remoteGone = $line.Contains(": gone]")
    # Check if the line does not contain text to indicate it is a tracking branch (i.e., it's local)
    $isLocal = !($line.Contains("[origin/"))
    if ($remoteGone -or $isLocal)
    {
        # Print the branch name
        $branch
    }
}

【讨论】:

    【解决方案8】:

    这里投票最多的答案在我的系统上不起作用,请参阅gist

    以下内容确实有效并且相当干净。

    git branch -v | awk '$3 == "[gone]" { print $1 }' | xargs git branch -D
    

    如果您不想删除未合并的分支,请使用 -d。

    【讨论】:

    • 这行得通。小提示:如果你使用'squash merge',你需要使用-D,因为分支在技术上是不合并的。
    【解决方案9】:

    结合一些现有的答案:

    [alias]
            branch-local = !git branch -vv | cut -c 3- | egrep '([0-9a-f]{7} [^[])|(: gone\\])' | sed -E 's/(^.+[0-9a-f]{7} (\\[.+\\])?).*$/\\1/'
    

    例如:

    $ git branch-local
    autogen_autoreconf      fcfb1c6 [github/autogen_autoreconf: gone]
    autotools_documentation 72dc477 [github/autotools_documentation: gone]
    cray-mpich-messy        2196f4b
    epel-sphinx             cfda770
    lammps                  07d96a7 [github/lammps: gone]
    lark-error              9ab5d6c [github/lark-error: gone]
    no-root2                c3894d1
    openmpi-cray            69326cf [github/openmpi-cray: gone]
    shellcheck-cleanup      40d90ec
    travis-python36         cde072e
    update_vagrant_default  4f69f47 [github/update_vagrant_default: gone]
    web-docs                e73b4a8
    

    【讨论】:

      【解决方案10】:

      现有的答案似乎都不适合我。

      这是我列出并非远程的本地分支的解决方案

      comm -13 <(git branch -r | sed 's/origin\/\(.*\)/\1/g' | cut -c 3-) <(git branch | cut -c 3-)
      

      下面是它如何工作的解释:

      1. 考虑所有远程分支的列表(没有'origin/'或前导空格) git branch -r | sed 's/origin\/\(.*\)/\1/g' | cut -c 3-

      2. 考虑所有本地分支的列表(没有星号或前导空格) git branch | cut -c 3-

      3. 比较这两个列表并显示列表 2(我的本地分支)中不在列表 1(远程分支列表)中的任何内容 comm -13 &lt;(git branch -r | sed 's/origin\/\(.*\)/\1/g' | cut -c 3-) &lt;(git branch | cut -c 3-)

      comm 可以采用标志 -1、-2 和 -3 的组合,表示 从哪个文件中抑制行(文件 1 独有,文件 2 独有 或两者共同)

      【讨论】:

        猜你喜欢
        • 2023-01-07
        • 2018-04-27
        • 2010-09-27
        • 2022-11-05
        • 2014-06-09
        • 1970-01-01
        • 2013-04-30
        • 2020-06-11
        • 2013-03-21
        相关资源
        最近更新 更多