Удалить отслеживание веток больше не на удаленном - PullRequest
851 голосов
/ 11 октября 2011

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

Пример:

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

  • master
  • origin / master
  • origin / bug-fix-a
  • origin / bug-fix-b
  • origin / bug-fix-c

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

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

  • master
  • bug-fix-a
  • bug-fix-b
  • origin / master
  • origin / bug-fix-a
  • origin / bug-fix-b
  • origin / bug-fix-c

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

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

Ветви (локальные и удаленные)

  • master
  • bug-fix-a
  • bug-fix-b
  • origin / master
  • origin / bug-fix-c

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

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

Ответы [ 26 ]

13 голосов
/ 27 февраля 2017

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

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

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

git remote prune origin
12 голосов
/ 11 октября 2011

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

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

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

12 голосов
/ 28 февраля 2018

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

git branch | grep -v "master" | grep -v "develop" | xargs git branch -D
7 голосов
/ 27 марта 2018

И еще один ответ на кучу, в значительной степени опирающийся на https://stackoverflow.com/a/48411554/2858703 (что мне нравится, потому что кажется, что он устраняет любую двусмысленность относительно того, где gone] будет совпадать в выводе git branch), но добавляя * 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 "${1}" in
      (-[dD] | --delete) DELETE=true ;;
    esac
    shift
  done
  get_gone | action
}

main "${@}"

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

6 голосов
/ 23 июня 2016

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

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

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

5 голосов
/ 17 августа 2018
grep gone <(git branch -v) | cut -d ' ' -f 3 | xargs git branch -d

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

5 голосов
/ 06 февраля 2018

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

2 голосов
/ 23 мая 2019

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

2 голосов
/ 27 сентября 2018

На основе Git Совет: удаление старых локальных веток , что похоже на решение jason.rickman Я реализовал для этой цели собственную команду под названием git seen использование 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.Этот также называется мерзавец ушел .
1 голос
/ 19 февраля 2018

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

git branch -r | awk '{print $1}' | egrep -v -f /dev/fd/0 <(git branch -vv | grep origin) | awk '{print $1}' | xargs git branch -d
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...