В чем разница между git remote prune, git prune, git fetch --prune и т. Д.

Моя ситуация такова ... кто-то, работающий над одним и тем же репо, удалил ветку из своего локального и удаленного репо ...

У большинства людей, которые спрашивали об этой проблеме на Stack Overflow или на других сайтах, проблема с ветвями, которые все еще отображаются в их списке веток удаленного отслеживания 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':

Почему?


person gogogadgetinternet    schedule 20.11.2013    source источник
comment
Спасибо, но мне просто любопытно, почему это могло произойти.   -  person gogogadgetinternet    schedule 21.11.2013
comment
При работе с иерархией ветвей (x/y) была небольшая разница: она была исправлена ​​(см. мой ответ ниже)   -  person VonC    schedule 12.01.2014


Ответы (4)


Я не виню вас за то, что вы разочаровались из-за этого. Лучше всего посмотреть на это. Потенциально существует три версии каждой удаленной ветки:

  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 и больше не хотите, чтобы она отображалась в вашем списке локальных веток (git branch -r), то вам следует использовать эту команду.

Чтобы удалить локальную ветку, вы должны использовать git branch -d (или -D, если она нигде не объединена). FWIW, нет команды git для автоматического удаления локальных ветвей отслеживания, если удаленная ветка исчезает.

person John Szakmeister    schedule 20.11.2013
comment
Это позволяет лучше ответить на общий вопрос, объясняя соответствующие различия. Он также отвечает на дополнительные вопросы, которые у меня возникли из приведенного выше. - person gogogadgetinternet; 21.11.2013
comment
Эта команда покажет список всех локальных веток, у которых нет соответствующей удаленной ветки. Вы можете перенаправить это на xargs git branch -D, но учтите, что любые новые ветки, которые вы создали, но никогда не отправляли на сервер, будут удалены, поэтому действуйте осторожно: git branch -r | awk '{print $1}' | egrep -v -f /dev/fd/0 <(git branch -vv | grep origin) | awk '{print $1}' - person Jason Walton; 11.09.2014
comment
Я написал скрипт для удаления веток, уже объединенных в разработку. Я думаю, это безопаснее, чем подход @JasonWalton. Все сироты, оставшиеся под refs/remotes/..., затем удаляются случайным git-gc. - person amoebe; 11.04.2016
comment
@Seed Нет, это не так. :-( Он удаляет только локальные ссылки удаленного отслеживания. Я только что перепроверил это с версией 2.7.0. - person John Szakmeister; 09.05.2016
comment
Я положил alias gitcleanup="git fetch --prune && git branch --merged | egrep -v \"(^\*|master|dev)\" | xargs git branch -d" в свой ~/.profile файл. Затем я могу просто запустить gitcleanup в корне проекта, чтобы очистить все удаленное отслеживание и локальные ветки. - person BlueRaja - Danny Pflughoeft; 07.03.2017
comment
@ BlueRaja-DannyPflughoeft Будьте осторожны с таким подходом. Например, в зависимости от того, как вы делаете свои стабильные ветки, они могут казаться объединенными в основную ветку, и вы в конечном итоге их удалите. Это не большая потеря, поскольку вы не удаляете их с сервера, но если у вас была какая-либо специальная конфигурация, которую вы установили для нее, она будет потеряна при удалении ветки. - person John Szakmeister; 07.03.2017
comment
пожалуйста, не используйте ветку git для написания сценариев и рассмотрите следующий ответ: stackoverflow.com/questions/10610327/ - person Yolgie; 26.09.2017
comment
Чтобы понять ваше примечание о трех версиях каждой ветки: если у меня есть удаленная ветка с именем master ... 1) будет ли это «удаленная ветка»? и я делаю git checkout -b master upstream/master, тогда 2) это будет «снимок»? Если эти двое правы, то я не знаю, что это за третий. Вы можете объяснить? - person Honey; 25.01.2019
comment
@Honey Хорошие вопросы. В этом случае термин удаленная ветвь перегружен в большинстве дискуссий о Git - люди используют его для обозначения как локального снимка, так и фактической ветки в удаленном репозитории. Если бы у меня были мои коллеги по этому поводу, я бы назвал главную ветвь в удаленном репозитории удаленной веткой, последняя версия этой ветки была загружена в локальный репозиторий (с именем origin / master в данном случае) снимком. И главная ветка, которую вы проверили локально, локальную ветвь. Это помогает? - person John Szakmeister; 26.01.2019
comment
@Honey Я обновил 3 маркера, чтобы включить пример того, где найти 3 версии. Надеюсь, это поможет. - person John Szakmeister; 26.01.2019
comment
Вы также можете просто удалить их вручную через файловый менеджер. - person Cloud; 30.04.2019
comment
@Cloud Не совсем так. Ссылки могут быть упакованы (см. Файл packed-refs в области .git), поэтому не обязательно просто удалить их через проводник. Лучше использовать команды, чтобы убедиться, что обе заботятся правильно. - person John Szakmeister; 30.04.2019

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

Однако он не касается локальных веток, которые вы проверили, которые вы можете просто удалить с помощью

git branch -d  random_branch_I_want_deleted

Замените -d на -D, если ветка не объединена где-либо еще

git prune делает что-то другое, он очищает недостижимые объекты, те коммиты, которые недоступны ни в одной ветке или теге и, следовательно, больше не нужны.

person CharlesB    schedule 20.11.2013
comment
Я знаю, что это кажется очевидным, но git prune ищет не только ветки и теги, но и все остальные ссылки. - person ; 21.11.2013
comment
Так почему в моем случае не работает git prune? Потому что его не волнуют локальные ветки, а удаленные ссылки? Спасибо за краткую информацию. - person gogogadgetinternet; 21.11.2013
comment
@hvd какие ссылки есть, кроме веток и тегов? - person CharlesB; 21.11.2013
comment
@gogogadgetinternet, да, именно так. (предположим, вы имели в виду git remote prune) - person CharlesB; 21.11.2013
comment
@CharlesB По крайней мере, reflog, отдельная HEAD, замена refs (git replace), но, вероятно, и многое другое. (Честно говоря, я, возможно, ошибся, позвонив всем этим рефери, я не уверен, что это правильный термин.) - person ; 21.11.2013
comment
ИМО, соглашение об именах git об использовании prune для коллекции объектов и reference-cleanup - вот где возникает путаница. Но это только одна из многих загадок пользовательского интерфейса в git. :-) - person torek; 21.11.2013

В том случае, если кому будет интересно. Вот быстрый сценарий оболочки, который удалит все локальные ветки, которые не отслеживаются удаленно. Предупреждение: это избавит от любой ветки, которая не отслеживается удаленно, независимо от того, была она объединена или нет.

Если вы, ребята, заметите какие-либо проблемы с этим, дайте мне знать, и я исправлю это (и т. Д. И т. Д.).

Сохраните его в файле с именем 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 $@
person Pomme.Verte    schedule 27.03.2014
comment
Разве $ (git branch -d $ i) не будет безопаснее удалять только объединенные ветки? - person user2012677; 09.05.2019
comment
Более безопасные варианты обсуждаются в stackoverflow.com/questions/7726949/ - person Michael Freidgeim; 10.05.2020

Обратите внимание, что одно различие между git remote --prune и git fetch --prune исправлено: commit 10a6cc8, Том Миллер (tmiller) (для git 1.9 / 2.0, первый квартал 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", переместив операцию сокращения до операции выборки.
Таким образом, вместо предупреждения пользователя о конфликте он автоматически исправляет его.

person VonC    schedule 12.01.2014