问题:我想要一种删除没有遥控器的所有本地分支的方法。将分支的名称输入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
任何帮助将不胜感激!感谢
答案 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
一旦你有了这个格式良好的输出,它就像通过cut
和awk
一样轻松获取你的清单:
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 -23
和git 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-)
这里解释了它是如何工作的:
考虑所有远程分支的列表(没有'origin/'或前导空格)
git branch -r | sed 's/origin\/\(.*\)/\1/g' | cut -c 3-
考虑所有本地分支的列表(没有星号或前导空格)
git branch | cut -c 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 唯一 或两者通用)