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

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

30 ответов


обновление:

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

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

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

надеюсь, что это помогает.


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

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

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

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

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

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


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

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

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

местный git ясно:

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

удаленный git clear:

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

синхронизация локального реестра удаленных филиалов:

git fetch -p

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

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

Git Sweep делает большую работу в этом.


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

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

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

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

git branch -d `git branch --merged`

Я использую следующий скрипт 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

ответ кубуна пропустил удаление ветвей, которые имеют слово master в имени ветви. Его ответ улучшается следующим образом:

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

конечно, он не удаляет саму ветку "master":)


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

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

посмотреть GitHub для Windows


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

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

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

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


git branch --merged | grep -Ev '^(. master|\*)' | xargs -n 1 git branch -d удалит все локальные ветви, кроме текущей проверенной ветви и / или master.

вот полезная статья для тех, кто хочет понять эти команды: Git Clean: удалить уже Объединенные ветви, Стивен Харман.


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

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

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

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

TL; DR

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

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

и вызовите его с помощью:

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, develop или настоящее

оригинальное регулярное выражение пропускает ветви "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" включена, даже если она не была объединена в мастер:

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

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

обособленное головное государство

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

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 '!f(){ git branch --merged $([[  != "-f" ]] \
&& git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)" \
| xargs git branch -d; }; f'

псевдоним принимает необязательный -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-del-br инструмент.

git-del-br -a

вы можете установить его с помощью pip используя

pip install git-del-br

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


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

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

Также см. ответ полезные советы о побеге сложные псевдонимы.


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

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

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


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

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 reflog найти потерянный совершает.


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

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

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

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

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


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

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

и это будет фильтровать любую заданную ветвь в трубе grep.

хорошо работает над HTTP-клоном, но не так хорошо для ssh-соединения.


напишите сценарий, в котором 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 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

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


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

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

добавить в вашего ~/.gitconfig:

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

теперь вы можете просто позвонить git sweep для выполнения этой необходимой очистки.


для 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

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


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


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

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