删除所有本地git分支


323

我遵循一个开发过程,在其中为每个新功能或故事卡创建一个新的本地分支。完成后,我将分支合并到master中,然后进行推送。

由于懒惰或健忘的组合,随着时间的流逝往往会发生的事情是,我最终得到了大量本地分支,其中一些分支(例如尖峰)可能没有合并。

我知道如何列出所有本地分支,也知道如何删除单个分支,但是我想知道是否有git命令可以删除所有本地分支?

下面是git branch --merged命令的输出。

user@machine:~/projects/application[master]$ git branch --merged
  STORY-123-Short-Description
  STORY-456-Another-Description
  STORY-789-Blah-Blah
* master

所有尝试删除列出的分支的尝试grep -v \*(按照下面的答案)都会导致错误:

error: branch 'STORY-123-Short-Description' not found.
error: branch 'STORY-456-Another-Description' not found.
error: branch 'STORY-789-Blah-Blah' not found.

我正在使用:
git 1.7.4.1
ubuntu 10.04
GNU bash,版本4.1.5(1)-
发布GNU grep 2.5.4


7
我求你接受@Andrew的回答!
罗伯特·西默


@GiulioCaccin该问题还与可能尚未合并的分支有关,我已经更新了该问题以明确反映这一点。
Louth

Answers:


384

'git branch -d'子命令可以删除多个分支。因此,简化@sblom的答案,但添加一个关键的xargs:

git branch -D `git branch --merged | grep -v \* | xargs`

或者进一步简化为:

git branch --merged | grep -v \* | xargs git branch -D 

重要的是,如@AndrewC所述,git branch不建议将其用于脚本。为了避免这种情况,请使用以下方法:

git for-each-ref --format '%(refname:short)' refs/heads | grep -v master | xargs git branch -D

删除时必须小心!

$ mkdir br
$ cd br; git init
Initialized empty Git repository in /Users/ebg/test/br/.git/
$ touch README; git add README; git commit -m 'First commit'
[master (root-commit) 1d738b5] First commit
 0 files changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 README
$ git branch Story-123-a
$ git branch Story-123-b
$ git branch Story-123-c
$ git branch --merged
  Story-123-a
  Story-123-b
  Story-123-c
* master
$ git branch --merged | grep -v \* | xargs
Story-123-a Story-123-b Story-123-c
$ git branch --merged | grep -v \* | xargs git branch -D
Deleted branch Story-123-a (was 1d738b5).
Deleted branch Story-123-b (was 1d738b5).
Deleted branch Story-123-c (was 1d738b5).

该命令仍然报告与以下答案的注释中提到的错误相同的错误。error:branch 'STORY-123-Short-Description' not found.对于列出的每个分支。
Louth

1
为我工作;请参阅上面的详细信息。
GoZoner

1
那么,使用git 1.7.10是否解决了您的问题,还是您更喜欢直接在.git存储库中工作?
GoZoner

1
如果出现error:branch 'STORY-123-Short-Description' not found.错误,可能是由于git color设置。这对我--no-colorgit branch --no-color --merged | grep -v \* | xargs git branch -D
有用

3
因此,我找到了唯一的答案。谢谢!
凯文·萨特尔

140

在github上对此问题的评论中找到了一种更好的方法:

git branch --merged master --no-color | grep -v master | grep -v stable | xargs git branch -d

编辑:添加了无颜色选项并排除了稳定分支(根据需要添加其他分支)


2
最后,我一直需要的解决方案
Code Whisperer 2013年

1
我已经尝试过了,但是error: branch 'my-branch-name' not found.每个分支都在努力。使用git版本1.8.3.4(Apple Git-47)。知道为什么吗?
wheresrhys 2014年

尝试'git branch --merged master | grep -v大师| xargs echo'调试它到底想删除什么?没有更好的主意...
mBardos 2014年

2
所以。git for-each-ref --format '%(refname:short)' refs/heads/ | grep -v master | xargs git branch -d
ПавелТявин

1
一起学习了xargs的用法。谢谢
Volem '17

105

git branch不建议解析的输出,这对于以后使用Stack Overflow的读者来说不是一个很好的答案。

  1. git branch这就是所谓的瓷器命令。瓷器命令并非设计用于机器解析,并且输出可能会在不同版本的Git之间改变。
  2. 有一些用户配置选项会以git branch难以解析的方式更改输出(例如,着色)。如果用户已设置,color.branch那么您将在输出中获得控制代码,这将导致error: branch 'foo' not found.您尝试将其通过管道传递到另一个命令中。您可以使用--no-color标志来绕过此操作git branch,但是谁知道其他用户配置可能会破坏事情。
  3. git branch 可能会执行其他烦人的解析操作,例如在当前检出的分支旁边放置一个星号

git维护者有话要说关于git branch输出的脚本

为了找出当前分支是什么,临时/粗心的用户可能在git分支周围编写了脚本,这是错误的。我们积极反对在脚本中使用任何瓷器命令,包括git branch,因为该命令的输出可能会发生变化,以帮助人类消费用例。

建议手动编辑目录中的.git文件(如.git / refs / heads)的答案也同样存在问题(refs可能位于.git / packed-refs中,或者Git将来可能会更改其内部布局)。

Git提供了for-each-ref检索分支列表的命令。

Git 2.7.X将引入的--merged选项,因此您可以执行以下操作来查找和删除所有合并到的分支HEAD

for mergedBranch in $(git for-each-ref --format '%(refname:short)' --merged HEAD refs/heads/)
do
    git branch -d ${mergedBranch}
done

在Git 2.6.X及更早版本的Git中,您将需要列出所有本地分支,然后分别对其进行测试,以查看它们是否已合并(这将显着降低速度并变得更加复杂)。

for branch in $(git for-each-ref --format '%(refname:short)' refs/heads/)
do
    git merge-base --is-ancestor ${branch} HEAD && git branch -d ${branch}
done

git branch --no-color 2>/dev/null
nobar 2014年

5
肯定是一个改进。您总是会遇到需要过滤*的问题,而且如果有人从分离的头上运行它,它的确很有趣。但是主要的问题是git branch瓷器命令,并且不能保证在将来的git版本中输出不会改变。
Andrew C

谢谢@AndrewC-这既可以回答神秘的“未找到分支”错误,又可以使用更适当的命令提供有效的解决方案!👍–
杰森

2
如何识别“瓷器”和“非瓷器” GIT命令?
GoZoner

1
默认情况下排除“ dev”和“ master”是否可能是有用的增强功能?
PandaWood '17

65

删除所有分支但保留诸如“ develop”和“ master”之类的其他分支的更简单方法如下:

git branch | grep -v "develop" | grep -v "master" | xargs git branch -D

很有用 !


8
您已经恢复了一个古老的线程,并为现有的线程发布了几乎相同的答案,这是有问题的,并且缺少它的安全性更改。这不是一个好答案。
安德鲁C

6
从git分支管道输出,对其进行修改并传递给git分支-D时,此答案很清楚。不必刻薄。
2015年

这个解决方案对我有用。删除所有本地分支。
普拉德

1
这不会删除任何包含单词develop或master的分支,例如“ develop_feature”或“ master_feature”。
django,

这是我正在寻找的答案
Konrad G

62

要删除除当前已签出的分支以外的所有分支:

for b in `git branch --merged | grep -v \*`; do git branch -D $b; done

我建议更改git branch -D $becho $b头几次,以确保它删除了您想要的分支。


1
使用此命令,我error:branch 'a_branch_name' not found.可以看到您要执行的操作,并且一直在使用该命令,但是由于某些原因,git似乎不喜欢提供的分支名称...
Louth,2012年

嗯。为帮助进行故障排除,请查看git branch --merged
sblom 2012年

我的分支名称格式为STORY-123-Short-Description
Louth,2012年

当您运行时git branch --merged,会得到一个列表,其中每行都有一个?
2012年

1
从字面上说error:branch 'a_branch_name' not found.吗?还是它抱怨git branch上面输出中的分支名称之一?
2012年

52

以下命令将删除除master分支外的所有本地分支。

git branch | grep -v "master" | xargs git branch -D

上面的命令

  1. 列出所有分支
  2. 从列表中忽略主分支,并选择其余分支
  3. 删除分支

4
git branch | grep -v "master" | xargs git branch -d为了安全起见,我会先使用它,以便不删除未合并的分支。但是很好的答案!
乔纳斯·洛姆霍尔特

3
这是一个功能,@(git branch | Select-String -Pattern "[^(*?)\s? master]") | ForEach-Object{$_.Line.Trim()} | %{git branch -D $_}
强大的

1
@baklazan,如果您安装了一些工具,则仅在Windows 10命令行中有效。您可能有MINGW或其他类似的东西,但您不知道。
KthProg

42

请注意,我将升级到git 1.7.10。您可能会在这里获得不适用于您的版本的答案。我的猜测是,您必须在分支名称前添加refs/heads/

注意,仅当您复制了工作文件夹和.git目录时,才进行以下操作。

有时我只是继续删除不需要的分支.git/refs/heads。所有这些分支都是文本文件,包含指向它们的提交的40个字符的sha-1。.git/config如果您为其中任何一个设置了特定的跟踪,则将获得无关的信息。您也可以手动删除这些条目。


最后是一个简单实用的选择。我喜欢:D
Melvyn 2015年

2
如果您具有打包的引用,或者即使您有时是从远程服务器克隆的(这将为您提供打包的文件),这将不起作用。如果您的裁判是打包的,那么裁判将不会存储在.git / refs / heads中,而是会存储在一个名为“ packed-refs”的文件中。看到git-scm.com/docs/git-pack-refs
亚历山大·伯德

1
删除您目前已签出的分支似乎是个坏主意
Moberg

@Moberg只需预先签出一个提交,然后您分离的HEAD就会浮动。
RomainValeri

34

尝试以下shell命令:

git branch | grep -v "master" | xargs git branch -D

说明:

  • via通过git branch | grep -v "master"命令获取所有分支
  • with用xargs命令选择每个分支
  • with用 xargs git branch -D

3
尽管这可能是正确的答案。如果没有解释什么以及如何解决原始问题,那么一行代码不是很有用。请提供您的答案的详细信息。
RyanNerd


25

我发现仅使用文本编辑器和Shell会更容易。

  1. 键入git checkout <TAB>壳。将显示所有本地分支机构。
  2. 将它们复制到文本编辑器,删除您需要保留的那些。
  3. 用空格替换换行符。(在SublimeText中,这非常容易。)
  4. 打开外壳,键入git branch -D <PASTE THE BRANCHES NAMES HERE>

而已。


我认为您无法删除所站的分支。
东同'18

@Dong在该分支旁边有一个*,因此您只需将其从复制的列表中删除即可!
媚兰

12

我有类似的情况,最近发现以下命令很有用。

git branch -D `git branch | awk '{ if ($0 !~ /<Branch_You_Want_to_Keep>/) printf "%s", $0 }'`

如果要保留多个分支,则

git branch -D `git branch | awk '{ if ($0 !~ /<Branch_You_Want_to_Keep1>|<Branch_You_Want_to_Keep2>/) printf "%s", $0 }'`

希望这对某人有帮助。


1
不错,但我需要反引号才能使它正常工作- git branch -D `git branch | awk '{ if ($0 !~ /master/) printf "%s", $0 }'` 实际上,我认为您最初确实有它们,但是它们在SO格式中迷失了。
tassinari 2014年

10

在Windows命令行中,使用以下命令删除除当前已检出分支以外的所有内容:

for /f "tokens=*" %f in ('git branch ^| find /v "*"') do git branch -D %f

7

如果您不需要自己遍历Git,也可以手动或以编程方式删除.git / refs / heads下的heads。以下应该在Bash下进行最少的调整即可工作:

shopt -s extglob
rm -rf .git/refs/heads/!(master)

这将删除除您的主分支外的每个本地分支。由于您的上游分支存储在.git / refs / remotes下,因此它们将保持不变。

如果您不使用Bash,或者想一次递归很多Git存储库,则可以使用GNU find做类似的事情:

find . \
    -path remotes -path logs -prune -o \
    -wholename \*.git/refs/heads/\* \! -name master -print0 |
xargs -0 rm -rf

查找解决方案可能更易于移植,但是修剪路径和文件名比较棘手,并且可能更容易出错。


凉。可视删除:)
sandalone

5

没有一个答案可以完全满足我的需求,因此我们开始:

git branch --merged | grep -E "(feature|bugfix|hotfix)/" | xargs git branch -D && git remote prune origin

这将删除其合并,并与开始的所有地方分公司feature/bugfix/hotfix/。之后,上游遥控器将origin被修剪(您可能必须输入密码)。

适用于Git 1.9.5。


5

根据此处的多个答案的组合-如果您想保留远程存在的所有分支但删除其余分支,则以下oneliner可以解决问题:

git for-each-ref --format '%(refname:short)' refs/heads | grep -Ev `git ls-remote --quiet --heads origin | awk '{print substr($2, 12)}'| paste -sd "|" -` | xargs git branch -D

3

尽管这不是命令行解决方案,但令我惊讶的是还没有建议使用Git GUI

我99%的时间都使用命令行,但是在这种情况下,它要么变慢(因此出现原始问题),要么您不知道在诉诸于冗长而巧妙的shell操作时要删除的内容。

UI可以解决此问题,因为您可以快速检查要删除的分支,并提醒您要保留的分支,而不必为每个分支键入命令。

从用户界面转到分支->删除,然后按住Ctrl键单击要删除的分支,使其突出显示。如果要确保将它们合并到一个分支中(例如dev),请在“ 仅当合并到一起删除时”下将“ 本地分支”设置为dev。否则,将其设置为“ 始终”以忽略此检查。

GitUI:删除本地分支


1

对于powershell,这将起作用:

git branch --format '%(refname:lstrip=2)' --merged `
    | Where-Object { $_ -ne 'master' } `
    | ForEach-Object { git branch -d $_ }

0

以下脚本删除分支。使用和修改它需要您自担风险,等等。

根据该问题的其他答案,我最终为自己编写了一个快速的bash脚本。我将其称为“ gitbd”(git分支-D),但如果使用它,则可以将其重命名为所需的名称。

gitbd() {
if [ $# -le 1 ]
  then
    local branches_to_delete=`git for-each-ref --format '%(refname:short)' refs/heads/ | grep "$1"`
    printf "Matching branches:\n\n$branches_to_delete\n\nDelete? [Y/n] "
    read -n 1 -r # Immediately continue after getting 1 keypress
    echo # Move to a new line
    if [[ ! $REPLY == 'N' && ! $REPLY == 'n' ]]
      then
        echo $branches_to_delete | xargs git branch -D
    fi
else
  echo "This command takes one arg (match pattern) or no args (match all)"
fi
}

它会删除所有与模式参数匹配的分支(如果传入的话),或者在没有参数的情况下删除所有本地分支。这也将为您提供一个确认步骤,因为您知道我们正在删除内容,所以很好。

这有点愚蠢-如果没有匹配模式的分支,就不会意识到。

输出示例运行:

$ gitbd test
Matching branches:

dummy+test1
dummy+test2
dummy+test3

Delete? [Y/n] 

0

我写了一个shell脚本来删除除 develop

branches=$(git branch | tr -d " *")
output=""
for branch in $branches 
do
  if [[ $branch != "develop" ]]; then
    output="$output $branch"
  fi
done
git branch -d $output

0

以上答案工作正常。这是另一种方法,当我们在本地仓库中有很多分支,并且必须删除许多分支(除了少数位于本地机器中的分支)时。

首先git branch将列出所有本地分支机构。

通过运行unix命令
git branch > sample.txt
将分支名称的列转置为文件中的单行, 这会将其保存在sample.txt文件中。并
awk 'BEGIN { ORS = " " } { print }' sample.txt
在shell中运行 命令。这会将列转换为行,并在单行中复制分支名称列表。

然后运行
git branch -D branch_name(s)
这将删除本地中存在的所有列出的分支


0

最实用的方法:确保您没有未提交的工作master,如有需要,请提交/推送,克隆存储库的新副本,然后删除旧的。



0

我的包装盒上没有grep或其他Unix,但这在VSCode的终端上有效:

git branch -d $(git branch).trim()

我使用小写字母d,因此它不会删除未合并的分支。

当我这样做时,我也在使用master,所以* master它不存在,因此它没有尝试删除master。


确认:如果未启用master,此命令将删除master
Brett Rowberry

-1

确保您先执行此操作

git fetch

获得所有远程分支信息后,请使用以下命令删除除主服务器之外的每个分支

 git branch -a | grep -v "master" | grep remotes | sed 's/remotes\/origin\///g' | xargs git push origin --delete
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.