118

问题:我想要一种方法来删除我拥有的所有没有远程的本地分支。将分支的名称通过管道传输到 a 中很容易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>...]'

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

4

10 回答 10

136

我建议使用git branch --format来指定您想要的git 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

cut一旦你有了这个格式良好的输出,就很容易通过管道awk获取你的列表:

git branch -vv | cut -c 3- | awk '$3 !~/\[/ { print $1 }'
于 2015-08-02T20:24:57.230 回答
39

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

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

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

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

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

于 2013-03-27T15:02:36.627 回答
25

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

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

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

但是,如果您不想看到错误消息(实际上,谁会责怪您),那么您将需要其他东西来检查空管道。如果您可以使用ifne来自moreutils。您将插入ifnebefore xargs,它将停止xargs运行空数据。注意ifne认为任何内容都不为空,这包括空行,因此您可能仍会看到该错误消息。我没有在 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'
于 2016-01-23T22:31:57.510 回答
20

后期编辑:

更好的是

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

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

于 2013-03-27T23:02:45.330 回答
18

这对我有用:

git branch -vv | grep -v origin

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

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

于 2016-04-13T14:36:49.280 回答
12

我合成了自己的 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]'将只打印消失的远程分支。

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

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

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

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

于 2018-11-19T08:56:34.497 回答
2

这是我在 PowerShell 中使用的内容,并带有注释来解释它在做什么。为了弄清楚发生了什么,我没有使用任何缩写的 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
    }
}
于 2018-06-15T18:02:04.370 回答
1

此处投票最多的答案在我的系统上不起作用请参阅要点

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

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

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

于 2021-10-07T22:15:36.007 回答
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
于 2020-01-22T19:08:59.727 回答
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 独有或两者共有)

于 2020-12-18T18:48:45.977 回答