繁体   English   中英

如何删除所有已合并的 Git 分支?

[英]How do I delete all Git branches which have been merged?

如何删除已经合并的分支? 我可以一次删除它们,而不是一个一个地删除每个分支吗?

更新:

如果您的工作流将这些分支作为可能的祖先,您可以添加其他分支以排除,例如 master 和 dev。 通常我从“sprint-start”标签分支出来,master、dev 和 qa 不是祖先。

首先,列出在远程合并的本地跟踪分支(您可以考虑使用 -r 标志列出所有远程跟踪分支,如其他答案中所建议的那样)。

git branch --merged

您可能会看到一些您不想删除的分支。 我们可以添加一些 arguments 来跳过我们不想删除的重要分支,例如 master 或 development。 以下命令将跳过 master 分支以及其中包含 dev 的任何内容。

git branch --merged| egrep -v "(^\*|master|main|dev)"

如果要跳过,可以将其添加到 egrep 命令中,如下所示。 分支skip_branch_name不会被删除。

git branch --merged| egrep -v "(^\*|master|main|dev|skip_branch_name)"

删除所有已合并到当前签出分支的本地分支:

git branch --merged | egrep -v "(^\*|master|main|dev)" | xargs git branch -d

您可以看到 master 和 dev 被排除在外,以防它们是祖先。


您可以使用以下命令删除合并的本地分支:

git branch -d branchname

如果未合并,请使用:

git branch -D branchname

要从远程使用中删除它:

git push --delete origin branchname

git push origin :branchname    # for really old git

从远程删除分支后,您可以通过以下方式修剪以摆脱远程跟踪分支:

git remote prune origin

或修剪单个远程跟踪分支,正如另一个答案所暗示的那样,使用:

git branch -dr branchname

要删除远程上已合并的所有分支:

git branch -r --merged | grep -v master | sed 's/origin\//:/' | xargs -n 1 git push origin

在 Git 的更新版本中

git branch -r --merged | grep -v master | sed 's/origin\///' | xargs -n 1 git push --delete origin

更新(@oliver;因为不适合评论,但已经有足够的答案) :如果您在分支 ABC 上,那么 ABC 将出现在git branch -r --merged的结果中,因为未指定分支,所以分支默认到当前分支,并且分支始终符合合并到自身的条件(因为分支与自身之间没有区别。)。

所以要么指定分支:

git branch -r --merged master | grep -v master ...

或第一个结帐大师:

git checkout master | git branch -r --merged | grep -v ...

只是扩展亚当的答案一点:

通过运行git config -e --global将其添加到您的 Git 配置中

[alias]
    cleanup = "!git branch --merged | grep  -v '\\*\\|master\\|develop' | xargs -n 1 -r git branch -d"

然后您可以删除所有本地合并分支,执行简单的git cleanup

您需要从这些命令中排除mastermaindevelop分支。

本地 git 清除:

git branch --merged | grep -v '\*\|master\|main\|develop' | xargs -n 1 git branch -d

远程 git 清除:

git branch -r --merged | grep -v '\*\|master\|main\|develop' | sed 's/origin\///' | xargs -n 1 git push --delete origin

同步远程分支的本地注册表:

git fetch -p

这也适用于删除除 master 之外的所有合并分支。

git branch --merged | grep -v '^* master$' | grep -v '^  master$' | xargs git branch -d

对于那些使用 Windows 并且更喜欢 PowerShell 脚本的人,这里有一个删除本地合并分支的脚本:

function Remove-MergedBranches
{
  git branch --merged |
    ForEach-Object { $_.Trim() } |
    Where-Object { $_ -NotMatch "^\*" } |
    Where-Object { -not ( $_ -Like "*master" -or $_ -Like "*main" ) } |
    ForEach-Object { git branch -d $_ }
}

或简短版本:

git branch --merged | %{$_.trim()}  | ?{$_ -notmatch 'dev' -and $_ -notmatch 'master' -and $_ -notmatch 'main'} | %{git branch -d $_.trim()}

我多年来一直使用亚当的答案。 也就是说,在某些情况下它的行为并不像我预期的那样:

  1. 包含单词“master”的分支被忽略,例如“notmaster”或“masterful”,而不仅仅是master分支
  2. 包含单词“dev”的分支被忽略,例如“dev-test”,而不仅仅是 dev 分支
  3. 删除从当前分支的 HEAD 可达的分支(即不一定是 master)
  4. 在分离的 HEAD state 中,删除当前提交中可到达的每个分支

1 和 2 很容易解决,只需更改正则表达式。 3 取决于您想要的上下文(即仅删除尚未合并到主分支或当前分支的分支)。 如果您无意中在分离的 HEAD state 中运行它,则 4 可能会造成灾难性的后果(尽管可以使用git reflog恢复)。

最后,我希望这一切都在一个不需要单独的(Bash|Ruby|Python)脚本的单行程序中。

TL;博士

创建一个接受可选-f标志的 git 别名“sweep”:

git config --global alias.sweep '!git branch --merged $([[ $1 != "-f" ]] \
&& git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)" \
| xargs git branch -d'

并调用它:

git sweep

或者:

git sweep -f

长而详细的答案

对我来说,最简单的方法是创建一个示例 git 存储库,其中包含一些分支和提交以测试正确的行为:

使用单个提交创建一个新的 git 存储库

mkdir sweep-test && cd sweep-test && git init
echo "hello" > hello
git add . && git commit -am "initial commit"

创建一些新分支

git branch foo && git branch bar && git branch develop && git branch notmaster && git branch masterful
git branch --list
 bar develop foo * master masterful notmaster

期望的行为:select 所有合并的分支,除了:master、develop 或current

原始正则表达式错过了“masterful”和“notmaster”分支:

git checkout foo
git branch --merged | egrep -v "(^\*|master|dev)"
 bar

使用更新的正则表达式(现在不包括“develop”而不是“dev”):

git branch --merged | egrep -v "(^\*|^\s*(master|develop)$)"
 bar masterful notmaster

切换到分支 foo,进行新的提交,然后签出一个基于 foo 的新分支 foobar:

echo "foo" > foo
git add . && git commit -am "foo"
git checkout -b foobar
echo "foobar" > foobar
git add . && git commit -am "foobar"

我当前的分支是 foobar,如果我重新运行上面的命令来列出我要删除的分支,即使它还没有合并到 master 中,分支“foo”也会被包括在内:

git branch --merged | egrep -v "(^\*|^\s*(master|develop)$)"
 bar foo masterful notmaster

但是,如果我在 master 上运行相同的命令,则不包括分支“foo”:

git checkout master && git branch --merged | egrep -v "(^\*|^\s*(master|develop)$)"
 bar masterful notmaster

这仅仅是因为git branch --merged如果没有另外指定,默认为当前分支的 HEAD。 至少对于我的工作流程,我不想删除本地分支,除非它们已合并到主分支,所以我更喜欢使用 git rev-parse的以下变体:

git checkout foobar
git branch --merged $(git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)"
 bar masterful notmaster

分离头 state

依赖git branch --merged的默认行为 --merged 在分离的 HEAD state 中具有更显着的后果:

git checkout foobar
git checkout HEAD~0
git branch --merged | egrep -v "(^\*|^\s*(master|develop)$)"
 bar foo foobar masterful notmaster

这将删除我刚才所在的分支,“foobar”和“foo”,这几乎肯定不是预期的结果。 但是,使用我们修改后的命令:

git branch --merged $(git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)"
 bar masterful notmaster

一行,包括实际删除

git branch --merged $(git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)" | xargs git branch -d

全部包装成 git 别名“扫描”:

git config --global alias.sweep '!git branch --merged $([[ $1 != "-f" ]] \
&& git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)" \
| xargs git branch -d'

别名接受可选的-f标志。 默认行为是只删除已合并到 master 的分支,但-f标志将删除已合并到当前分支的分支。

git sweep
 Deleted branch bar (was 9a56952). Deleted branch masterful (was 9a56952). Deleted branch notmaster (was 9a56952).
git sweep -f
 Deleted branch foo (was 2cea1ab).

Git Sweep在这方面做得很好。

使用 Git 版本 2.5.0:

git branch -d `git branch --merged`

If you're on Windows you can use Windows Powershell or Powershell 7 with Out-GridView to have a nice list of branches and select with mouse which one you want to delete:

git branch --format "%(refname:short)" --merged  | Out-GridView -PassThru | % { git branch -d $_ }

在此处输入图像描述 单击确定后 Powershell 将把这个分支名称传递给git branch -d命令并删除它们在此处输入图像描述

您可以将提交添加到 --merged 选项。 这样,您可以确保只删除合并到的分支,即源/主

以下命令将从您的来源中删除合并的分支。

git branch -r --merged origin/master | grep -v "^.*master" | sed s:origin/:: |xargs -n 1 git push origin --delete 

您可以测试将删除哪些分支,将 git push origin --delete 替换为 echo

git branch -r --merged origin/master | grep -v "^.*master" | sed s:origin/:: |xargs -n 1 echo

我使用以下 Ruby 脚本来删除我已经合并的本地和远程分支。 如果我正在为具有多个遥控器的存储库执行此操作并且只想从一个中删除,我只需将 select 语句添加到遥控器列表中,以仅获取我想要的遥控器。

#!/usr/bin/env ruby

current_branch = `git symbolic-ref --short HEAD`.chomp
if current_branch != "master"
  if $?.exitstatus == 0
    puts "WARNING: You are on branch #{current_branch}, NOT master."
  else
    puts "WARNING: You are not on a branch"
  end
  puts
end

puts "Fetching merged branches..."
remote_branches= `git branch -r --merged`.
  split("\n").
  map(&:strip).
  reject {|b| b =~ /\/(#{current_branch}|master)/}

local_branches= `git branch --merged`.
  gsub(/^\* /, '').
  split("\n").
  map(&:strip).
  reject {|b| b =~ /(#{current_branch}|master)/}

if remote_branches.empty? && local_branches.empty?
  puts "No existing branches have been merged into #{current_branch}."
else
  puts "This will remove the following branches:"
  puts remote_branches.join("\n")
  puts local_branches.join("\n")
  puts "Proceed?"
  if gets =~ /^y/i
    remote_branches.each do |b|
      remote, branch = b.split(/\//)
      `git push #{remote} :#{branch}`
    end

    # Remove local branches
    `git branch -d #{local_branches.join(' ')}`
  else
    puts "No branches removed."
  end
end

如何在 PowerShell 控制台中删除合并的分支

git branch --merged | %{git branch -d $_.Trim()}

如果要排除master或任何其他分支名称,可以 pipe 和 PowerShell Select-String 像这样并将结果传递给git branch -d

git branch -d $(git branch --merged | Select-String -NotMatch "master" | %{$_.ToString().Trim()})

我最喜欢的简单脚本:

git branch --merged | grep -E -v "(master|develop|other)" | xargs git branch -d

kuboon 的回答错过了删除分支名称中包含 master 一词的分支。 以下改进了他的答案:

git branch -r --merged | grep -v "origin/master$" | sed 's/\s*origin\///' | xargs -n 1 git push --delete origin

当然,它不会删除“master”分支本身:)

注意:我对以前的答案不满意,(不适用于所有系统,不适用于远程,未指定 --merged 分支,未精确过滤)。 所以,我添加我自己的答案。

主要有两种情况:

当地的

您想删除已经合并到另一个本地分支的本地分支 在删除过程中,您希望保留一些重要的分支,例如 master、develop 等。

git branch --format "%(refname:short)" --merged master | grep -E -v '^master$|^feature/develop$' | xargs -n 1 git branch -d

备注

  • git branch output --format ".." 用于去除空格并允许精确的 grep 匹配
  • grep -E用于代替egrep ,因此它也适用于没有 egrep 的系统(即:git for windows)。
  • grep -E -v '^master$|^feature/develop$'是指定我不想删除的本地分支
  • xargs -n 1 git branch -d :删除本地分支(远程分支无效)
  • 当然,如果您尝试删除当前签出的分支,则会出现错误。 所以,我建议提前切换到master。

偏僻的

您要删除已合并到另一个远程分支的远程分支 在删除过程中,你希望保留一些重要的分支,如 HEAD、master、releases 等。

git branch -r --format "%(refname:short)" --merged origin/master | grep -E -v '^*HEAD$|^*/master$|^*release' | cut -d/ -f2- | xargs -n 1 git push --delete origin

备注

  • 对于远程,我们使用-r选项并提供完整的分支名称origin/master
  • grep -E -v '^*HEAD$|^*/master$|^*release'是为了匹配我们不想删除的远程分支。
  • cut -d/ -f2- :删除不需要的 'origin/' 前缀,否则会由git branch命令打印出来。
  • xargs -n 1 git push --delete origin :执行远程分支的删除。

如果您将OhMyZSHgit 插件一起使用,则可以使用gbda别名。

我用这个:

git branch --delete $(git branch --format '%(refname:short)' --merged | grep --invert-match 'main\|master\|branch-to-skip')

它以指定格式列出所有合并的分支,然后将该列表提供给 git 分支 --delete。

Git 中没有命令会自动为您执行此操作。 但是您可以编写一个使用 Git 命令的脚本来满足您的需求。 这可以通过多种方式完成,具体取决于您使用的分支 model。

如果您需要知道分支是否已合并到 master 中,如果 myTopicBranch 已合并(即您可以将其删除),则以下命令将产生 no output

$ git rev-list master | grep $(git rev-parse myTopicBranch)

您可以使用 Git 分支命令并解析出 Bash 中的所有分支,并对所有分支执行for循环。 在此循环中,您可以使用上述命令检查是否可以删除分支。

git branch --merged | grep -Ev '^(. master|\*)' | xargs -n 1 git branch -d git branch --merged | grep -Ev '^(. master|\*)' | xargs -n 1 git branch -d将删除除当前签出的分支和/或master之外的所有本地分支。

对于那些希望了解这些命令的人来说,这是一篇有用的文章: Git Clean: Delete Already Merged Branches,作者 Steven Harman

您可以使用git-del-br工具

git-del-br -a

您可以使用pip安装它

pip install git-del-br

PS:我是该工具的作者。 欢迎任何建议/反馈。

我使用 git-flow esque 命名方案,所以这对我来说非常安全:

git branch --merged | grep -e "^\s\+\(fix\|feature\)/" | xargs git branch -d

它基本上会查找以字符串fix/feature/开头的合并提交。

在 Windows 和git bash安装 egrep -v 将不起作用

git branch --merged | grep -E -v "(master|test|dev)" | xargs git branch -d

其中grep -E -v相当于egrep -v

使用-d删除已合并的分支或使用-D删除未合并的分支

如果您想删除所有已合并到您当前所在分支的本地分支,那么我根据之前的答案提出了一个安全命令:

git branch --merged | grep -v \* | grep -v '^\s*master$' | xargs -t -n 1 git branch -d

此命令不会影响您当前的分支或您的主分支。 它还会使用 xargs 的 -t 标志在执行此操作之前告诉您它在做什么。

亚当更新答案的别名版本:

[alias]
    branch-cleanup = "!git branch --merged | egrep -v \"(^\\*|master|dev)\" | xargs git branch -d #"

此外,请参阅此答案以获取有关 escaping 复杂别名的便捷提示。

公认的解决方案非常好,但有一个问题是它还会删除尚未合并到远程的本地分支。

如果您查看 output 您会看到类似

$ git branch --merged master -v
  api_doc                  3a05427 [gone] Start of describing the Java API
  bla                      52e080a Update wording.
  branch-1.0               32f1a72 [maven-release-plugin] prepare release 1.0.1
  initial_proposal         6e59fb0 [gone] Original proposal, converted to AsciiDoc.
  issue_248                be2ba3c Skip unit-for-type checking. This needs more work. (#254)
  master                   be2ba3c Skip unit-for-type checking. This needs more work. (#254)

分支blaissue_248是本地分支,将被静默删除。

但是您也可以看到[gone]一词,它表示已推送到远程的分支(现在已消失),因此表示可以删除分支。

因此,原始答案可以更改为(拆分为多行以缩短行长)

git branch --merged master -v | \
     grep  "\\[gone\\]" | \
     sed -e 's/^..//' -e 's/\S* .*//' | \
      xargs git branch -d

保护尚未合并的分支。 也不需要主人保护它的grepping,因为它在原点有一个遥控器并且不会显示为消失。

基于其中一些答案,我也制作了自己的 Bash 脚本来完成它

它使用git branch --mergedgit branch -d删除已合并的分支,并在删除前提示您输入每个分支。

merged_branches () {
    local current_branch=$(git rev-parse --abbrev-ref HEAD)
    for branch in $(git branch --merged | cut -c3-)
      do
        echo "Branch $branch is already merged into $current_branch."
        echo "Would you like to delete it? [Y]es/[N]o "
        read REPLY
        if [[ $REPLY =~ ^[Yy] ]]; then
            git branch -d $branch
        fi
    done
}

尝试以下命令:

git branch -d $(git branch --merged | grep -vw $(git rev-parse --abbrev-ref HEAD))

通过使用git rev-parse将获取当前分支名称以排除它。 如果您收到错误消息,则意味着没有要删除的本地分支。

要对远程分支执行相同操作(使用您的远程名称更改origin ),请尝试:

git push origin -vd $(git branch -r --merged | grep -vw $(git rev-parse --abbrev-ref HEAD) | cut -d/ -f2)

如果您有多个遥控器,请添加grep origin | cut之前只过滤origin

如果上述命令失败,请先尝试删除合并的远程跟踪分支:

git branch -rd $(git branch -r --merged | grep -vw $(git rev-parse --abbrev-ref HEAD))

然后git fetch遥控器并再次使用之前的git push -vd命令。

如果您经常使用它,请考虑将别名添加到您的~/.gitconfig文件中。

如果您错误地删除了一些分支,请使用git reflog来查找丢失的提交。

下面的查询对我有用

for branch in  `git branch -r --merged | grep -v '\*\|master\|develop'|awk 'NR > 0 {print$1}'|awk '{gsub(/origin\//, "")}1'`;do git push origin --delete $branch; done

这将过滤 grep pipe 中的任何给定分支。

在 http 克隆上运行良好,但在 ssh 连接上效果不佳。

截至2018.07

将此添加到~/.gitconfig[alias]部分:

sweep = !"f() { git branch --merged | egrep -v \"(^\\*|master|dev)\" || true | xargs git branch -d; }; f"

现在您只需调用git sweep来执行所需的清理。

我一直在使用以下方法在一个 cmd 中删除合并的本地和远程分支

我的bashrc文件中有以下内容:

function rmb {
  current_branch=$(git branch --no-color 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/\1/')
  if [ "$current_branch" != "master" ]; then
    echo "WARNING: You are on branch $current_branch, NOT master."
  fi
  echo "Fetching merged branches..."
  git remote prune origin
  remote_branches=$(git branch -r --merged | grep -v '/master$' | grep -v "/$current_branch$")
  local_branches=$(git branch --merged | grep -v 'master$' | grep -v "$current_branch$")
  if [ -z "$remote_branches" ] && [ -z "$local_branches" ]; then
    echo "No existing branches have been merged into $current_branch."
  else
    echo "This will remove the following branches:"
    if [ -n "$remote_branches" ]; then
      echo "$remote_branches"
    fi
    if [ -n "$local_branches" ]; then
      echo "$local_branches"
    fi
    read -p "Continue? (y/n): " -n 1 choice
    echo
    if [ "$choice" == "y" ] || [ "$choice" == "Y" ]; then
      # Remove remote branches
      git push origin `git branch -r --merged | grep -v '/master$' | grep -v "/$current_branch$" | sed 's/origin\//:/g' | tr -d '\n'`
      # Remove local branches
      git branch -d `git branch --merged | grep -v 'master$' | grep -v "$current_branch$" | sed 's/origin\///g' | tr -d '\n'`
    else
      echo "No branches removed."
    fi
  fi
}

原始来源

这不会删除主分支,但会删除合并的本地和远程分支 一旦你在你的 rc 文件中有了这个,只需运行rmb ,你就会看到一个合并分支的列表,这些分支将被清理并要求确认操作。 您也可以修改代码以不要求确认,但最好保留它。

编写一个脚本,在其中 Git 检出所有已合并到 master 的分支。

然后做git checkout master

最后,删除合并的分支。

for k in $(git branch -ra --merged | egrep -v "(^\*|master)"); do
  branchnew=$(echo $k | sed -e "s/origin\///" | sed -e "s/remotes\///")
  echo branch-name: $branchnew
  git checkout $branchnew
done

git checkout master

for k in $(git branch -ra --merged | egrep -v "(^\*|master)"); do
  branchnew=$(echo $k | sed -e "s/origin\///" | sed -e "s/remotes\///")
  echo branch-name: $branchnew
  git push origin --delete $branchnew
done

对我来说git branch --merged不显示通过 GitHub PR 合并的分支。 我不确定原因,但我使用以下行删除所有没有远程跟踪分支的本地分支

diff <(git branch --format "%(refname:short)") <(git branch -r | grep -v HEAD | cut -d/ -f2-) | grep '<' | cut -c 3- | xargs git branch -D

解释:

  • git branch --format "%(refname:short)"给出本地分支列表
  • git branch -r | grep -v HEAD | cut -d/ -f2- git branch -r | grep -v HEAD | cut -d/ -f2-给出远程分支列表,过滤掉HEAD
  • diff <(...) <(...)给出括号内两个命令的 output 的差异
  • grep '<'过滤存在于第一个列表中但不存在于第二个列表中的分支
  • cut -c 3-给出从第三个字符开始的行,从而删除前缀<
  • xargs git branch -D git branch -D

或者,您可以像这样避免grep -v '<'

diff --old-line-format="%L" --new-line-format="" --unchanged-line-format="" <(git branch --format "%(refname:short)") <(git branch -r | grep -v HEAD | cut -d/ -f2-) | xargs git branch -D

为避免意外从除 master 以外的任何其他分支运行命令,我使用以下 bash 脚本。 否则,运行git branch --merged | grep -v "\*" | xargs -n 1 git branch -d git branch --merged | grep -v "\*" | xargs -n 1 git branch -d git branch --merged | grep -v "\*" | xargs -n 1 git branch -d从已合并关闭 master 的分支中可以删除 master 分支。

#!/bin/bash

branch_name="$(git symbolic-ref HEAD 2>/dev/null)" ||
branch_name="(unnamed branch)"     # detached HEAD
branch_name=${branch_name##refs/heads/}

if [[ $branch_name == 'master' ]]; then
   read -r -p "Are you sure? [y/N] " response
   if [[ $response =~ ^([yY][eE][sS]|[yY])$ ]]; then
       git branch --merged | grep -v "\*" | xargs -n 1 git branch -d
   fi
else
   echo "Refusing to delete branches that are not merged into '$branch_name'. Checkout master first."
fi

我发现的最简单的方法是只删除本地分支,而不是远程分支:

$ git branch --merged | grep -v master | xargs -n 1 git branch -D

此命令将仅删除已合并到您的主分支中的分支。 如果您不想删除其他分支(例如staging ),请小心。

要删除合并的分支, git-delete-merged-branches比 shell hack 更健壮、更方便。 它还检测 rebase 合并和 squash 合并。 它的自述文件有更多细节

来自git-toolbeltgit cleanup脚本

删除所有已经合并到 master 或 develop 的分支。 保持其他分支躺在周围。 将是最保守的删除。

删除本地和远程源中的分支。

要删除已合并到主分支的本地分支,我使用以下别名( git config -e --global ):

cleanup = "!git branch --merged master | grep -v '^*\\|master' | xargs -n 1 git branch -D"

我正在使用git branch -D以避免error: The branch 'some-branch' is not fully merged. 消息,而我当前的结帐与主分支不同。

假设我有一个名为 upstream 的遥控器和一个 origin(GitHub 样式,我的 fork 是 origin,upstream 是上游)。

我不想从上游删除任何主人、HEAD 或任何东西。 我也不想删除开发分支,因为这是我们创建 PR 的公共分支。

列出所有远程分支,按合并的分支过滤:

git branch -r

从该列表中删除包含我知道在我不想删除的分支名称中的单词的行:

sed '/develop\|master\|HEAD\|upstream/d'

从引用名称中删除远程名称(origin/somebranch 变为 somebranch):

sed 's/.*\///'

使用 xargs 调用单行:

xargs git push --delete origin

Pipe 这一切你得到:

git branch -r --merged | sed '/develop\|master\|HEAD\|upstream/d' |  sed 's/.*\///' | xargs git push --delete origin

这将使我只剩下一些我已经处理过但尚未合并的分支。 然后,您可以将它们一一删除,因为不应该太多。

查找您不再需要的分支:

git branch -ar

假设您找到要删除的 branch1、branch2 和 branch3:

git push --delete origin branch1 branch2 branch3
$ git config --global alias.cleanup
'!git branch --merged origin/master | egrep -v "(^\*|master|staging|dev)" | xargs git branch -d'

(为了便于阅读,分成多行)

调用“git cleanup”将删除已经合并到 origin/master 的本地分支。 它会跳过 master、staging 和 dev,因为我们不想在正常情况下删除它们。

打破这个,这就是它正在做的事情:

  1. git config --global alias.cleanup
    • 这正在创建一个名为“cleanup”的全局别名(在您的所有存储库中)
  2. ! 在命令的开头是说我们将使用一些非 git 命令作为这个别名的一部分,所以我们需要在这里实际运行 bash 命令
  3. git branch --merged origin/master
    • 此命令返回已合并到origin/master的分支名称列表
  4. egrep -v "(^\*|master|staging|dev)"
    • 这会从已合并的分支列表中删除 master、staging 和 dev 分支。 我们不想删除这些分支,因为它们不是特性。
  5. xargs git branch -d
    • 这将为每个未合并的分支运行git branch -d xxxxx命令。 这会一一删除本地分支。

对于 Windows,您可以使用以下命令安装Cygwin并删除所有远程分支:

git branch -r --merged | "C:\cygwin64\bin\grep.exe" -v master | "C:\cygwin64\bin\sed.exe" 's/origin\///' | "C:\cygwin64\bin\xargs.exe" -n 1 git push --delete origin

刚刚为此创建了 python 脚本:

import sys
from shutil import which
import logging
from subprocess import check_output, call

logger = logging.getLogger(__name__)

if __name__ == '__main__':
    if which("git") is None:
        logger.error("git is not found!")
        sys.exit(-1)

    branches = check_output("git branch -r --merged".split()).strip().decode("utf8").splitlines()
    current = check_output("git branch --show-current".split()).strip().decode("utf8")
    blacklist = ["master", current]

    for b in branches:
        b = b.split("/")[-1]

        if b in blacklist:
            continue
        else:
            if input(f"Do you want to delete branch: '{b}' [y/n]\n").lower() == "y":
                call(f"git branch -D {b}".split())
                call(f"git push --delete origin {b}".split())

tl;dr: git branch --format='%(if:notequals=main)%(refname:short)%(then)%(if:notequals=master)%(refname:short)%(then)%(refname:short)%(end)%(end)' --merged | xargs --max-args=1 --no-run-if-empty echo git branch --delete git branch --format='%(if:notequals=main)%(refname:short)%(then)%(if:notequals=master)%(refname:short)%(then)%(refname:short)%(end)%(end)' --merged | xargs --max-args=1 --no-run-if-empty echo git branch --delete ,如果您愿意实际删除列出的分支,则删除echo显。

看妈妈,没有工具!

Git 可以在不使用外部工具的情况下过滤分支,这意味着有一种跨平台的、相对简单的方法可以从搜索中排除默认分支。 列出合并到“主”分支的分支,不包括“主”分支本身: git branch --format='%(if:notequals=main)%(refname:short)%(then)%(refname:short)%(end)' --merged=main 对于“master”分支: git branch --format='%(if:notequals=master)%(refname:short)%(then)%(refname:short)%(end)' --merged=master

我们也可以将两者结合起来,仅当它既不匹配“main”也不匹配“master”时打印分支名称: git branch --format='%(if:notequals=main)%(refname:short)%(then)%(if:notequals=master)%(refname:short)%(then)%(refname:short)%(end)%(end)' --merged

最后一个有一个小警告:您应该首先检查默认分支(在本例中为“main”或“master”),因为没有值的--merged意味着“合并到 HEAD”,这可能指向到您要删除的分支之一。 但是尝试删除当前的本地分支无论如何都行不通,所以如果您正在这样做的话,这不是风险。

这种方法的另一个优点是没有额外的前导空格或星号可以过滤掉。

这些命令将为排除的分支打印一个空行而不是什么都不打印,但xargs会处理这个问题。 如果你想使用xargs以外的东西处理这些行,你可能需要对空行进行特殊处理(比如通过sed '/^$/d'

有关--format的更多信息,请参阅git help for-each-ref

Windoze 友好的 Python 脚本(因为git-sweep在 Wesnoth 存储库中阻塞):

#!/usr/bin/env python
# Remove merged git branches. Cross-platform way to execute:
#
#   git branch --merged | grep -v master | xargs git branch -d
#
# Requires gitapi - https://bitbucket.org/haard/gitapi
# License: Public Domain

import gitapi

repo = gitapi.Repo('.')
output = repo.git_command('branch', '--merged').strip()
for branch in output.split('\n'):
  branch = branch.strip()
  if branch.strip(' *') != 'master':
    print(repo.git_command('branch', '-d', branch).strip())

https://gist.github.com/techtonik/b3f0d4b9a56dbacb3afc

如果您使用分支 model (如 HubFlow 或 GitFlow),您可以使用此命令删除合并的功能分支:

git branch --merged | grep feature.* | grep -v "\*" | xargs -n 1 git branch -d

如果您希望删除已合并的本地分支以及删除其远程分支,这是我更喜欢的单行代码:

git branch --merged | xargs -I_br -- sh -c 'git branch -d _br; git push origin --delete _br'

我的 Bash 脚本贡献大致基于mmrobin 的回答

它需要一些有用的参数来指定包含和排除,或者只检查/删除本地或远程分支而不是两者。

#!/bin/bash

# exclude branches regex, configure as "(branch1|branch2|etc)$"
excludes_default="(master|next|ag/doc-updates)$"
excludes="__NOTHING__"
includes=
merged="--merged"
local=1
remote=1

while [ $# -gt 0 ]; do
  case "$1" in
  -i) shift; includes="$includes $1" ;;
  -e) shift; excludes="$1" ;;
  --no-local) local=0 ;;
  --no-remote) remote=0 ;;
  --all) merged= ;;
  *) echo "Unknown argument $1"; exit 1 ;;
  esac
  shift   # next option
done

if [ "$includes" == "" ]; then
  includes=".*"
else
  includes="($(echo $includes | sed -e 's/ /|/g'))"
fi

current_branch=$(git branch --no-color 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/\1/')
if [ "$current_branch" != "master" ]; then
  echo "WARNING: You are on branch $current_branch, NOT master."
fi
echo -e "Fetching branches...\n"

git remote update --prune
remote_branches=$(git branch -r $merged | grep -v "/$current_branch$" | grep -v -E "$excludes" | grep -v -E "$excludes_default" | grep -E "$includes")
local_branches=$(git branch $merged | grep -v "$current_branch$" | grep -v -E "$excludes" | grep -v -E "$excludes_default" | grep -E "$includes")
if [ -z "$remote_branches" ] && [ -z "$local_branches" ]; then
  echo "No existing branches have been merged into $current_branch."
else
  echo "This will remove the following branches:"
  if [ "$remote" == 1 -a -n "$remote_branches" ]; then
    echo "$remote_branches"
  fi
  if [ "$local" == 1 -a -n "$local_branches" ]; then
    echo "$local_branches"
  fi
  read -p "Continue? (y/n): " -n 1 choice
  echo
  if [ "$choice" == "y" ] || [ "$choice" == "Y" ]; then
    if [ "$remote" == 1 ]; then
      remotes=$(git remote)
      # Remove remote branches
      for remote in $remotes
      do
        branches=$(echo "$remote_branches" | grep "$remote/" | sed "s/$remote\/\(.*\)/:\1 /g" | tr -d '\n')
        git push $remote $branches
      done
    fi

    if [ "$local" == 1 ]; then
      # Remove local branches
      locals=$(echo "$local_branches" | sed 's/origin\///g' | tr -d '\n')
      if [ -z "$locals" ]; then
        echo "No branches removed."
      else
        git branch -d $(echo "$locals" | tr -d '\n')
      fi
    fi
  fi
fi

git git-extras repo 中git-delete-merged-branches

https://github.com/tj/git-extras/blob/master/Commands.md#git-delete-merged-branches

鉴于您要删除合并的分支,您只需要删除远程跟踪分支,除非您 state 否则。

因此,要删除这些分支,您可以通过

git branch --remote --merged origin/master | egrep -v "(^\*|master|development)" | cut -b 10- | xargs git push --delete origin

这将删除除masterdevelopment之外的所有合并分支(合并到 master)。

我使用 Python 脚本,该脚本自动执行最流行答案中的步骤,并检查剩余的分支以查看它们是否会在合并时产生任何更改,如果没有则交互提示删除它们: https://github.com/robertknight/prune-合并分支

下面使用一个可选参数分支创建别名git cleanup 默认情况下,它使用远程来源的默认分支。 已合并到此的每个分支都将被删除。 还有一个-d / --dryrun选项来显示将被删除的内容。

设置

git config --global alias.cleanup '!COMMAND="git branch -D"; while [[ $# -gt 0 ]]; do case "$1" in -d|--dryrun) COMMAND="echo"; shift; ;; *) MAIN_BRANCH="$1"; shift;; esac; done; MAIN_BRANCH="${MAIN_BRANCH:-$(git symbolic-ref refs/remotes/origin/HEAD)}"; git for-each-ref --merged="$MAIN_BRANCH" --no-contains="$MAIN_BRANCH" --format="%(refname:short)" refs/heads/ | xargs -n1 -r $COMMAND;#'

用法:

git cleanup             # delete all branches that have been merged into origin/HEAD
git cleanup master2     # delete all branches that have been merged into master2
git cleanup master2 -d  # do a dryrun (show names of branches that would be delted)

可读代码

谁能读懂那个“oneliner”? 那么你在这里 go

COMMAND="git branch -D";
while [[ $# -gt 0 ]]; do
  case "$1" in
    -d|--dryrun)
      COMMAND="echo"; 
      shift; 
      ;; 
    *)
      MAIN_BRANCH="$1";
      shift
    ;;
  esac;
done;
MAIN_BRANCH="${MAIN_BRANCH:-$(git symbolic-ref refs/remotes/origin/HEAD)}"; 
git for-each-ref --merged="$MAIN_BRANCH" --no-contains="$MAIN_BRANCH" --format="%(refname:short)" refs/heads/ | xargs -n1 -r $COMMAND;
#

与其他答案有什么不同?

  • 使用--no-contains选项过滤掉身份分支(已合并所有其他已删除分支的分支)而不是grep -v (如果您具体了解您的分支并指定 refs/heads/master,这会更好例如)
  • 使用远程 HEAD 检查默认分支名称
  • 有一个参数来指定哪个分支用作合并主控
  • 有空运行选项

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM