Які відмінності між віддаленим чорносливом, git prune, git fetch --prune тощо


358

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

Більшість людей, які запитували про подібну проблему на переповнюванні стека чи інших веб-сайтах, проблеми гілок все ще відображаються у списку філій віддаленого відстеження git branch -aвнизу:

* master
  develop
  feature_blah
  remotes/origin/master
  remotes/origin/develop
  remotes/origin/feature_blah
  remotes/origin/random_branch_I_want_deleted

Однак у моїй ситуації галузь, яка не повинна бути там, локальна:

* master
  develop
  feature_blah
  random_branch_I_want_deleted
  remotes/origin/master
  remotes/origin/develop
  remotes/origin/feature_blah

Коли я виконую щось із наведеного нижче, він не видаляється локально:

$ git prune

Я також спробував:

$ git remote prune origin
$ git fetch --prune

Більш корисна інформація: Коли я перевіряю git remote show origin, як це виглядає:

* remote origin
Fetch URL: utilities:homeconnections_ui.git
Push  URL: utilities:homeconnections_ui.git
HEAD branch: master
Remote branches:
 master                        tracked
 develop                       tracked
 feature_blah                  tracked
 other123                      tracked
 other444                      tracked
 other999                      tracked
Local branches configured for 'git pull':
 develop                      merges with remote develop
 feature_blah                 merges with remote other999
 master                       merges with remote master
 random_branch_I_want_deleted merges with remote random_branch_I_want_deleted
Local refs configured for 'git push':
 develop         pushes to develop     (local out of date)
 master          pushes to master      (up to date)
 feature_blah    pushes to feature_blah(up to date)

Зауважте, що це лише у розділі під назвою Local branches configured for 'git pull':

Чому?


git branch -d the_local_branch
krsteeve

1
Дякую, але мені просто цікаво, чому це могло статися.
gogogadgetinternet

Була тонка різниця в роботі з ієрархією гілок ( x/y): вона була виправлена ​​(див. Мою відповідь нижче )
VonC

Відповіді:


664

Я не звинувачую вас у тому, що ви засмучені з цього приводу. Найкращий спосіб подивитися на це. У кожному віддаленому відділенні потенційно є три версії:

  1. Фактична гілка віддаленого сховища
    (наприклад, віддалене репо за адресою https://example.com/repo.git , refs/heads/master)
  2. Ваш знімок місцевої гілки (зберігається під refs/remotes/...)
    (наприклад, місцевий репо, refs/remotes/origin/master)
  3. І локальна гілка, яка може відслідковувати віддалену гілку
    (наприклад, локальний репо, refs/heads/master)

Почнемо з git prune. Це видаляє об'єкти , на які більше не посилаються, не видаляє посилання. У вашому випадку ви маєте місцеве відділення. Це означає, що існує посилання на ім'я, random_branch_I_want_deletedяке посилається на деякі об'єкти, які представляють історію цієї гілки. Отже, за визначенням, git pruneне видалять random_branch_I_want_deleted. Дійсно, git pruneце спосіб видалити дані, які накопичилися в Git, але ні на що не посилаються. Взагалі це не впливає на ваш погляд на будь-які гілки.

git remote prune originі git fetch --pruneобидва працюють на посиланнях refs/remotes/...(я буду називати їх віддаленими посиланнями). Це не впливає на місцеві відділення. git remoteВерсія корисна , якщо ви хочете , щоб видалити віддалені посилання під конкретний пульт дистанційного керування. Інакше двоє роблять точно те саме. Отже, коротше кажучи, git remote pruneі git fetch --pruneдійте на номер 2 вище. Наприклад, якщо ви видалили гілку за допомогою веб-інтерфейсу git web і не хочете більше відображатися у вашому локальному списку філій ( git branch -r), це команда, яку ви повинні використовувати.

Щоб видалити локальну гілку, слід скористатися git branch -d(або -Dякщо вона ніде не об'єднана). FWIW, немає команди git для автоматичного видалення локальних гілок відстеження, якщо віддалена гілка зникає.


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

14
Ця команда покаже список усіх локальних гілок, які не мають відповідної віддаленої гілки. Ви можете передавати це xargs git branch -D, але зауважте, що будь-які нові гілки, які ви створили, але ніколи не натискали на сервер, будуть видалені, тому ретельно ступайте: git branch -r | awk '{print $1}' | egrep -v -f /dev/fd/0 <(git branch -vv | grep origin) | awk '{print $1}'
Джейсон Уолтон,

4
@Seed Ні, це не так. :-( Він видаляє лише локальні відкликання відстеження. Я лише двічі перевірив це у версії 2.7.0.
Джон Сакмайстер

1
@ BlueRaja-DannyPflughoeft Будьте обережні з таким підходом. Наприклад, залежно від того, як ви стабільні гілки, вони можуть здатися об'єднаними в головну гілку, і ви в кінцевому підсумку видалите їх. Тут це не велика втрата, оскільки ви не видаляєте їх із сервера, але якщо у вас була спеціальна конфігурація, яку ви встановили для цього, то вона буде втрачена при видаленні гілки.
Джон Сакмайстер

1
@Cloud Не зовсім правда. Посилання можуть бути упаковані (див. packed-refsФайл у цій .gitобласті), тому видаляти їх через провідник файлів не обов'язково. Краще скористатися командами, щоб переконатися, що обидва доглядають правильно.
Джон Сакмайстер

55

git remote pruneі git fetch --pruneзробіть те ж саме: видаліть рефлекси на гілки, які не існують на пульті, як ви вже говорили. Друга команда підключається до пульта та отримує його поточні гілки перед обрізанням.

Однак це не торкається локальних гілок, які ви перевірили, і ви можете просто видалити їх

git branch -d  random_branch_I_want_deleted

Замініть -dна, -Dякщо філія не об’єднана в іншому місці

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


1
Я знаю, що це здається очевидним, але git pruneвиглядає не тільки для гілок та тегів, але й для всіх інших посилань.

Тож у моєму випадку, чому б не подіяти чорнослив? Тому що це не стосується місцевих відділень, а віддалених посилань? Дякуємо за стислу інформацію.
gogogadgetinternet

@hvd, які рефлекси існують, крім гілок та тегів?
CharlesB

@gogogadgetinternet так точно. (припустимо, ви мали на увазі git remote prune)
CharlesB

4
IMO умова іменування git використання "prune" як для збирання об'єктів, так і для очищення посилань - це місце, де виникає плутанина. Але це лише одна з багатьох загадок користувальницького інтерфейсу в git. :-)
torek

14

У випадку, якщо хтось зацікавиться. Ось швидкий скрипт оболонки, який видалить усі локальні гілки, які не відслідковуються віддалено. Слово обережності: Це дозволить позбутися будь-якої гілки, яка не відслідковується віддалено, незалежно від того, була вона об'єднана чи ні.

Якщо ви, хлопці, бачите якісь проблеми з цим, будь ласка, дайте мені знати, і я виправлю це (тощо. Тощо)

Збережіть його у файлі під назвою git-rm-ntb(називайте його будь-яким) PATHта запустіть:

git-rm-ntb <remote1:optional> <remote2:optional> ...

clean()
{
  REMOTES="$@";
  if [ -z "$REMOTES" ]; then
    REMOTES=$(git remote);
  fi
  REMOTES=$(echo "$REMOTES" | xargs -n1 echo)
  RBRANCHES=()
  while read REMOTE; do
    CURRBRANCHES=($(git ls-remote $REMOTE | awk '{print $2}' | grep 'refs/heads/' | sed 's:refs/heads/::'))
    RBRANCHES=("${CURRBRANCHES[@]}" "${RBRANCHES[@]}")
  done < <(echo "$REMOTES" )
  [[ $RBRANCHES ]] || exit
  LBRANCHES=($(git branch | sed 's:\*::' | awk '{print $1}'))
  for i in "${LBRANCHES[@]}"; do
    skip=
    for j in "${RBRANCHES[@]}"; do
      [[ $i == $j ]] && { skip=1; echo -e "\033[32m Keeping $i \033[0m"; break; }
    done
    [[ -n $skip ]] || { echo -e "\033[31m $(git branch -D $i) \033[0m"; }
  done
}

clean $@

Дякую! Приємний дотик з кольоровим виходом ;-)
Б. В. Бенгеров

2
Хіба не буде $ (git гілка -d $ i) безпечніше видаляти лише об'єднані гілки?
користувач2012677

Тож корисно дякую тобі !!!
Робін Хартленд

У більш безпечні варіанти обговорюються в stackoverflow.com/questions/7726949 / ...
Майкл Freidgeim

13

Слід зазначити , що одна відмінність між git remote --pruneі git fetch --pruneв даний час фіксується з фіксацією 10a6cc8 , від Тома Міллера ( tmiller) (для мерзотника 1.9 / 2.0, Q1 2014 року):

Коли у нас є гілка віддаленого відстеження з назвою " frotz/nitfol" з попереднього вибору, і тепер у верхній течії є гілка під назвою "** frotz " **, fetchне вдалося б видалити " frotz/nitfol" з " git fetch --prune" з висхідного потоку.
git сповістить користувача використовувати " git remote prune" для вирішення проблеми.

Отже: коли репо вгору за течією має гілку ("frotz") з такою ж назвою, як ієрархія гілки ("frotz / xxx", можлива умова іменування гілки ), досягла git remote --pruneуспіху (очищаючи гілку віддаленого відстеження від вашого репо) , але git fetch --pruneзазнав невдачі.

Більше:

Змініть спосіб " fetch --prune" роботи, перемістивши операцію обрізки перед операцією отримання.
Таким чином, замість попередження користувача про конфлікт, він автоматично виправляє його.

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