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

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

Пример:

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

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

Локально у меня только мастер ветка. Теперь мне нужно поработать над 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.

Ответ 1

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

Ответ 2

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

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

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

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

Ответ 3

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

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

Объяснение:

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

Примечания:

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

Ответ 4

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

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

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

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


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

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

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

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


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

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

С учетом feature/X ветки отслеживания feature/X удаленный репозиторий (сервер) будет иметь эту ветку и называть ее feature/X Ваш локальный репозиторий имеет ветку remotes/origin/feature/X что означает: "Это то, что удаленный сообщил мне, что его ветвь 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 прежнему содержит потерянные данные отслеживания, она содержит информацию для идентификации бывших отслеживающих ветвей, которые были полностью объединены. (В конце концов, он может дать вам информацию, которая позволит вам выполнить операцию вручную.)

Ответ 5

Я нашел ответ здесь: Как удалить все ветки 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

Ответ 6

Кажется, решение здесь - fooobar.com/questions/12742/...

Короче говоря, git remote prune делает магию

Ответ 7

Удалите все ветки, которые были объединены в 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 главная ветка проверки

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

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

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

Ответ 8

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 переключается на ветку master

git remote update origin --prune удаленные ветки

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

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

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

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

Ответ 9

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

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

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

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

Ответ 10

git fetch -p

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

Ответ 11

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

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

Ответ 12

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

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

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

git remote prune origin

Ответ 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

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

Ответ 14

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

Ответ 15

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

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

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

Ответ 16

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

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

Ответ 17

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

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 в конце этой команды конфигурации.

Ответ 18

Основанный на 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. Этот также называется мерзавец ушел.

Ответ 19

Рисунок сильно от числа из других ответов здесь, я в конечном итоге следующее (мерзавец 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

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

Ответ 20

Я придумал этот bash script. Он всегда сохраняет ветки 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
}

Ответ 21

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

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

Ответ 22

git pull -p 

Если мы используем -p с pull, он удалит все удаленные ветки из локальной.

Ответ 23

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

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

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

Ответ 24

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

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

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

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

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

Ответ 25

Вот решение, которое я использую для рыбной оболочки. Протестировано на 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\|\*\)". Он гарантирует, что вы не удаляете мастер или базовую ветку.

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

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

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

Ответ 26

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

Просто добавьте следующий фрагмент в ваш .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;};
Код>
  • Получить все пульты
  • Получить только объединенные ветки из git
  • Удалить из этого списка "защищенные/важные" ветки
  • Удалите остальные (например, чистые и объединенные ветки)

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

Ответ 27

Просто удалите проект и снова нажмите git clone.

Ответ 28

Я написал скрипт на 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()

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

Ответ 29

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

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('/')}` }

Ответ 30

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

git branch -D $(git branch | grep -v "master" | grep -v "develop")

Это удаление любых ветвей, не названных: master или develop.