В чем разница между git удаленной чернотой, git черносливом, git fetch --prune и т.д.

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

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

Почему?

Ответ 1

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

  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 version полезна, если вы хотите удалить только удаленные ссылки под конкретным удаленным. В противном случае эти двое делают одно и то же. Короче говоря, git remote prune и git fetch --prune работают с номером 2 выше. Например, если вы удалили ветку с помощью веб-интерфейса git и больше не хотите, чтобы она отображалась в вашем локальном списке ветвей (git branch -r), то эту команду вам следует использовать.

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

Ответ 2

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

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

git branch -d  random_branch_I_want_deleted

Замените -d на -d, если ветвь не объединена в другом месте

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

Ответ 3

Обратите внимание, что одно различие между git remote --prune и git fetch --prune исправлено с фиксацией 10a6cc8 Томом Миллером (tmiller) (для git 1.9/2.0, tmiller квартал 2014 года):

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

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

Уже нет:

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

Ответ 4

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

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

Сохраните его в файле с именем git-rm-ntb (вызовите его как угодно) на PATH и запустите:

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

clean()
{
  REMOTES="[email protected]";
  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 [email protected]

Ответ 5

Это немного жестоко, но если вы не заботитесь о местной истории, и все важные ветки уже совершены. Это быстрый reset:

rm -rf .git
git init
git remote add [email protected]:my/test.git
git checkout master -f