列出没有遥控器的所有本地分支

时间:2013-03-27 14:48:36

标签: git git-remote

问题:我想要一种删除没有遥控器的所有本地分支的方法。将分支的名称输入git branch -D {branch_name}很容易,但我如何首先获得该列表?

例如:

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

$ git co -b no_upstream

我列出了所有分支,只有1个远程

$ 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

任何帮助将不胜感激!感谢

10 个答案:

答案 0 :(得分:75)

我最近发现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 }'

结果如下:

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

cut部分只是通过从输出中删除前两个字符(包括*)来规范化数据,然后再将其传递给awk

如果第三列中没有方括号,awk部分将打印第一列。

加分:创建别名

通过在全局.gitconfig文件(或任何地方)中创建别名,让您轻松运行:

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

重要说明:反斜杠需要在别名中进行转义,否则您将拥有无效的gitconfig文件。

奖励:远程过滤

如果出于某种原因,您有不同分支的多个跟踪遥控器,则可以轻松指定要检查的遥控器。只需将远程名称附加到awk模式即可。在我的情况下,它是origin所以我可以这样做:

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

答案 1 :(得分:26)

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

通常,这些本地分支一旦合并到master就会被删除(如this issue of git-sweep所示):

git branch --merged master | grep -v master | xargs git branch -d

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

  

使用--merged,只会将分支合并到命名提交中(即,可以从命名提交到达提示提交的分支)。

答案 2 :(得分:16)

我有类似的问题。我想删除所有跟踪现在已删除的远程分支的本地分支。我发现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

编辑:(OSX修复) 如上所述,由于使用xargs -r(感谢,Korny),这在OSX上不起作用。

-r是为了防止xargs运行git branch -d而没有分支名称,这将导致错误消息&#34; fatal: branch name required&#34;。如果您不介意错误消息,则只需将-r参数移至xargs,即可完成所有设置。

但是,如果您不想看到错误消息(实际上,谁可能会责怪您),那么您还需要其他能够检查空管道的内容。如果您可以使用ifne中的moreutils。您可以在ifne之前插入xargs,这将阻止xargs使用空数据运行。 注意ifne认为任何不为空,这包括空行,因此您仍可能看到该错误消息。我没有在OSX上测试过这个。

以下git config行与ifne

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

答案 3 :(得分:15)

延迟编辑:更好的是

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

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

答案 4 :(得分:11)

这对我有用:

git branch -vv | grep -v origin

(如果您的遥控器被命名为原点以外的其他任何东西,请替换它。)

这将列出所有不跟踪遥控器的分支机构,这听起来就像您正在寻找的那样。

答案 5 :(得分:2)

粗糙的powershell实现:(如果origin是你唯一的远程)

@($branches = git br -r; git branch | %{ echo $_ | sed 's/..//' }) `
   | %{ if (($branches | ss "origin/$_") -eq $null) { `
          echo "git branch -D $_" `
        } `
      }

答案 6 :(得分:2)

这是我在PowerShell中使用的一些注释,用于解释它正在做什么。为了弄清楚发生了什么,我没有使用任何缩写的PS命令。随意将其压缩到您想要的神秘程度:)

$verboseList = @(git br -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
    }
}

答案 7 :(得分:0)

我合成自己的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 && 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之前将其留在命令中以检查命令。

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

答案 8 :(得分:0)

结合一些现有答案:

[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

答案 9 :(得分:0)

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

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

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 <(git branch -r | sed 's/origin\/\(.*\)/\1/g' | cut -c 3-) <(git branch | cut -c 3-)

<块引用>

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