Удалить отслеживание веток больше не на удаленном


1176

Есть ли простой способ удалить все ветви отслеживания, удаленный эквивалент которых больше не существует?

Пример:

Филиалы (местные и удаленные)

  • мастер
  • Происхождение / мастер
  • Происхождение / ошибка затруднительного-а
  • Происхождение / ошибка затруднительного-б
  • Происхождение / ошибка затруднительного-с

Локально у меня только мастер ветка. Теперь мне нужно поработать над bug-fix-a , поэтому я проверяю его, работаю над ним и отправляю изменения на пульт. Затем я делаю то же самое с bug-fix-b .

Филиалы (местные и удаленные)

  • мастер
  • ошибка-фикс-а
  • ошибка затруднительного-б
  • Происхождение / мастер
  • Происхождение / ошибка затруднительного-а
  • Происхождение / ошибка затруднительного-б
  • Происхождение / ошибка затруднительного-с

Теперь у меня есть мастер локальных веток , bug-fix-a , bug-fix-b . Мастер веток Мастер объединит мои изменения в мастер и удалит все ветви, которые он уже слил.

Итак, текущее состояние сейчас:

Филиалы (местные и удаленные)

  • мастер
  • ошибка-фикс-а
  • ошибка затруднительного-б
  • Происхождение / мастер
  • Происхождение / ошибка затруднительного-с

Теперь я хотел бы вызвать некоторую команду для удаления веток (в данном случае bug-fix-a , bug-fix-b ), которые больше не представлены в удаленном репозитории.

Это было бы что-то вроде существующей команды git remote prune origin, но больше похоже git local prune origin.

Ответы:


1284

git remote prune origin Чернослив отслеживания веток не на пульте.

git branch --merged перечисляет ветви, которые были объединены с текущей веткой.

xargs git branch -d удаляет ветви, перечисленные в стандартном вводе.

Будьте осторожны, удаляя перечисленные ветки git branch --merged. Список может включать masterили другие ветви, которые вы не хотите удалять.

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

git branch --merged >/tmp/merged-branches && \
  vi /tmp/merged-branches && xargs git branch -d </tmp/merged-branches

17
Первая строка объединенных веток находится * masterв моей системе. У меня сработала следующая команда:git branch -d $(git branch --merged |tail -n +2)
Trendfischer

99
Если я нахожусь, developто git branch --mergedвключает master! Вы вероятно (определенно!) Не хотите удалять это. Также я думаю, что это должно быть git branch -dтам, где строчные буквы -dозначают «безопасное удаление», например, удаление только в случае объединения.
thom_nic

11
Кажется , улучшенное решение обеспечивается там .
Сергей Брунов

34
Удаленный объединенный полезен, но не то же самое, что «удалить ветви не на удаленном».
dlsso

11
Просто используйте grep, чтобы исключить мастера:git branch --merged | grep -v "master" >/tmp/merged-branches && vi /tmp/merged-branches && xargs git branch -d </tmp/merged-branches
geniass

592

После команды

git fetch -p

удаляет удаленные ссылки при запуске

git branch -vv

он покажет «ушел» как удаленный статус. Например,

$ git branch -vv
  master                 b900de9 [origin/master: behind 4] Fixed bug
  release/v3.8           fdd2f4e [origin/release/v3.8: behind 2] Fixed bug
  release/v3.9           0d680d0 [origin/release/v3.9: behind 2] Updated comments
  bug/1234               57379e4 [origin/bug/1234: gone] Fixed bug

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

git fetch -p && for branch in $(git branch -vv | grep ': gone]' | awk '{print $1}'); do git branch -D $branch; done

Обратите внимание, что вышеприведенное использует команду "фарфор" git branchдля получения статуса восходящего потока.

Другой способ получить это состояние - использовать команду «plumbing» git for-each-refс интерполяционной переменной %(upstream:track), которая будет такой [gone]же, как и выше.

Этот подход несколько безопаснее, потому что нет риска случайного сопоставления части сообщения фиксации.

git fetch -p && for branch in $(git for-each-ref --format '%(refname) %(upstream:track)' refs/heads | awk '$2 == "[gone]" {sub("refs/heads/", "", $1); print $1}'); do git branch -D $branch; done

8
@KrzysztofWende - не на Solaris и некоторых BSDs и некоторых ОС X :)
jww

4
Похоже, это также удалит любую ветку, которая «ушла» в последнем сообщении коммита.
dlsso

11
@dlsso Если в последнем коммит-сообщении есть строка «: ушел]», то да, оно также будет удалено. Вы можете сделать его более надежным за счет простоты, добавив дополнительный awk / gawk для удаления сообщения о коммите. git branch -vv | gawk '{print $1,$4}' | grep 'gone]' | gawk '{print $1}'
jason.rickman

2
В ответ на мой предыдущий комментарий (вопрос) текущая ветвь имеет * в качестве первого поля. Если он также окажется в списке «пропавших» ветвей, $ 1 будет назначен * и будет интерпретирован как спецификация файла с awk, выплевывающей имена файлов и папок. Я устранил выражение Grep и было AWK делать все фильтрации: awk '/: gone]/{if ($1!="*") print $1}'. Теперь это работает, как и ожидалось.
Рабен

5
@ahmedbhs, так как команда использует одинарные кавычки «вам нужно использовать двойные кавычки», чтобы окружить всю команду. Кроме того, псевдонимы git, которые являются командами оболочки (как эта), требуют! в начале. Это работает для меня:test = "!git fetch -p && for branch in `git branch -vv | grep ': gone]' | awk '{print $1}'`; do git branch -D $branch; done"
jason.rickman

308

Большинство из этих ответов на самом деле не отвечают на первоначальный вопрос. Я много копал, и это было самое чистое решение, которое я нашел. Вот немного более полная версия этого ответа:

  1. Проверьте вашу ветку по умолчанию. Как правилоgit checkout master
  2. Запустить git fetch -p && git branch -vv | awk '/: gone]/{print $1}' | xargs git branch -d

Объяснение:

Работает, обрезая ваши ветви отслеживания, затем удаляя локальные, которые показывают, что они "пропали" git branch -vv.

Ноты:

Если ваш язык настроен на что-то отличное от английского, вам нужно будет перейти goneна соответствующее слово. Только локальные ветви не будут затронуты. Ветви, которые были удалены на удаленном компьютере, но не были объединены, будут отображать уведомление, но не будут удалены на локальном компьютере. Если вы хотите удалить их, также измените -dна -D.


2
для французской ОС ушли, должны быть изменены по причине разногласия
Мохамед ЭЛЬ-ХАБИБ

4
следует добавить LANG = en_US перед веткой git для принудительного использования английского: git fetch --prune && LANG = en_US git branch -vv | awk '/: none] / {print $ 1}' | xargs git branch -d
Мохамед ЭЛЬ-ХАБИБ,

3
Я бы добавил git checkout master && ...в начале команды.
1

2
Это опасно, когда вы находитесь на ветке, которая должна быть удалена - в этом случае первый столбец - «*», который затем передается в xargs. Чтобы улучшить это, добавьте символ '*' перед передачей вывода в awk: sed -e 's / ^ * //'
meeee

6
Осторожный! Существует крайний случай, который приведет к удалению всех ваших локальных веток: если вы в данный момент находитесь на ветке, которая была удалена на удаленном компьютере, вывод git branch -vvначнется со звездочки, что в итоге приведет к выполнению git branch -d *. Вот исправленная версия, которая будет игнорировать строки со звездочкой:git branch -vv | grep ': gone]'| grep -v "\*" | awk '{ print $1; }' | xargs -r git branch -d
kcm

210

Обычно я не отвечаю на вопрос, в котором уже есть 16 ответов, но все остальные ответы неверны, а правильный ответ очень прост. Вопрос говорит: «Есть ли простой способ удалить все ветви отслеживания, удаленный эквивалент которых больше не существует?»

Если «простой» означает удаление их всех за один раз, не хрупкое, не опасное и не зависящее от инструментов, которые есть не у всех читателей, то правильный ответ: нет.

Некоторые ответы просты, но они не делают то, что просили. Другие делают то, что просили, но они не просты: все полагаются на синтаксический анализ выходных данных Git с помощью команд манипулирования текстом или языков сценариев, которые могут отсутствовать в каждой системе. Кроме того, в большинстве предложений используются фарфоровые команды, выходные данные которых не предназначены для анализа сценарием («фарфор» относится к командам, предназначенным для работы с человеком; сценарии должны использовать низкоуровневые команды «слесарного дела»).

Дальнейшее чтение:


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

  • git fetch --prune(или git fetch -p, который является псевдонимом, или git prune remote originкоторый делает то же самое без извлечения, и, вероятно, это не то, что вы хотите большую часть времени).
  • Обратите внимание на любые удаленные ветви, которые сообщаются как удаленные. Или, чтобы найти их позже, git branch -v(любая потерянная ветвь отслеживания будет помечена как «[ушел]»).
  • git branch -d [branch_name] на каждой осиротевшей ветви отслеживания

(это то, что предлагают другие ответы).

Если вы хотите написать сценарий решения, то for-each-refэто ваша отправная точка, как в ответе Марка Лонгаира здесь и на этот вопрос на другой вопрос , но я не могу найти способ использовать его без написания цикла сценария оболочки, без использования xargs или чего-то еще. ,


Исходное объяснение

Чтобы понять, что происходит, нужно понимать, что в ситуации отслеживания веток у вас есть не одна ветка, а три. (И помните, что «ветвь» означает просто указатель на коммит.)

Учитывая ветвь отслеживания feature/X, удаленный репозиторий (сервер) будет иметь эту ветвь и вызывать ее feature/X. Ваш локальный репозиторий имеет ветку, remotes/origin/feature/Xкоторая означает: «Это то, что удаленный сообщил мне, что его ветвь feature / X была, когда мы говорили в прошлый раз», и, наконец, локальный репозиторий имеет ветку, feature/Xкоторая указывает на ваш последний коммит, и настроен на «отслеживать» remotes/origin/feature/X, что означает, что вы можете тянуть и толкать, чтобы держать их вровень.

В какой-то момент кто-то удалил feature/Xна пульте. С этого момента вы остаетесь с вашим локальным feature/X(что, вероятно, вам больше не нужно, поскольку работа над функцией X предположительно завершена), и вашим, remotes/origin/feature/Xкоторый, безусловно, бесполезен, потому что его единственная цель состояла в том, чтобы запомнить состояние ветки сервера ,

И Git позволит вам автоматически очистить избыточный remotes/origin/feature/X- вот что git fetch --pruneделает - но по какой-то причине он не позволяет автоматически удалять свои собственные feature/X... даже если ваш файл feature/Xвсе еще содержит потерянные данные отслеживания, поэтому он содержит информацию идентифицировать бывшие ветви отслеживания, которые были полностью объединены. (В конце концов, он может дать вам информацию, которая позволит вам выполнить операцию вручную.)


3
Это гораздо более безопасный ответ. Кроме того, он будет работать, если вы используете рабочий процесс «Сквош и слияние», в отличие от выбранного ответа.
Джейк Левитт

3
Это действительно только отвечает на простую часть вопроса «как найти пропавшие ветви» (и с помощью той же команды, что уже была опубликована jason.rickman в 2015 году), но затем говорит вам, что нужно удалить все ветви вручную, что в точности соответствует ОП. не хочет делать
Во

4
@ Voo В этом суть ответа: не рассказать вам, как это сделать (это просто бонус), но сказать вам, что ответ заключается в том, что нет простого и легкого способа сделать это. Какой правильный ответ на вопрос, как он был сформулирован.
Эндрю Спенсер

1
«Если вы хотите сделать это безопасно, для случая использования в вопросе ..» - что сводит на нет большинство требований первого абзаца. «[Git] может дать вам информацию, которая позволит вам выполнить операцию вручную», - мы программисты, поэтому, учитывая информацию в виде списка (который показан), задача все еще проста (например, xargs). Существует также git aliasупрощение ряда случаев.
user2864740

2
@ user2864740 Некоторые читатели могут подумать, что написание небольшого bash-скрипта подпадает под их определение «простого», и это вполне оправданная позиция, но я дал свою собственную интерпретацию «простого» во 2-м абзаце, а остальная часть ответа была последовательной с этим. И в защиту моей по общему признанию ограничительной интерпретации, не все пользователи Git имеют xargsили bash, и они, вероятно, здесь не ищут проблему микрокодирования, так как быстрый ответ они могут безопасно применить, не отвлекая себя от их реальной цели ,
Эндрю Спенсер

52

Я нашел ответ здесь: Как я могу удалить все ветви git, которые были объединены?

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

Убедитесь, что мы держим хозяина

Вы можете убедиться, что masterили любая другая ветка в этом отношении не будет удалена, добавив другую grepпосле первой. В этом случае вы бы пошли:

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

Так что, если бы мы хотели сохранить master, developи, stagingнапример, мы бы пошли:

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

Сделайте этот псевдоним

Так как это немного долго, вы можете добавить псевдоним в ваш .zshrcили .bashrc. Шахта называется gbpurge(для git branches purge):

alias gbpurge='git branch --merged | grep -v "\*" | grep -v "master" | grep -v "develop" | grep -v "staging" | xargs -n 1 git branch -d'

Затем перезагрузите ваш .bashrcили .zshrc:

. ~/.bashrc

или

. ~/.zshrc

8
Полезно, но не то же самое, что "удалить ветки не на удаленном"
dlsso

Greate answer @karlingen, я постоянно использую gbpurge для всех своих сред разработки
Питер Долан,

50

Windows Solution

Для Microsoft Windows Powershell:

git checkout master; git remote update origin --prune; git branch -vv | Select-String -Pattern ": gone]" | % { $_.toString().Trim().Split(" ")[0]} | % {git branch -d $_}

Explaination

git checkout master переключается на главную ветку

git remote update origin --prune чернослив удаленные ветви

git branch -vvполучает подробный вывод всех ветвей ( ссылка на git )

Select-String -Pattern ": gone]" получает только записи, где они были удалены из удаленного.

% { $_.toString().Trim().Split(" ")[0]} получить название филиала

% {git branch -d $_} удаляет ветку


3
Спасибо за это, хотя мне пришлось добавить .Trim()после .toString(), чтобы удалить два пробела перед именем ветви.
Матфея

2
Спасибо за эту команду. Я должен был изменить , git branch -dчтобы git branch -Dя еще получаю ошибку ветвь не полностью слита.
Markieo

1
@markieo Вы , наверное , уже знаете это, но для кого -то еще - git branch -Dэто разрушительное и удалить локальную работу , которую вы еще не нажаты. -dвсегда безопасно, просто будьте осторожны с -D.
Нейт Барбеттини

33

Сопоставление с шаблоном «ушел» в большинстве других решений было для меня немного страшным. Чтобы быть более безопасным, этот --formatфлаг используется для извлечения статуса отслеживания восходящего направления каждой ветви .

Мне нужна была версия, удобная для Windows, поэтому она удаляет все ветви, которые перечислены как «пропавшие» с помощью Powershell:

git branch --list --format "%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)" | 
    ? { $_ -ne "" } | 
    % { git branch -D $_ }

Первая строка перечисляет названия локальных ветвей, чья ветвь вверх по течению «ушла». Следующая строка удаляет пустые строки (которые выводятся для ветвей, которые не «пропали»), затем имя ветви передается команде для удаления ветви.


6
--formatВариант , кажется, довольно новый; Мне нужно было обновить git с 2.10. До 2.16.3, чтобы получить его. Это моя модификация для систем Linux-ish:git branch --list --format "%(if:equals=[gone])%(upstream:track)%(then)%(refname)%(end)" | sed 's,^refs/heads/,,' | grep . | xargs git branch -D
bxm

2
Это лучшее решение на сегодняшний день. Одним из предложений является использование refname:short. Тогда вы можете удалить строку% { $_ -replace '^refs/heads/', '' }
Ioudas

2
Это отличное решение для окон. Я использую это так, потому что это более читабельно. git branch --list --format "%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)" | where { $_ -ne "" } | foreach { git branch -d $_ }Также, вероятно, хорошая идея использовать -dвместо -D. Принудительное удаление не должно быть необходимым для филиалов, которые больше не находятся на удаленном компьютере.
Рубанов

31

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

git checkout master && git pull origin master && git fetch -p && git branch -d $(git branch --merged | grep master -v)

или добавьте псевдоним:

alias gitcleanlocal="git checkout master && git pull origin master && git fetch -p && git branch -d $(git branch --merged | grep master -v)"

Объяснение:

git checkout master касса мастер ветка

git pull origin master убедитесь, что в локальном филиале все удаленные изменения объединены

git fetch -p удалить ссылки на удаленные ветки, которые были удалены

git branch -d $(git branch master --merged | grep master -v) удалить все ветви, которые были объединены в мастер, но не пытайтесь удалить сам мастер


3
Одно замечание, это очень полезно, но оно также удалит те ветви, которые никогда не были перенесены на удаленный компьютер. Безопаснее всего перечислять различия, а затем копировать то, что вы действительно хотите удалить, в git branch -Dкоманду
Zefiryn

Просто чтобы уточнить, Зефирин имеет в виду использование опции -D, которая не является частью однострочника.
cs01 12.12.14

1
Или используйте строчные буквы, git branch -dкоторые должны выдавать предупреждение о неперекачиваемых ветвях.
ACM

16
git fetch -p

Это удалит все ветви, которые больше не существуют на пульте.


64
это удаляет удаленные ссылки, но не сами локальные ветви. Хотя это полезная команда, я не думаю, что это отвечает на вопрос ОП.
thataustin

Какая? Это удаляет местные филиалы для меня.
Алекс Холл

1
@AlexHall Удаленный репозиторий имеет ветку X; ты git checkout X; теперь ваш репозиторий имеет (локальную) ветвь отслеживания Xи удаленную ветку origin/X; удаленный репозиторий удаляет X; ты git fetch-p; в вашем локальном хранилище не только, origin/Xно и Xбыли удалены. Это то, что вы говорите?
Эндрю Спенсер

16

И еще один ответ на кучу, в значительной степени основанный на ответе Патрика (который мне нравится, потому что кажется, что он устраняет любую двусмысленность в отношении того, где gone]будут совпадать git branchрезультаты), но с добавлением * nix bent.

В простейшем виде:

git branch --list --format \
  "%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)" \
  | xargs git branch -D

У меня есть это в git-goneсценарии на моем пути:

#!/usr/bin/env bash

action() {
  ${DELETE} && xargs git branch -D || cat
}

get_gone() {
  git branch --list --format \
    "%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)"
}

main() {
  DELETE=false
  while [ $# -gt 0 ] ; do
    case "${1}" in
      (-[dD] | --delete) DELETE=true ;;
    esac
    shift
  done
  get_gone | action
}

main "${@}"

NB - --formatвариант кажется довольно новым; Мне нужно было обновить git с 2.10. До 2.16.3, чтобы получить его.

РЕДАКТИРОВАТЬ: настроить, чтобы включить предложение refname:shortот Бенджамина В.

NB2 - я только проверял bash, отсюда хэшбэнг, но, вероятно, переносим sh.


Не можете ли вы пропустить sedчасть, используя %(refname:short)в первой строке?
Бенджамин В.

Кажется, работает для меня, и у меня есть это как аккуратный псевдоним Git - самое чистое решение из всех здесь!
Бенджамин В.

2.13 введено --format. Другой способ пропустить sedчасть состоит в том, чтобы использовать git update-ref -d. Обратите внимание, что это, вероятно, несколько небезопасно, использование git for-each-refздесь безопаснее (дано --shell).
gsnedders

Отличный ответ, и он помог мне ответить на мои собственные вопросы, когда я пытался --formatсделать это сам. Только один вопрос: почему #!bash? Все здесь выглядит портативным shдля меня.
Тоби Спейт

Это просто мой обычный шаблон, и нигде не проверял.
BXM

15

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

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

Отличный ответ! Мне нравится, как можно легко поиграть с 'git branch | grep -v "master" | grep -v "develop"такими вещами, прежде чем добавлять к удаленной части команды. Fin
finneycanhelp

Но это не отвечает на вопрос выше. Это приведет к удалению веток, даже если удаленный еще есть.
Джим Б.

13

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

git branch --merged | grep -v "*" | grep -v "master" | xargs git branch -d

И это удалит все ветви, уже удаленные из удаленного репозитория, на которые ссылается « origin », но которые все еще доступны локально в « remotes / origin ».

git remote prune origin

git branch -vv | grep 'gone]' | grep -v "\*" | awk '{print $1}' | xargs -r git branch -d Объяснение: Я предпочитаю заменять на git branch --merged, git branch -vvчтобы показать статус (ушел), потому что предыдущий git branch --mergedможет также показать мастер
jpmottin

13

Я не думаю, что есть встроенная команда, чтобы сделать это, но это безопасно сделать следующее:

git checkout master
git branch -d bug-fix-a

Когда вы используете -d, git откажется от удаления ветки, если она не будет полностью объединена с HEADветкой удаленного отслеживания в восходящем направлении. Таким образом, вы всегда можете просмотреть цикл вывода git for-each-refи попытаться удалить каждую ветвь. Проблема с этим подходом состоит в том, что я подозреваю, что вы, вероятно, не хотите, bug-fix-dчтобы его удаляли только потому, что он origin/bug-fix-dсодержит его историю. Вместо этого вы можете создать скрипт примерно так:

#!/bin/sh

git checkout master &&
for r in $(git for-each-ref refs/heads --format='%(refname:short)')
do
  if [ x$(git merge-base master "$r") = x$(git rev-parse --verify "$r") ]
  then
    if [ "$r" != "master" ]
    then
      git branch -d "$r"
    fi
  fi
done

Предупреждение: я не проверял этот скрипт - используйте только осторожно ...


Я позволил себе отредактировать сценарий. Все еще не дает никаких гарантий, но, он работает и, кажется, работает сейчас.
fwielstra

13

TL; DR:

Удалить ВСЕ локальные ветви, которые не находятся на удаленном

git fetch -p && git branch -vv | grep ': gone]' | awk '{print $1}' | xargs git branch -D

Удалите ВСЕ локальные ветви, которые не находятся на удаленном И полностью объединены И не используются, как сказано во многих ответах ранее.

git fetch -p && git branch --merged | grep -v '*' | grep -v 'master' | xargs git branch -d

объяснение

  • git fetch -p удалит все ветви, которые больше не существуют на удаленном
  • git branch -vv распечатает локальные ветви, а обрезанные ветви будут помечены gone
  • grep ': gone]' выбирает только те ветви, которые ушли
  • awk '{print $1}' отфильтруйте вывод, чтобы отобразить только название веток
  • xargs git branch -D будет перебирать все линии (ветви) и принудительно удалять эту ветку

Почему git branch -Dи нет у git branch -dвас будет для филиалов, которые не полностью объединены.

error: The branch 'xxx' is not fully merged.

1
ты хотел сказать удаленный вместо мастера?
Тинос


7

Основываясь на информации выше, это сработало для меня:

git br -d `git br -vv | grep ': gone] ' | awk '{print $1}' | xargs`

Удаляет все локальные ветки с ': gone] 'удаленно.


1
Похоже, это также удалит любую ветку, которая «ушла» в последнем сообщении коммита.
dlsso

Он также удалит любую ветку, которая имеет goneгде-либо в своем имени.
bfontaine

3
"git branch -D git branch -vv | grep ': away]' | awk '{print $ 1}' | xargs`" Это сработало для меня.
Мутху Ганапати Натан

7
grep gone <(git branch -v) | cut -d ' ' -f 3 | xargs git branch -d

Приведенная выше команда может использоваться для извлечения веток, которые объединены и удалены в удаленном режиме, и удаляет локальную ветвь, которая больше не доступна в удаленном


Лучшее решение до сих пор, хотя я изменил его , grep gone <(git branch -v) | cut -d ' ' -f 3 | xargs git branch -Dчтобы заставить удалить все
Shoaib

Опасно, если любое из названий вашей ветки содержит подстроку в goneлюбом месте (например usingonefunction).
Тоби Спейт

7

Ничто из этого не было действительно правильным для меня. Я хотел что-то, что очистило бы все локальные ветви, которые отслеживали удаленную ветвь, там origin, где удаленная ветвь была удалена ( gone). Я не хотел удалять локальные ветви, которые никогда не были настроены для отслеживания удаленной ветви (т.е. мои локальные ветви разработки). Также я хотел простой однострочник, который просто использует git, или другие простые инструменты CLI, вместо того, чтобы писать собственные сценарии. Я использовал немного grepи awkсделал эту простую команду.

Это в конечном итоге то, что закончилось в моем ~/.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'

ПРИМЕЧАНИЕ. В команде config я использую -dопцию git branchвместо -D, как в реальной конфигурации. Я использую, -Dпотому что я не хочу слышать, как Гит жалуется на неразделенные ветви. Вы можете также хотеть эту функциональность. Если это так, просто используйте -Dвместо -dв конце этой команды конфигурации.


Мне нравится подход git alias. Быстрый вопрос: зачем делать, git branch -vvа что делать, : gone]а не делать git branch -vи делать [gone]?
Лалиби

@Lalibi, хороший вопрос. Я не помню Я подозреваю, что что-то было не только с одним v. Если git branch -v | grep '[gone]'работает для вас, пойти на это. Это кажется немного чище.
Карл Уилбур

4

Основанный на Git Tip: Удаление старых локальных веток , который похож на решение jason.rickman, я реализовал специальную команду для этой цели под названием git, используя Bash:

$ git gone
usage: git gone [-pndD] [<branch>=origin]
OPTIONS
  -p  prune remote branch
  -n  dry run: list the gone branches
  -d  delete the gone branches
  -D  delete the gone branches forcefully

EXAMPLES
git gone -pn    prune and dry run
git gone -d     delete the gone branches

git gone -pn объединяет обрезку и перечисление «пропавших» веток:

$ git gone -pn
  bport/fix-server-broadcast         b472d5d2b [origin/bport/fix-server-broadcast: gone] Bump modules
  fport/rangepos                     45c857d15 [origin/fport/rangepos: gone] Bump modules

Затем вы можете нажать на курок, используя git gone -dилиgit gone -D .

Ноты

  • Регулярное выражение, которое я использовал, "$BRANCH/.*: gone]"где $BRANCHобычно будетorigin . Это, вероятно, не сработает, если ваш вывод Git локализован на французский и т. Д.
  • Себастьян Виснер также портировал его на Rust для пользователей Windows. Этот также называется мерзавец ушел .

Вероятно, это должен быть принятый ответ - git goneвыглядит как псевдоним для git branch -vv | grep 'origin/.*: gone]' | awk '{print $1}' | xargs git branch -d, который решает проблему ОП.
alex

4

Рисунок сильно от числа из других ответов здесь, я в конечном итоге со следующими (мерзавца 2,13 и выше только, я считаю), который должен работать на любой UNIX-подобные оболочки:

git for-each-ref --shell --format='ref=%(if:equals=[gone])%(upstream:track)%(then)%(refname)%(end)' refs/heads | while read entry; do eval "$entry"; [ ! -z "$ref" ] && git update-ref -d "$ref" && echo "deleted $ref"; done

Это, в частности, использует for-each-refвместо branch(как branchкоманда «фарфор», предназначенная для удобочитаемого вывода, а не для машинной обработки) и использует свой --shellаргумент для получения правильно экранированного вывода (это позволяет нам не беспокоиться о каком-либо символе в имени ссылки).


Это работает для меня, но было бы неплохо, если бы вы могли объяснить, что делают другие шаги в команде. Например, я не знаю, что [ ! -z "$ref" ]значит. Я думаю, что мультилинер уже помог бы. Но все равно спасибо за ваш вклад!
KevinH

4

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

Команда для удаления локальных веток не на удаленных:

for b in $(git for-each-ref --format='%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)' refs/heads); do git branch -d $b; done

Чтобы интегрировать его с gitconfig, чтобы его можно было запустить с git branch-prune :

удар

git config --global alias.branch-prune '!git fetch -p && for b in $(git for-each-ref --format='\''%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)'\'' refs/heads); do git branch -d $b; done'

PowerShell

git config --global alias.branch-prune '!git fetch -p && for b in $(git for-each-ref --format=''%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)'' refs/heads); do git branch -d $b; done'

(Нужна помощь в поиске универсальной команды для PowerShell и Bash)

Почему этот ответ самый лучший?

  • Предлагает полное решение: добавляет git branch-prune команду в ваш мерзавец
  • Работает нормально из Windows PowerShell
  • Основная идея состоит @ jason.rickman «s метод пуленепробиваемого с использованиемgit for-each-ref
  • Синтаксический анализ и фильтрация выполняются --filterбез внешних зависимостей.

Объяснение:

  • Добавляет новый псевдоним к вашему ~\.gitconfig . После выполнения этого вы можете просто сделатьgit branch-prune
  • Внутри этого псевдонима:
    • Получает ветки с --prune флагом, который «удаляет удаленные ветви отслеживания больше не на удаленном»
    • Использует git for-each-refи --filter, чтобы получить список филиалов [gone](без удаленного)
    • Перебирает этот список и удаляет ветку безопасно

1
Спасибо, @ jerry-wu, за то, что улучшили удивительность этого решения до бесконечности.
Химура

@ jerry-wu, и ваше последнее редактирование команды git config не работает в PowerShell ((
Himura,

1

Я придумал этот скрипт bash. Она всегда держать ветви develop, qa, master.

git-clear() {
  git pull -a > /dev/null

  local branches=$(git branch --merged | grep -v 'develop' | grep -v 'master' | grep -v 'qa' | sed 's/^\s*//')
  branches=(${branches//;/ })

  if [ -z $branches ]; then
    echo 'No branches to delete...'
    return;
  fi

  echo $branches

  echo 'Do you want to delete these merged branches? (y/n)'
  read yn
  case $yn in
      [^Yy]* ) return;;
  esac

  echo 'Deleting...'

  git remote prune origin
  echo $branches | xargs git branch -d
  git branch -vv
}

1

Я использую короткий метод, чтобы сделать трюк, я рекомендую вам сделать то же самое, так как это может сэкономить несколько часов и дать вам больше видимости

Просто добавьте следующий фрагмент в ваш .bashrc (.bashprofile на macos).

git-cleaner() { git fetch --all --prune && git branch --merged | grep -v -E "\bmaster|preprod|dmz\b" | xargs -n 1 git branch -d ;};
  1. Получить все пульты
  2. Получайте только слитые ветки из git
  3. Удалить из этого списка «защищенные / важные» ветки
  4. Удалить остальные (например, чистые и слитые ветви)

Вам нужно отредактировать регулярное выражение grep, чтобы оно соответствовало вашим потребностям (здесь это предотвращает удаление master, preprod и dmz)


git fetch --all --pruneсделал свое дело. Спасибо!
Леон - Хань Ли

1

Это сработало для меня:

git branch -r | awk '{print $1}' | egrep -v -f /dev/fd/0 <(git branch -vv | grep origin) | awk '{print $1}' | xargs git branch -d

о, я дважды опубликовал это на ... просто видел это при просмотре сообщений. Но вы действительно могли бы указать на парня, который предоставил эту команду вместо того, чтобы принять это как свою!
Двза

Я получаю это с форума, не пытайтесь быть умным, просто примите ответ или проигнорируйте его
Фарид Алнамрути,

Даже чем ты мог ... во всяком случае ... не пришел сюда, чтобы обсудить это с тобой. Как вы сказали ... примите мой комментарий или проигнорируйте его;)
Dwza

0

Я не уверен, как долго, но сейчас я использую git-up, который позаботится об этом.

я делаю git up и он начинает отслеживать новые ветви и удаляет старые.

Просто чтобы прояснить, это не готовая команда git - https://github.com/aanand/git-up

Кстати, он также прячет грязное дерево и делает перебазировки еще только с git up .

Надеюсь, это будет кому-то полезно


2
Это не удаляет локальные ветви, которые не существуют на сервере.
Эшли

0

Вот решение, которое я использую для раковины рыбы. Испытано на Mac OS X 10.11.5, fish 2.3.0и git 2.8.3.

function git_clean_branches
  set base_branch develop

  # work from our base branch
  git checkout $base_branch

  # remove local tracking branches where the remote branch is gone
  git fetch -p

  # find all local branches that have been merged into the base branch
  # and delete any without a corresponding remote branch
  set local
  for f in (git branch --merged $base_branch | grep -v "\(master\|$base_branch\|\*\)" | awk '/\s*\w*\s*/ {print $1}')
    set local $local $f
  end

  set remote
  for f in (git branch -r | xargs basename)
    set remote $remote $f
  end

  for f in $local
    echo $remote | grep --quiet "\s$f\s"
    if [ $status -gt 0 ]
      git branch -d $f
    end
  end
end

Несколько заметок:

Убедитесь в правильности установки base_branch. В этом случае я использую developв качестве базовой ветви, но это может быть что угодно.

Эта часть очень важна grep -v "\(master\|$base_branch\|\*\)". Это гарантирует, что вы не удалите master или вашу базовую ветку.

Я использую git branch -d <branch>в качестве дополнительной меры предосторожности, чтобы не удалять ветви, которые не были полностью объединены с вышестоящими или текущими заголовками.

Простой способ испытания заменить git branch -d $fс echo "will delete $f".

Я полагаю, я должен также добавить: ИСПОЛЬЗУЙТЕ НА СВОЙ СТРАХ И РИСК!


0

Я написал скрипт Python, используя GitPython для удаления локальных веток, которые не существуют на удаленном компьютере.

    import git
    import subprocess
    from git.exc import GitCommandError
    import os

    def delete_merged_branches():
        current_dir = input("Enter repository directory:")
        repo = git.Repo(current_dir)
        git_command = git.Git(current_dir)

        # fetch the remote with prune, this will delete the remote references in local.
        for remote in repo.remotes:
            remote.fetch(prune=True)

        local_branches = [branch.name for branch in repo.branches]
        deleted_branches = []

        # deleted_branches are the branches which are deleted on remote but exists on local.
        for branch in local_branches:
            try:
                remote_name = 'origin/'+ branch
                repo.git.checkout(remote_name)
            except GitCommandError:
            # if the remote reference is not present, it means the branch is deleted on remote.
                deleted_branches.append(branch)

        for branch in deleted_branches:
            print("Deleting branch:"+branch)
            git_command.execute(["git", "branch", "-D",branch])


        # clean up the work flow.
        repo.git.checkout('master')
        repo.git.pull()

    if __name__ == '__main__':
        delete_merged_branches()

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


0

Если вы используете zshоболочку с Oh My Zshустановленным, то самый простой способ сделать это безопасно - использовать встроенное автозаполнение.

Сначала определите, какие ветви вы хотите удалить:

~ git branch --merged

  branch1
  branch2
  branch3
* master

это покажет вам список уже слитых веток

После того, как вы знаете несколько, которые хотите удалить, введите:

~ git branch -d 

Все, что вам нужно сделать, это нажать [tab], и он покажет вам список местных отделений. Используйте табуляцию или просто нажмите [tab] еще раз, и вы можете переключаться между ними, чтобы выбрать ветку с помощью [enter].

Вкладка Выберите ветки снова и снова, пока у вас не появится список ветвей, которые вы хотите удалить:

~ git branch -d branch1 branch2 branch3

Теперь просто нажмите Enter, чтобы удалить свою коллекцию веток.

Если вы не используете zsh на своем терминале ... Получите это здесь.


0

Мне нравится использовать каналы, потому что это облегчает чтение команды.

Это моё решение, если вы хотите удалить все ветки, кроме master.

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

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

git branch --merged | grep feature_name | xargs -n 1 git branch -D

-3

Вот простой ответ, который работал для меня, используя клиент git:

Удалите хранилище полностью с вашего компьютера, а затем проверьте снова.

Никаких шуток с рискованными сценариями.


2
А как насчет филиалов, над
которыми

@ MailoSvětel, если они находятся на вашем пульте, вы можете просто потянуть их снова (не забудьте зафиксировать и перенести вашу последнюю работу на ваш пульт!)
Хуан Карлос Оспина Гонсалес

В моем вопросе и в большинстве ответов мы стараемся избегать ненужной работы. Другими словами: мне нужно просто удалить ветки, я больше не буду работать. Удаление репо, клонирование и повторное отслеживание ветвей - это много лишней работы для меня. Кроме того, некоторые работы могут быть потеряны :(
Майло Светел
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.