В чем разница между 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
Я не виню вас за то, что вы расстроены из-за этого. Лучший способ посмотреть на это. Существует потенциально три версии каждой удаленной ветки:
- Актуальная ветка в удаленном репозитории
(например, удаленное репо на https://example.com/repo.git, refs/heads/master
) - Ваш снимок этой ветки локально (хранится в
refs/remotes/...
)
(например, локальный репозиторий, refs/remotes/origin/master
) - И локальная ветка, которая может отслеживать удаленную ветку
(например, локальный репо, 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