Прибирання старих віддалених гілок git


695

Я працюю з двох різних комп’ютерів (A і B) і зберігаю загальний пульт дистанційного керування у каталозі dropbox.

Скажімо, у мене є дві гілки, майстер і розробник. Обидва відстежують походження / майстер та походження / розвиток своїх віддалених колег.

Зараз, перебуваючи на комп’ютері A, я видаляю розробки відділення, локальні та віддалені.

git push origin :heads/devel
git branch -d devel

Працюючи git branch -aна комп’ютері A, я отримую наступний список галузей.

  • майстер
  • походження / ГОЛОВА
  • походження / майстер

Працюючи git fetchна комп’ютері B, я можу видалити локальну гілку розробок git branch -d devel, але я не можу видалити гілку віддаленої розробки.

git push origin :heads/devel повертає наступні повідомлення про помилки.

помилка: не в змозі перейти до некваліфікованого пункту призначення: heads / proxy3d Refspec
призначення не відповідає існуючому ref на пульті дистанційного управління, а також не починається з refs /, і ми не можемо відгадати префікс на основі джерела ref.
фатально: віддалений кінець повісив трубку несподівано

git branch -a все ще перелічує походження / розробку у віддалених гілках.

Як я можу очистити віддалені гілки від комп'ютера B?


4
Мені розповів той, хто це спробував, що сховища git у папках Dropbox трохи крихкі (але без додаткових деталей).
Thorbjørn Ravn Andersen

5
@ ThorbjørnRavnAndersen, ймовірно, тому, що вам доведеться чекати, щоб він повністю синхронізувався щоразу, коли ви виконуватимете зобов’язання, перш ніж ви можете бути впевнені, що це безпечно використовувати на іншій машині (і ще тоді потрібна інша синхронізація).
ataulm

Відповіді:


1240

По-перше, що є результатом роботи git branch -aмашини B?

По- друге, ви вже вилучені heads/develна origin, так ось чому ви не можете видалити його з машини B.

Спробуйте

git branch -r -d origin/devel

або

git remote prune origin

або

git fetch origin --prune

і сміливо додайте --dry-runдо кінця своєї gitзаяви, щоб побачити результат його запуску, не фактично запускаючи його.

Документи для git remote pruneта git branch.


50
git remote prune originпрацював на мене => * [pruned] origin/my-old-branch
Харі Карам Сінгх

126
git remote prune origin --dry-runпоказує, що було б видалено без фактичного виконання.
Вольфрам Арнольд

31
git fetch origin --pruneбуло ідеально для видалення видалених гілок
Sébastien Barbieri

10
Якщо у вас є локальна філія, яка відслідковує віддалений пульт, це нічого не видалить. Для тих, хто з'являється, git branch -vvслідує, git branch -D branchnameі нарешті, чорнослив - найкращий спосіб.
Роман Старков

7
Ви можете налаштувати обрізку, щоб вона відбулася автоматично при витягуванні / витягуванні, встановивши наступний варіант:git config remote.origin.prune true
Патрік Джеймс МакДугле

101

Розглянемо:

git fetch --prune

Регулярно в кожному РЕПО видаляти локальні гілки, які відстежують видалену гілку, яка видаляється (більше не існує у віддаленій репортажі GIT).

Це можна додатково спростити

git config remote.origin.prune true

це per-repoналаштування, яке зробить будь-яке майбутнє git fetch or git pullавтоматично обрізаним .

Щоб налаштувати це для свого користувача, ви можете також відредагувати глобальну .gitconfig та додати

[fetch]
    prune = true

Однак рекомендується зробити це за допомогою наступної команди:

git config --global fetch.prune true

або застосовувати його в системі (не тільки для користувача)

git config --system fetch.prune true

14

Ось сценарій bash, який може зробити це за вас. Це модифікована версія сценарію http://snippets.freerobby.com/post/491644841/remove-merged-branches-in-git . Моя модифікація дозволяє йому підтримувати різні віддалені місця.

#!/bin/bash

current_branch=$(git branch --no-color 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/\1/')
if [ "$current_branch" != "master" ]; then
  echo "WARNING: You are on branch $current_branch, NOT master."
fi
echo -e "Fetching merged branches...\n"

git remote update --prune
remote_branches=$(git branch -r --merged | grep -v '/master$' | grep -v "/$current_branch$")
local_branches=$(git branch --merged | grep -v 'master$' | grep -v "$current_branch$")
if [ -z "$remote_branches" ] && [ -z "$local_branches" ]; then
  echo "No existing branches have been merged into $current_branch."
else
  echo "This will remove the following branches:"
  if [ -n "$remote_branches" ]; then
echo "$remote_branches"
  fi
  if [ -n "$local_branches" ]; then
echo "$local_branches"
  fi
  read -p "Continue? (y/n): " -n 1 choice
  echo
  if [ "$choice" == "y" ] || [ "$choice" == "Y" ]; then
    remotes=`echo "$remote_branches" | sed 's/\(.*\)\/\(.*\)/\1/g' | sort -u`
# Remove remote branches
for remote in $remotes
do
        branches=`echo "$remote_branches" | grep "$remote/" | sed 's/\(.*\)\/\(.*\)/:\2 /g' | tr -d '\n'`
        git push $remote $branches 
done

# Remove local branches
git branch -d `git branch --merged | grep -v 'master$' | grep -v "$current_branch$" | sed 's/origin\///g' | tr -d '\n'`
  else
echo "No branches removed."
  fi
fi

1
Це зламалось на гілці під назвою "походження / особливість / мібрич", я не знаю чому.
Ставрос Корокітакіс

Проблема в двох sedс. Замінити sed 's/\(.*\)\/\(.*\)/\1/g'наsed 's/\([^/]*\)\/\(.*\)/\1/g'
Benoit Latinier

14

Ця команда видалить всі віддалені ( origin) об'єднані гілки, крім master. Ви можете змінити це або додати додаткові гілки після головного:grep -v for-example-your-branch-here |

git branch -r --merged | 
  grep origin | 
  grep -v '>' | 
  grep -v master | 
  xargs -L1 | 
  awk '{sub(/origin\//,"");print}'| 
  xargs git push origin --delete --dry-run

Якщо це добре виглядає, видаліть --dry-run. Крім того, ви можете спочатку перевірити це на вилці.


Приємно. Моя настройка за допомогою perl замість 1-го xargs + awk: git branch -r --merged | греп походження | grep -v '>' | grep -v майстер | perl -lpe '($ junk, $ _) = split (/ \ //, $ _, 2)' | xargs git push origin --delete
Андрій

6

Якщо git branch -rвідображається багато гілок віддаленого відстеження, які вас не цікавлять, і ви хочете видалити їх лише з локальних даних, скористайтеся такою командою:

git branch -r | grep -Ev 'HEAD|master|develop'  | xargs -r git branch -rd

Більш безпечною версією буде видалення лише об'єднаних:

git branch -r --merged | grep -Ev 'HEAD|master|develop'  | xargs -r git branch -rd

Це може бути корисно для великих проектів, де вам не потрібні гілки функцій інших товаришів по команді, але є багато відділень віддаленого відстеження, знайдених на початковому клоні.

Однак, цього кроку недостатньо, оскільки ті видалені гілки віддаленого відстеження повернуться наступним чином git fetch.

Щоб зупинити отримання цих гілок віддаленого відстеження, вам потрібно чітко вказати коефіцієнти refs для отримання у .git / config :

[remote "origin"]
  # fetch = +refs/heads/*:refs/remotes/origin/*    ### don't fetch everything
  fetch = +refs/heads/master:refs/remotes/origin/master
  fetch = +refs/heads/develop:refs/remotes/origin/develop
  fetch = +refs/heads/release/*:refs/remotes/origin/release/*

У наведеному вище прикладі ми тільки витягти master, developі звільнити гілки, НЕ соромтеся , щоб адаптуватися , як вам потрібно.


1
Дякую, перша команда працювала на мене. Ви також можете отримати лише одну гілку з git fetch origin branchnameабо створити псевдонім, як ft = "!f() { git fetch origin $(git rev-parse --abbrev-ref HEAD);}; f"щоб отримати лише поточну гілку (мій особистий улюблений). Ура.
ДжованіМорено

Можливо, ОТ, але що означає -rпрапор? Я бачу xargs, є -Rаргумент, але нічого не знайшов -r. Я маю на увазі, якщо теоретично я добре пам'ятаю, як xargsпрацює, навіть без -rцього він повинен працювати.
Aldo 'xoen' Giambelluca

Мені подобається ця відповідь. Пару приміток (констатуючи очевидне насправді). Можна "переглянути", які гілки будуть видалені, видаливши останню трубу та останню команду | xargs git branch -d. Також, видаляючи -rопцію ( --remotes), git branch -dми очищаємо лише локальні гілки (що може бути досить враховуючи, що за замовчуванням все git branchодно не відображаються віддалені гілки).
Aldo 'xoen' Giambelluca

Дякую! Це саме те, що мені було потрібно. Інші рішення пропонують підштовхувати обрізані місцеві гілки до віддаленого, щоб також їх видалити, але це не допомагає, коли віддалений був видалений або його більше немає. Цей підхід видалив локальні посилання на віддалені гілки, до яких більше не маю доступу.
обережністьбуг

@aldo, про xargs -r, а саме --no-run-if-empty, це означає розширення GNU, ось приємне пояснення .
ryenus

4

Видалення - це завжди складне завдання і може бути небезпечним !!! Тому спочатку виконайте таку команду, щоб побачити, що буде:

git push --all --prune --dry-run

Роблячи так, як описано вище, gitви надасте вам список того, що станеться, якщо виконується команда нижче.

Потім запустіть наступну команду, щоб видалити всі гілки з віддаленого репо, які не є у вашому локальному репо:

git push --all --prune

10
Ця команда видається небезпечною ... Вдалось видалити те, що я хотів (і не міг зробити принаймні чотири відповіді, наведені вище). Але він також видалив чотири інші відділи розробки. Git абсолютно смокче ...
jww

2
Ці відділення, можливо, не були у вашому населеному пункті. Однак все не втрачено. Git commit, Git reflog, а потім скидання git --hard <checksum>. Ви можете буквально на будь-який вчинок (він же зберегти) та інші. Відділення - це лише мітка, видалення мітки не видаляє збереження ... вона назавжди матиме контрольну суму. Дайте мені знати, чи можу я допомогти
Тімоті ЛЖ Стюарт

3
Звичайно, ви захочете відновити їх досить швидко, оскільки збирач сміття Git згодом видалить комісії, на які не посилаються гілки.
Андрій

1
Добре додати -n(сухий запуск) до цієї команди, щоб ви могли переглянути попередні зміни, а потім, якщо все добре, зателефонуйте ще раз без цього -n.
mati865

1
Погодьтеся з @GuiWeinmann - Це занадто небезпечно, особливо без конкретного опису, щоб принаймні виконати це в першу чергу.
Вівек М. Чаула

2

Ось як це зробити з SourceTree (v2.3.1):
1. Клацніть Вибір
2. Поставте прапорець "Відрізати гілки відсіку ..."
3. Натисніть OK
4. 😀

введіть тут опис зображення


1

Тут мені доведеться додати відповідь, тому що інші відповіді або не висвітлюють мою справу, або непотрібні. Я використовую github разом з іншими розробниками, і я просто хочу, щоб усі локальні гілки, віддалені (можливо, об'єднані та) видалені з PR github, були видалені за один раз з моєї машини. Ні, такі речі git branch -r --mergedне охоплюють гілки, які не були об'єднані локально, або ті, які взагалі не були об'єднані (покинуті) тощо, тому потрібне інше рішення.

У будь-якому випадку, перший крок я отримав з інших відповідей:

git fetch --prune

Сухий пробіг git remote prune originздавався, що це зробить те саме в моєму випадку, тому я пішов з найкоротшою версією, щоб зробити це просто.

Тепер git branch -vслід позначити гілки, видалені видалені як [gone]. Тому все, що мені потрібно зробити:

git branch -v|grep \\[gone\\]|awk '{print $1}'|xargs -I{} git branch -D {}

Настільки ж просто, він видаляє все, що я хочу для вищевказаного сценарію.

Менш поширений xargsсинтаксис полягає в тому, що він також працює на Mac & BSD на додаток до Linux. Обережно, ця команда не є сухим виконанням, тому вона змусить видалити всі гілки, позначені як [gone]. Очевидно, що це git нічого не пропаде назавжди, якщо ви бачите видалені гілки, які ви пам’ятаєте, що хотіли зберегти їх, ви завжди можете їх скасувати (вищевказана команда перерахувала їх хеш при видаленні, настільки проста git checkout -b <branch> <hash>.


0
# First use prune --dry-run to filter+delete the local branches
git remote prune origin --dry-run \
  | grep origin/ \
  | sed 's,.*origin/,,g' \
  | xargs git branch -D

# Second delete the remote refs without --dry-run
git remote prune origin

Обріжте ті ж гілки з локальних та віддалених реф (на моєму прикладі з origin).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.