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

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

пример:

филиалы (локальные и удаленные)

  • мастер
  • origin/master
  • origin / bug-fix-a
  • origin / bug-fix-b
  • origin / bug-fix-c

локально, у меня только ветку master. Теперь мне нужно работать над Исправлена ошибка-a, поэтому я проверяю его, работаю над ним и нажмите изменения на пульте ДУ. Затем я делаю то же самое с Исправлена ошибка-b.

филиалы (локальные и удаленные)

  • мастер
  • Исправлена ошибка-a
  • Исправлена ошибка-b
  • origin/master
  • origin / bug-fix-a
  • origin / bug-fix-b
  • origin / bug-fix-c

теперь у меня есть местные отделения мастер, Исправлена ошибка-a, Исправлена ошибка-b. Христос сопровождающий филиала объединит мои изменения в мастер и удалите все ветви, которые он уже объединил.

таким образом, текущее состояние теперь:

филиалы (локальные и удаленные)

  • мастер
  • Исправлена ошибка-a
  • Исправлена ошибка-b
  • origin/master
  • origin / bug-fix-c

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

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

25 ответов


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


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

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 }'`; do git branch -D $branch; done

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

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

объяснение:

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

Примечания:

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


Кажется, решение здесь -https://stackoverflow.com/a/1072178/133986

короче, git remote prune делает волшебство


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

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

убедитесь, что мы держим master

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

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

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

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

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

если "простой" означает не хрупкий, не опасный, и без опоры на инструменты, которые не все читатели будут иметь, то правильный ответ: нет.

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

дальнейшее чтение:https://stackoverflow.com/a/20107184/587365 и https://stackoverflow.com/a/26152574/587365

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

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

объяснения

чтобы понять, что происходит, вам нужно понять, что в ситуации отслеживания ветвей у вас есть не одна ветвь, а три. (И иметь в виду, что" ветвь " - это метка для указателя на фиксацию.)

филиала 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 по-прежнему содержит потерянную информацию отслеживания, поэтому он имеет информацию для идентификации бывших ветвей отслеживания они были полностью объединены. (В конце концов, он может дать вы информация, которая позволяет выполнять операцию вручную самостоятельно.)


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

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 checkout master branch

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

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

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


git fetch -p

это удалит все ветви, которые не отслеживаются удаленно.


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

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

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

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

при использовании -d, git откажется удалить ветку, если она не будет полностью объединена в HEAD или его восходящая ветвь удаленного отслеживания. Таким образом, вы всегда можете зациклиться на выходе git for-each-ref и попробуйте удалить каждую ветку. Проблема с этим подходом заключается в том, что я подозреваю, что вы, наверное, не хочу!--5--> быть удаленным только потому, что 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

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


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

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

и это удалит все ветви, которые уже были удалены из удаленного репозитория, на который ссылается "origin", но все еще локально доступны в "пульты дистанционного управления / origin".

git remote prune origin

Решение Для Windows

Для 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 $_}

объяснение

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

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

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

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

% { $_.toString().Trim().Split(" ")[0]} показать ветку имя

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


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

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

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

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


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

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

Он удаляет все локальные ветви с помощью are ': gone] ' на пульте дистанционного управления.


еще-другой-ответ для кучи, тяжело вытягивая из https://stackoverflow.com/a/48411554/2858703 (что мне нравится, потому что это, похоже, устраняет любую двусмысленность о том, где gone] будет соответствовать в git branch output) , но добавление * Nix bent:

git branch --list --format "%(if:equals=[gone])%(upstream:track)%(then)%(refname)%(end)" \
  | sed 's,^refs/heads/,,;/^$/d' \
  | 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)%(end)" \
    | sed 's,^refs/heads/,,;/^$/d'

}

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

main "${@}"

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


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

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


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

это в конечном итоге то, что закончилось в моем ~/.gitconfig:

[alias]
  prune-branches = !git remote prune origin && git branch -vv | grep ': gone]' | awk '{print }' | 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 }'"'"' | xargs -r git branch -d'

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


Я придумал этот сценарий. Он всегда держит ветви 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
}

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

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

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

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

чтобы было ясно, это не команда git из коробки -https://github.com/aanand/git-up

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

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


вот решение, которое я использую для рыбы оболочки. Протестировано на 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 }')
    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".

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


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

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

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


на основе Git Tip: Удаление Старых Локальных Ветвей, который похож на Джейсон.решение я реализовал собственную команду для этой цели под названием git gone использование 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 -D $(git branch | grep -v "master" | grep -v "develop")

это удалить любые ветви, не названные:master или develop.


это удалит все удаленные ветви, которые не присутствуют локально (в ruby):

bs = `git branch`.split; bs2 = `git branch -r | grep origin`.split.reject { |b| bs.include?(b.split('/')[1..-1].join('/')) }; bs2.each { |b| puts `git  push origin --delete #{b.split('/')[1..-1].join('/')}` }

пояснил:

# local branches
bs = `git branch`.split
# remote branches
bs2 = `git branch -r | grep origin`.split
# reject the branches that are present locally (removes origin/ in front)
bs2.reject! { |b| bs.include?(b.split('/')[1..-1].join('/')) }
# deletes the branches (removes origin/ in front)
bs2.each { |b| puts `git  push origin --delete #{b.split('/')[1..-1].join('/')}` }