Могут ли "удаленная ветвь", "ветка удаленного отслеживания" и "ветвь отслеживания" иметь разные имена?
Я играю с git.
Текущий статус:
1) в моем локальном репо есть одна ветка master_local.
2) удаленное репо имеет одну ветку master_remote. (имя пульта - hehe_server)
3) мой местный .git/config
выглядит как
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
ignorecase = true
precomposeunicode = true
[remote "hehe_server"]
url = /path/to/git/remote_main.git
fetch = +refs/heads/*:refs/remotes/hehe_server/*
[branch "master_local"]
remote = hehe_server
merge = refs/heads/master_remote
4) когда я бегу git fetch
, git получит master_remote@hehe_server
к hehe_server/master_remote@local (aka, /.git/refs/remotes/hehe_server/master_remote@local)
5) когда я бегу git branch -vv
, это говорит
* master_local 06022cf [hehe_server/master_remote] my_commit_msg
6) Я так понимаю
я. master_local@local
называется "отслеживающая ветвь"
II. master_remote@hehe_server
называется "удаленная ветка"
iii. hehe_server/master_remote@local
называется "ветвью удаленного отслеживания"
7) Моя версия git - версия git 2.23.0.
8) Я использую Mac 10.15.1
Мой вопрос:
Я хочу переименовать hehe_server/master_remote@local
к hehe_server/master_haha@local
, оставив все остальное без изменений. Я могу это сделать?
Мой эксперимент:
Я пробовал играть с fetch =
линия внутри .git/config
, но это действительно сбивает с толку...
Тест 1
менять fetch = +refs/heads/*:refs/remotes/hehe_server/*
к fetch = +refs/heads/master_local:refs/remotes/hehe_server/master_remote
Результат 1
git branch -vv говорит
* master_local 06022cf my_commit_msg
Кажется, master_local больше не отслеживает master_remote.. Я не понимаю.
Тест 2
менять fetch = +refs/heads/*:refs/remotes/hehe_server/*
к fetch = +refs/heads/master_local:refs/remotes/hehe_server/master_haha
Результат 2
как результат 1
2 ответа
Терминология Git здесь... не такая уж хорошая. В частности, термины удаленная ветвь и отслеживающая ветка вообще не определены. См. Gitglossary, чтобы узнать, что это определено.
Тем не менее, люди иногда используют фразу удаленная ветвь для обозначения либо имени ветки удаленного отслеживания, либо результата проверки имен веток на удаленном компьютере. Люди - и книга Git - иногда используют ветвь отслеживания фраз для обозначения ветки, для которой установлен восходящий поток.
Ваше определение ветки удаленного отслеживания совпадает с определением в Gitglossary. Мне не нравится этот термин, поскольку он приводит к тому, что люди отказываются от прилагательного отслеживания и называют его удаленной ветвью, что разные люди интерпретируют по-разному. (Я предпочитаю называть это именем удаленного отслеживания, хотя на самом деле это не является значительным улучшением. Главное улучшение, если оно есть, заключается в том, что снова не используется слово "ветвь".:-))
Более общий термин, который не страдает от всего вышеперечисленного, - это ref (сокращенно для ссылки; большую часть времени я стараюсь излагать его подробно). Если вы посмотрите глоссарий Git, то увидите, что он определяется как:
Имя, которое начинается с
refs/
(напримерrefs/heads/master
), который указывает на имя объекта или другую ссылку (последняя называется символической ссылкой). Для удобства ссылку иногда можно сократить, когда она используется в качестве аргумента команды Git; подробности см. в gitrevisions[7]. Ссылки хранятся в репозитории.
В любом случае: да, вы можете производить произвольные модификации имен, как вы предлагаете. Вfetch =
строки в вашем .git/config
определить, как будет изменен каждый реф.
Когда ты бежишь git fetch
, первым шагом процесса является то, что ваш Git вызывает какой-то другой Git. URL-адрес, по которому ваш Git достигает этого Git, происходит от:
- командная строка, если вы запустите
git fetch https://github.com/owner/repo.git
например, или - сохраненный URL-адрес под именем удаленного, в данном случае тот, который хранится под
hehe_server
поскольку вы использовалиgit fetch hehe_server
.
(Есть несколько других способов указать URL-адреса репозитория, так как до изобретения пультов было много истории. Это два общих метода.)
Установив это соединение, другой Git выдает все свои ссылки. 1 Вы можете убедиться в этом сами, используяgit ls-remote
:
git ls-remote hehe_server
Результатом этой команды является набор ссылок и хеш-идентификаторов, которые ваш Git видит, когда их Git представляет их.
В любом случае ваш Git теперь может принимать эти ссылки и работать с ними в соответствии с инструкциями fetch =
настройки. Каждая настройка состоит из refspec. Refspecs описаны в git fetch
документация, но в основном они состоят из:
- необязательный ведущий
+
иероглиф, означающий силу; - источник имя или шаблон;
- символ двоеточия
:
; а также - назначения имя или шаблон.
Имя или шаблон источника сопоставляются с именами, которые представляет другой Git. Полученное в результате имя или шаблон назначения используется для создания имени, которое ваш Git создаст или обновит (или, с--prune
, удалите, если имя входа не совпадает).
Здесь есть некоторые странные ограничения. В частности, если вы настроили несколько имен источников, которые соответствуют одному месту назначения, или один источник, который соответствует нескольким назначениям, это не сработает. Например:
+refs/heads/master:refs/remotes/hehe_server/foo
+refs/heads/master:refs/remotes/hehe_server/bar
вызывает один источник, master
, чтобы отобразить на два выхода, и:
[remote "hehe_server"]
fetch = +refs/heads/master:refs/remotes/hehe_server/foo
fetch = +refs/heads/develop:refs/remotes/hehe_server/foo
вызывает два источника, master
а также develop
, чтобы сопоставить с одним выходом. Ни с одним из них нельзя обращаться с пользой.
Я хочу переименовать
hehe_server/master_remote@local
кhehe_server/master_haha@local
, оставив все остальное без изменений. Могу ли я сделать это?
Вроде да, но в основном нет. В частности, если вы хотите взять ихrefs/heads/master
и назови это refs/remotes/hehe_server/master_haha
, эта часть проста:
fetch = +refs/heads/master:refs/remotes/hehe_server/master_haha
делает свое дело. Но если теперь вы хотите взять все оставшиеся имена и обработать их обычным способом:
fetch = +refs/heads/*:refs/remotes/origin/*
вы сказали Git, что refs/heads/master
должны стать двумя именами локально, потому что вторая строка сопоставляет имя сrefs/remotes/origin/master
.
Это означает, что для того, чтобы это работало, вы должны:
- связаться с другим Git
- получить полный список всех названий их веток
- напишите новый набор
remote.hehe_server.fetch
строк, по одной строке на имя ветки, с желаемым отображением: все, кроме ихmaster
карты как обычно, а ихmaster
карты странно.
Каждый раз, когда набор имен веток на их сервере изменяется, вы должны повторять этот процесс.
1 Новый проводной протокол позволяет фильтровать ссылки на стороне сервера. Без этой фильтрации репозиторий со множеством тегов и / или веток может выбросить несколько мегабайт нежелательных данных на ваш Git, прежде чем ваш Git сможет начать с ним полезную беседу. Но это - выдача всех ссылок - вот что происходит со старым протоколом.
Это не ответ. Я поместил свой тестовый сценарий в этот ответ, чтобы другие получили полную картину.
#!/bin/bash
echo "
change branches' names
refs/heads/master_local
refs/remote/hehe_server/master_haha
master_remote@remote
"
PATHA=/path/to/an/empty/folder/
# Any subsequent(*) commands which fail will cause the shell script to exit immediately
set -e
# Makes the bash script to print out every command before it is executed except echo
trap '[[ $BASH_COMMAND != echo* ]] && echo "++++++RUN COMMAND: Line ${LINENO}: $BASH_COMMAND --- RESULT IS A BELOW"' DEBUG
cd $PATHA
echo "make a bare repo"
git --git-dir=$PATHA/remote_main.git init --bare
echo "clone"
cd $PATHA
git clone $PATHA/remote_main.git main --origin hehe_server
echo "------------------------------------------------------------------------------------------------------------------------------------"
echo "commit and push in master"
cd $PATHA/main
echo "test@master" > $PATHA/main/index.js
git add .
git commit -m "commit and push in master"
git push
echo "------------------------------------------------------------------------------------------------------------------------------------"
echo "commit and push in feature"
git checkout -b feature
echo "test@feature" > $PATHA/main/index.js
git add .
git commit -m "commit and push in feature"
git push -u hehe_server feature
git checkout master
echo "------------------------------------------------------------------------------------------------------------------------------------"
echo "commit and push in release"
git checkout -b release
echo "test@release" > $PATHA/main/index.js
git add .
git commit -m "commit and push in release"
git push -u hehe_server release
git checkout master
echo "------------------------------------------------------------------------------------------------------------------------------------"
echo "master@local --> master_local, master@hehe_server --> master_remote@hehe_server"
echo "# create and switch to the release branch"
git checkout -b master_local master
echo "# push the master_local branch to the remote and track it"
git push -u hehe_server master_local:master_remote
echo "# delete local master"
git branch -d master
echo "# delete remote master"
git --git-dir=$PATHA/remote_main.git symbolic-ref HEAD refs/heads/master_remote
git push --delete hehe_server master
echo "------------------------------------------------------------------------------------------------------------------------------------"
echo "hehe_server/master_remote@local --> hehe_server/master_haha@local"
echo "remove fetch= section first"
git config --unset remote.hehe_server.fetch
cat .git/config
echo "add first line for fetch="
git config --add remote.hehe_server.fetch "+refs/heads/master_remote:refs/remotes/hehe_server/master_haha"
echo "add second line for fetch="
git config --add remote.hehe_server.fetch "+refs/heads/*:refs/remotes/hehe_server/*"
cat .git/config
echo "check"
echo "see torek's warning: But if you now want to take all the remaining names and handle them in the usual way ...."
git branch -vv # outputs: * master_local 0870a94 [hehe_server/master_haha: gone] xxx
git fetch
git branch -vv # outputs: * master_local 0870a94 [hehe_server/master_haha] xxx
echo "why doesn't `git fetch --prune` remove the hehe_server/master_remote@local?"
ls -lah $PATHA/main/.git/refs/remotes/hehe_server
git fetch --prune
ls -lah $PATHA/main/.git/refs/remotes/hehe_server