Могут ли "удаленная ветвь", "ветка удаленного отслеживания" и "ветвь отслеживания" иметь разные имена?

Я играю с 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
Другие вопросы по тегам