列出所有没有远程控制的本地分支

问题: 我想要一种方法来删除所有本地分支,我有没有一个远程。将分支的名称通过管道输入到 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

58977 次浏览

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

通常,这些本地分支一旦合并到 master中就应该被删除(如 这期的 Git 扫描所示) :

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

虽然没有你想的那么完整,但也算是个开始。

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

后期编辑:

最好是

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

我建议使用 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

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

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

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

如前所述,由于使用了 xargs -r(谢谢,科尼) ,这在 OS X 上无法工作。

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

但是,如果您不希望看到错误消息(实际上,谁会责怪您呢) ,那么您将需要其他一些东西来检查一个空管道。如果你可以从 Moreutils中使用 很好。您将在 xargs之前插入 ifne,这将阻止 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'

这对我有用:

git branch -vv | grep -v origin

(如果您的遥控器的名称不是原点,请替换它)。

这将列出所有没有跟踪远程的分支,这听起来像是您正在寻找的。

以下是我在 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
}
}

我合成了自己的 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

结合现有的几个答案:

[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

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

下面是列出不同于远程的本地分支的解决方案

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

下面是它的工作原理:

  1. 考虑所有远程分支的列表(不包括“ source/”或前导空格) 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唯一) 或两者共有)

这里投票最多的答案不在我的系统上工作,见 大意

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

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

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