Понимание разделов «удаленный» и «ветка» .git/config

Вот содержимое разделов remote и branch моего файла .git/config.

[remote "origin"]  
    url = https://[email protected]/EvanAad/bitbucketstationlocations.git  
    fetch = +refs/heads/*:refs/remotes/origin/*  
[branch "master"]  
    remote = origin  
    merge = refs/heads/master

В чем смысл и цель содержания этих разделов, в частности подразделов fetch и merge? Как эта информация используется Git для управления своей работой?


person Evan Aad    schedule 10.04.2017    source источник
comment
Все это можно прочитать в документации... git-scm.com/docs/git-config   -  person René Höhle    schedule 10.04.2017
comment
@Stony: я не понимаю документацию. Я надеялся на более понятное объяснение.   -  person Evan Aad    schedule 10.04.2017
comment
@Rene: Мне кажется, что документы по git-config объясняют все способы использования git-config для вывода списка и управления файлом конфигурации git, но ничего о том, что вызывает различное содержимое в отношении поведения git.   -  person qxotk    schedule 24.12.2020


Ответы (2)


Это называется refspec. Это механизм, который git использует для связи с удаленным сервером и сопоставления локальных ветвей с удаленными ветвями.

Рефспеки

Спецификация ссылок сопоставляет ветку в локальном репозитории с веткой в ​​удаленном репозитории.
Это позволяет управлять удаленными ветками с помощью локальных команд Git и настраивать некоторые расширенные функции git push и git fetch. поведение.

Спецификация указывается как [+]<src>:<dst>. Параметр <src> — это исходная ветвь в локальном репозитории, а параметр <dst> — целевая ветвь в удаленном репозитории.
Необязательный знак + используется для принуждения удаленного репозитория к выполнению небыстрой перемотки вперед. обновить.

Refspecs можно использовать с командой git push, чтобы дать удаленной ветке другое имя. Например, следующая команда отправляет ветку master в исходное удаленное репозиторий, как обычный git push, но использует qa-master в качестве имени ветки в исходном репозитории. Это полезно для групп контроля качества, которым необходимо отправить свои ветки в удаленное репо.

git push origin master:refs/heads/qa-master

Добавив несколько строк в файл конфигурации Git, вы можете использовать refspecs для изменения поведения git fetch.

По умолчанию git fetch извлекает все ветки в удаленном репозитории. Причиной этого является следующий раздел файла .git/config:

[remote "origin"]
    url = https://[email protected]:mary/example-repo.git
    fetch = +refs/heads/*:refs/remotes/origin/*

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

[remote "origin"]
    url = https://[email protected]:mary/example-repo.git
    fetch = +refs/heads/master:refs/remotes/origin/master

Вы также можете настроить git push аналогичным образом. Например, если вы хотите всегда нажимать ветку master на qa-master в удаленном источнике (как мы сделали выше), вы должны изменить файл конфигурации на:

[remote "origin"]
    url = https://[email protected]:mary/example-repo.git
    fetch = +refs/heads/master:refs/remotes/origin/master
    push = refs/heads/master:refs/heads/qa-master

Refspecs дают вам полный контроль над тем, как различные команды Git передают ветки между репозиториями.

Они позволяют переименовывать и удалять ветки из локального репозитория, fetch/push создавать ветки с разными именами, а также настраивать git push и git fetch для работы только с нужными ветвями.

person CodeWizard    schedule 10.04.2017
comment
Предположим, что спецификация fetch ref равна fetch = +refs/heads/*:refs/remotes/origin/*. Если в удаленном репозитории есть ветка с именем mybranch, а в моем локальном репозитории нет ветки удаленного отслеживания с таким же именем, будет ли создана ветка удаленного отслеживания с таким именем или будет сообщено об ошибке? - person Evan Aad; 10.04.2017
comment
Он создаст новую ветку, если она не существует, но если вы используете git v2.X и не изменили спецификацию выборки по умолчанию, вы сможете нажать только в ту же ветку. - person CodeWizard; 10.04.2017
comment
А что, если, наоборот, в моем локальном репозитории есть ветка удаленного отслеживания с именем origin/mybranch, созданная предыдущим fetch, но тем временем ветка mybranch удалена на удаленном. Что произойдет после fetch, учитывая спецификацию, упомянутую в моем предыдущем комментарии? Будет ли удален локальный origin/mybranch? - person Evan Aad; 10.04.2017
comment
Если ветка удалена, вы можете обновить локальное репо с помощью git fetch --all --prune, это удалит локальные неудаленные ветки. если вы попытаетесь отправить удаленную ветку на удаленный сервер, она будет снова создана на удаленном компьютере. - person CodeWizard; 10.04.2017
comment
@CodeWizard, не могли бы вы отформатировать эту строку - fetch = +refs/heads/master:refs/remotes/origin/master? Я не могу, потому что не хватает символов. - person hIpPy; 19.04.2017

TL;DR резюме

В целом нас интересуют две или три вещи:

  1. Что произойдет, если вы запустите git fetch без дополнительных аргументов?
  2. Что произойдет, если вы запустите git merge или git rebase без дополнительных аргументов?
  3. Что произойдет, если вы запустите git pull без дополнительных аргументов?

Краткий ответ на вопрос № 1: Git выбирает один из ваших пультов для загрузки, а затем извлекает данные с этого пульта. Удаленный выбор Git происходит из настройки remote = name в разделе [branch]. Если такой настройки нет, Git использует origin.

Ответ на вопрос № 2: Git выбирает какое-то имя для использования, как если бы вы запустили git merge name или git rebase name. name основан на настройке merge = ref в разделе [branch], но принцип его работы несколько неясен: если в этом же разделе, например, указаны remote = origin и branch = refs/heads/master, имя, которое Git выбирает для использования, не master, а скорее origin/master. Если он говорит remote = origin и branch = develop, Git выбирает имя origin/develop и так далее.

(Хотя это выглядит очень просто, фактическое сопоставление внутри Git довольно сложно: если в разделе указано remote = . и branch = master, имя будет, например, master, а не ./master. Если вы настроите необычные спецификации выборки, может произойти еще больше странностей. ответ вообще не распространяется на этот последний случай.)

Ответ на вопрос № 3 в каком-то смысле самый простой: git pull просто запускает сначала git fetch, а затем — при условии, что это удается — одну из двух других команд, git merge или git rebase, так что вам действительно нужно взглянуть только на вопросы 1 и 2.

Длинный

Запись merge под каждым разделом branch, я думаю, наименее очевидна. Документация Git немного неясна. Давайте сначала покроем остальные.

Настройки в разделе [remote "..."]

Есть много возможных настроек. Как правило, вам не нужно устанавливать какие-либо из них с помощью git config напрямую — почти все они имеют команды-оболочки, чтобы установить их более удобным для пользователя способом. Это включает в себя обе настройки, которые вы видите здесь. Их также редко хочется менять.

Раздел remote для каждого именованного удаленного устройства, такого как origin, содержит URL-адрес для git fetch (и, при необходимости, отдельный URL-адрес для отправки для git push и другие элементы конфигурации remote.* в виде описано в git config документации). Он также имеет одну или несколько строк fetch, которые предоставляют аргументы refspec по умолчанию для git fetch с этого удаленного устройства.

То есть, если вы запустите:

git fetch origin

Git будет искать remote.origin.url, чтобы увидеть, куда подключиться, затем подключиться туда, а затем получить ссылки на основе всех записей remote.origin.fetch. Значение по умолчанию, которое вы видите здесь:

+refs/heads/*:refs/remotes/origin/*

указывает Git скопировать все ветки1 из удаленного хранилища, переименовав их в ветку удаленного отслеживания с префиксом origin/2 в вашем собственном репозитории, поэтому :

git fetch origin

в принципе все достается. (В начале + говорится, что Git должен делать это независимо от того, является ли обновление ветки удаленного отслеживания операцией быстрой перемотки вперед. То есть это похоже на использование --force, но без указания --force.)

С другой стороны, если вы запустите:

git fetch origin a:b c:d

Git полностью проигнорирует все строки fetch =, извлекая только ссылки a и c с удаленного сервера и записывая их в ссылки b и d в вашем репозитории. (И поскольку здесь нет ни +, ни --force, ни один из них не будет принудительно обновлен, хотя в большинстве случаев это все равно не имеет значения.)


1, 2 ссылка – это общий термин, охватывающий теги обеих ветвей и (и многое другое). Имена ветвей, такие как master, являются просто сокращением для ссылок, начинающихся с refs/heads/. Имена ветвей удаленного отслеживания, такие как origin/master, являются просто сокращением для ссылок, начинающихся с refs/remotes/. Обратите внимание, что часть origin/ происходит от строки fetch =, но для того, чтобы все это работало должным образом, эта строка должна совпадать с именем пульта в квадратных скобках.


Настройки в разделе [branch "..."]

Есть много возможных настроек. В общем, вам не нужно устанавливать какой-либо из них с помощью git config напрямую — почти все они имеют команды-оболочки, чтобы установить их более удобным для пользователя способом. Это включает в себя обе настройки, которые вы видите здесь. Не так уж редко хочется изменить один или оба из них, используя команду, которую мы вскоре увидим.

Тем не менее, часть remote сама по себе довольно ясна: это означает, что если вы находитесь в ветке master и запускаете git fetch вообще без указания удаленного имени, Git должен получать данные с удаленного сервера с именем origin.

Часть merge сложная. В нем указано имя ветки, которое видно на удаленном компьютере. Обратите внимание, что когда мы запускаем git fetch origin, мы говорим нашему Git вызвать другой Git, найти другой Git master и скопировать его в наш репозиторий, но назвать его origin/master. И еще... в этой строке merge написано merge = refs/heads/master. Разве не должно быть написано: merge = refs/remotes/origin/master?

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

Этот параметр используется, если вы запускаете git merge или git rebase без указания имени ветки для слияния или перебазирования. Git пропускает имя через сопоставления, предоставленные строкой fetch = для удаленного сервера, чтобы выяснить, например, что оно должно объединяться с origin/master.

Этот параметр также используется вспомогательной командой git pull, которая фактически3 аналогична запуску git fetch с последующим запуском git merge.

Возможно, вы захотите изменить одно или оба из них. Например, если вы создаете новый локальный филиал feature/tall, он может вообще не иметь никаких настроек branch.feature/tall.remote и branch.feature/tall.merge.

Поскольку вы только что создали эту ветку, в ней нет origin/feature/tall. Git по адресу origin еще не имеет feature/tall, поэтому у вас нет его копии.

Затем вы git push origin feature/tall:feature/tall хотите, чтобы ваш Git вызывал Git origin и чтобы их Git создавал эту ветку, так что теперь у вас делает origin/feature/tall. Возможно, вы захотите, чтобы ваш Git запомнил это.

Вы могли запустить две команды git config, но вместо этого вы можете запустить одну команду оболочки более высокого уровня:

git branch --set-upstream-to=origin/feature/tall feature/tall

Это говорит вашему Git установить branch.feature/tall.remote на origin, а branch.feature/tall.merge на refs/heads/feature/tall (это имя на origin).

Вы можете комбинировать шаги git push и git branch --set-upstream-to, используя git push -u, что даже лучше, но суть здесь остается: вы используете оболочку, чтобы получить оба значения одновременно, поскольку установка только одного значения не так уж и важна. полезно.4

Специальное удаленное имя . означает этот репозиторий (в отличие от какого-либо удаленного репозитория). Если в разделе [branch "xyzzy"] указаны remote = . и branch = refs/heads/whatever, то ветвь xyzzy имеет локальную ветвь whatever в качестве восходящей, а не, например, origin/whatever в качестве восходящей.


3Это намеренно замалчивает множество мелких деталей.

4Установка только части remote действительно влияет на будущее git push, но git merge и git rebase не смогут выполнять сопоставление ветвей удаленного отслеживания без обеих записей.

person torek    schedule 10.04.2017
comment
Настройки в разделе branch не влияют на fetch; только на merge и pull, верно? - person Evan Aad; 10.04.2017
comment
Верно. (И они влияют только на git pull, потому что он запускает git merge или, если вы настроите его на git rebase, хотя то, что настраивает git pull на запуск git rebase, является еще одной записью в branch разделе!) - person torek; 10.04.2017
comment
@torek Но все же вы пишете: часть remote сама по себе довольно ясна: [...] Git должен получить из удаленного именованного источника ... Было бы неплохо, если бы вы могли это прояснить. - person philipp2100; 26.06.2020
comment
@ philipp2100: я правильно понимаю: в чем тут неразбериха? Будет ли полезно, если я включу сюда настоящий текст remote = origin? - person torek; 26.06.2020
comment
Нет, сбивает с толку то, что вы описываете remote, который находится в разделе branch, определенным образом влияет на git fetch, но в комментариях вы оба соглашаетесь, что настройки в разделе branch не повлияют git fetch. - person philipp2100; 27.06.2020
comment
@philipp2100: а. Проблема здесь в том, что remote = <name> сообщает git fetch, какой удаленный доступ для извлечения из. Однако это не влияет на действие извлечения, а только на то, какой URL-адрес и тому подобное используется. Чтобы управлять получением действием с этого конкретного пульта, включая сам URL-адрес, вам нужно заглянуть в раздел [remote]. Я посмотрю, смогу ли я сделать это яснее. - person torek; 28.06.2020
comment
@torek Ваш последний комментарий и редактирование прояснили ситуацию, спасибо! - person philipp2100; 28.06.2020