Как удалить все ветки Git, которые были объединены?

У меня много ветвей Git. Как удалить ветки, которые уже были объединены? Есть ли простой способ удалить их все, а не удалять их один за другим?

Ответ 1

ОБНОВИТЬ:

Вы можете добавить другие ветки для исключения, такие как master и dev, если ваш рабочий процесс имеет их в качестве возможного предка. Обычно я разветвляюсь от тега "sprint-start" и master, dev и qa не являются предками.

Сначала перечислите все ветки, которые были объединены в удаленном.

git branch --merged

Вы можете увидеть несколько веток, которые не хотите удалять. мы можем добавить несколько аргументов, чтобы пропустить важные ветки, которые мы не хотим удалять, как master или development. Следующая команда пропустит основную ветку и все, что содержит dev.

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

Если вы хотите пропустить, вы можете добавить его в команду egrep, как показано ниже. Ветка skip_branch_name не будет удалена.

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

Чтобы удалить все локальные ветки, которые уже объединены в текущую извлеченную ветку:

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

Вы можете видеть, что master и dev исключены, если они являются предками.


Вы можете удалить объединенную локальную ветку с помощью:

git branch -d branchname

Если оно не объединено, используйте:

git branch -D branchname

Чтобы удалить его с пульта в старых версиях Git, используйте:

git push origin :branchname

В более поздних версиях Git используют:

git push --delete origin branchname

После того как вы удалите ветку с пульта, вы можете удалить ветки удаленного отслеживания с помощью:

git remote prune origin

или обрезать отдельные ветки удаленного отслеживания, как предлагает другой ответ, с помощью:

git branch -dr branchname

Надеюсь это поможет.

Ответ 2

Чтобы удалить все удаленные ветки, которые уже объединены:

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 ...

Ответ 3

Просто расширяя Адама немного:

Добавьте это в конфигурацию Git, запустив git config -e --global

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

И затем вы можете удалить все локальные объединенные ветки, выполнив простой git cleanup.

Ответ 4

Это также позволяет удалить все объединенные ветки, кроме master.

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

Ответ 5

Вы хотите исключить ветки master и develop из этих команд.

Локальный git очистить:

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

Удаленная git очистка:

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

Синхронизировать локальный реестр удаленных ветвей:

git fetch -p

Ответ 6

Для тех из вас, кто находится в Windows и предпочитает сценарии PowerShell, вот что удаляет локальные объединенные ветки:

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

Ответ 7

Я использовал ответ Адама в течение многих лет. Тем не менее, есть некоторые случаи, когда он не вел себя так, как я ожидал:

  1. ветки, содержащие слово "master", игнорировались, например, "notmaster" или "masterful", а не только основная ветвь
  2. ветки, содержащие слово "dev", игнорировались, например, "dev-test", а не только ветка dev
  3. удаление веток, которые доступны из HEAD текущей ветки (то есть не обязательно master)
  4. в отдельном состоянии HEAD, удаляя каждую ветвь, достижимую из текущего коммита

1 и 2 были просты для решения, просто с изменением в регулярном выражении. 3 зависит от контекста того, что вы хотите (т.е. удаляете только те ветки, которые не были объединены в master или с вашей текущей веткой). 4 может привести к катастрофическим последствиям (хотя их можно git reflog с помощью git reflog), если вы непреднамеренно запустили это в отключенном состоянии HEAD.

Наконец, я хотел, чтобы все было в одной строке, для которой не требовался отдельный скрипт (Bash | Ruby | Python).

TL; DR

Создайте псевдоним git "sweep", который принимает необязательный флаг -f:

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 repo с некоторыми ветками и коммитами для проверки правильности поведения:

Создать новый репозиторий 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

Желаемое поведение: выберите все объединенные ветки, кроме: master, development или current

Оригинальное регулярное выражение пропускает ветки "masterful" и "notmaster":

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

С обновленным регулярным выражением (которое теперь исключает "развернуть", а не "dev"):

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

Переключитесь на ветку foo, сделайте новый коммит, затем извлеките новую ветку foobar, основанную на foo:

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

Моя текущая ветвь - foobar, и если я перезапущу приведенную выше команду для вывода списка ветвей, которые я хочу удалить, ветка "foo" будет включена, даже если она не была объединена с master:

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 умолчанию git branch --merged значение HEAD текущей ветки, если не указано иное. По крайней мере, для моего рабочего процесса я не хочу удалять локальные ветки, если они не были объединены с master, поэтому я предпочитаю следующий вариант:

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

Отделенное состояние HEAD

Использование стандартного поведения git branch --merged имеет еще более существенные последствия в отключенном состоянии HEAD:

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 "sweep":

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).

Ответ 8

Git Sweep отлично справляется с этой задачей.

Ответ 9

Использование Git версии 2.5.0:

git branch -d `git branch --merged`

Ответ 10

Вы можете добавить фиксацию к опции -merged. Таким образом, вы можете убедиться, что только удалены ветки, которые объединены в i.e origin/master

Следующая команда удалит объединенные ветки из вашего источника.

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

Вы можете проверить, какие ветки будут удалены, заменив начало git push -delete с помощью эха

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

Ответ 11

Я использую следующий Ruby script, чтобы удалить уже объединенные локальные и удаленные ветки. Если я делаю это для репозитория с несколькими удаленными устройствами и только хочу удалить из него, я просто добавляю оператор 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

Ответ 12

Как удалить объединенные ветки в консоли PowerShell

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

Если вы хотите исключить master или любые другие имена веток, вы можете передать с помощью PowerShell Select-String, как git branch -d и передать результат в git branch -d:

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

Ответ 13

В Git нет команды, которая сделает это автоматически. Но вы можете написать script, который использует команды Git, чтобы дать вам то, что вам нужно. Это можно сделать разными способами в зависимости от используемой модели ветвления.

Если вам нужно знать, если ветвь была объединена с мастером, следующая команда не даст результата, если myTopicBranch был объединен (т.е. вы можете удалить его)

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

Вы можете использовать команду ветвления Git и проанализировать все ветки в Bash и выполнить цикл for по всем ветвям. В этом цикле вы проверяете с помощью приведенной выше команды, если вы можете удалить ветку или нет.

Ответ 14

Ответ kuboon пропустил удаление ветвей, у которых есть имя слова в имени ветки. Следующее улучшает его ответ:

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

Конечно, он не удаляет сам "главный":)

Ответ 16

Вы можете использовать инструмент git-del-br.

git-del-br -a

Вы можете установить его через pip используя

pip install git-del-br

PS: Я автор инструмента. Любые предложения/отзывы приветствуются.

Ответ 17

Версия псевдонима Адам обновил ответ:

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

Также см. этот ответ для удобных советов по экранированию сложных псевдонимов.

Ответ 18

Основываясь на некоторых из этих ответов, я сделал мой собственный Bash script, чтобы сделать это тоже!

Он использует git branch --merged и git 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
}

Ответ 19

Если вы хотите удалить все локальные ветки, которые уже были объединены, в ветку, в которой вы сейчас находитесь, я придумал безопасную команду для этого, основываясь на более ранних ответах:

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

Эта команда не повлияет на вашу текущую ветку или главную ветку. Он также расскажет вам, что он делает, прежде чем он это сделает, используя флаг -t xargs.

Ответ 20

Я использую схему именования git -flow esque, поэтому для меня это очень безопасно:

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

В основном он ищет объединенные коммиты, начинающиеся с строки fix/ или feature/.

Ответ 21

Попробуйте выполнить следующую команду:

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, чтобы найти потерянные коммиты.

Ответ 22

Ниже запроса работает для меня

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-канале.

Хорошо работает над http clone, но не так хорошо для ssh-соединения.

Ответ 23

В 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 для удаления несвязанных ветвей

Ответ 24

По состоянию на 2018.07

Добавьте это в раздел [alias] вашего ~/.gitconfig:

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

Теперь вы можете просто вызвать git sweep чтобы выполнить необходимую очистку.

Ответ 25

Напишите script, в котором Git проверяет все ветки, которые были объединены с мастером.

Затем выполните 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

Ответ 26

Принятое решение довольно хорошо, но имеет одну проблему: он также удаляет локальные ветки, которые еще не были объединены в удаленный.

Если вы посмотрите на результат, вы увидите что-то вроде

$ 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)

Филиалы bla и issue_248 являются локальными ветвями, которые будут удалены молча.

Но вы также можете увидеть слово [gone], которое указывает ветки, которые были нажаты на удаленный (который теперь ушел) и, таким образом, обозначают ветки, которые можно удалить.

Таким образом, исходный ответ может быть изменен на (разбитый на многострочный для более короткой длины строки)

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

для защиты еще не объединенных веток. Также grepping для мастера, чтобы защитить его, не требуется, так как у этого есть пульт по происхождению и он не отображается, как ушел.

Ответ 27

Чтобы избежать случайного запуска команды из любой другой ветки, кроме мастера, я использую следующий bash script. В противном случае запуск git branch --merged | grep -v "\*" | xargs -n 1 git branch -d из ветки, которая была объединена с отключенным мастером, может удалить главную ветвь.

#!/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

Ответ 28

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

(Разделить на несколько строк для удобства чтения)

Вызов "git cleanup" приведет к удалению локальных ветвей, которые уже были объединены в origin/master. Он пропускает мастер, постановку и dev, потому что мы не хотим удалять их в обычных обстоятельствах.

Нарушая это, это то, что он делает:

  1. git config --global alias.cleanup
    • Это создает глобальный псевдоним, называемый "очистка" (во всех ваших репозиториях)
  2. ! в начале команды говорится, что мы будем использовать некоторые команды не-git как часть этого псевдонима, поэтому нам нужно фактически запускать команды bash здесь
  3. git branch --merged origin/master
    • Эта команда возвращает список имен ветвей, которые уже были объединены в origin/master
  4. egrep -v "(^\*|master|staging|dev)"
    • Это удаляет ведущую, промежуточную ветвь и ветвь dev из списка ветвей, которые уже были объединены. Мы не хотим удалять эти ветки, поскольку они не являются функциями.
  5. xargs git branch -d
    • Это приведет к выполнению команды git branch -d xxxxx для каждой из несвязанных ветвей. Это удаляет локальные ветки по одному.

Ответ 29

В 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

Ответ 30

Если вы работаете в Windows, вы можете использовать Windows Powershell с Out-GridView (к сожалению, в Powershell Core пока нет), чтобы получить хороший список ветвей и выбрать мышью, какую из них вы хотите удалить:

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

enter image description here после нажатия OK Powershell передаст имена этих веток команде git branch -d и удалит их enter image description here