Что означает FETCH_HEAD в Git?

git pull --help говорит:

В режиме по умолчанию git pull является сокращением для git fetch, за которым следует git merge FETCH_HEAD.

Что это за FETCH_HEAD и что на самом деле объединяется во время git pull?


person Misha Moroshko    schedule 11.02.2012    source источник
comment
Примечание. Начиная с git 1.8.4 (август 2013 г.), git fetch origin master фактически обновляет origin/master, а не только FETCH_HEAD. См. stackoverflow.com/a/20967347/6309   -  person VonC    schedule 07.01.2014
comment
Подробнее о git merge FETCH_HEAD (начиная с Git 2.5, второй квартал 2015 г.) см. stackoverflow.com/a/30425991/6309   -  person VonC    schedule 24.05.2015


Ответы (6)


FETCH_HEAD - это кратковременная ссылка, чтобы отслеживать, что только что было извлечено из удаленного репозитория. git pull сначала вызывает git fetch, в нормальных случаях выбирая ветку с удаленного устройства; FETCH_HEAD указывает на верхушку этой ветки (она хранит SHA1 фиксации, как и ветки). git pull затем вызывает git merge, объединяя FETCH_HEAD в текущую ветвь.

Результат - именно то, что вы ожидаете: фиксация на конце соответствующей удаленной ветки объединяется с фиксацией на конце вашей текущей ветки.

Это немного похоже на выполнение git fetch без аргументов (или git remote update), обновление всех ваших удаленных веток, затем запуск git merge origin/<branch>, но с внутренним использованием FETCH_HEAD вместо того, чтобы ссылаться на любую полученную единственную ссылку, вместо того, чтобы указывать вещи.

person Cascabel    schedule 11.02.2012
comment
Pull может выполнить перебазирование вместо слияния, если вы настроите его таким образом. - person Adam Dymitruk; 11.02.2012
comment
@AdamDymitruk: Конечно. Я описал поведение по умолчанию, полагая, что если кто-то его изменит, они будут знать, что они изменили его. (Для полноты картины поведение идентично, merge FETCH_HEAD заменяется на rebase FETCH_HEAD). - person Cascabel; 11.02.2012
comment
@Jefromi: извините, я думаю, вы ошибаетесь: насколько я понимаю, git fetch обновляет (объединяет) все данные объекта из удаленного хранилища, а не только поздний завтрак. Поэтому я не понимаю из вашего ответа, как git решает, на какую ветку указывать FETCH_HEAD. Я также не могу найти FETCH_HEAD в документации git (определение, а не примеры). Существование FETCH_HEAD больше похоже на обходной путь, позволяющий заставить git pull работать как-то. - person Alexey; 15.07.2012
comment
Алексей: FETCH_HEAD соответствует вершине удаленной ветки, указанной branch.<BRANCH>.merge в конфигурации локального репозитория. Таким образом, хотя fetch действительно извлекает все данные объекта из удаленного хранилища, FETCH_HEAD используется, чтобы указать, куда продвинулась удаленная ветвь, отслеживаемая локальной ветвью. Таким образом, если вы находитесь в локальной ветке master и запускаете git fetch, а branch.master.merge указывает на refs/heads/master, тогда FETCH_HEAD будет иметь то же значение, что и origin/master сразу после операции выборки. - person larsks; 27.07.2012
comment
@alexy FETCH_HEAD описан во втором абзаце описания git fetch на его странице руководства. Мой ответ правильный. И git fetch без аргументов обновляет все удаленные ветки для удаленного по умолчанию ... но это определенно не то же самое, что слияние. - person Cascabel; 27.07.2012
comment
Что будет FETCH_HEAD, если вы получите все удаленные ветки через git fetch -a? - person stigi; 10.10.2012
comment
@stigi Кончик ветки удаленного отслеживания, на которую указывает ваша текущая проверенная ветка в конфигурации git. См. Ответ Ларска в комментарии выше. - person Ankur Agarwal; 01.11.2015
comment
А что, если вы отстранитесь и сделаете выборку? Что делать, если у вас есть местный рефери, но нет ветки удаленного отслеживания? Как манипулируют FETCH_HEAD во время git fetch в этих обстоятельствах? - person void.pointer; 27.07.2017
comment
@ void.pointer Кажется, местный штат не имеет значения? FETCH_HEAD предназначен для отслеживания удаленного. Итак, что бы вы ни выбрали, это FETCH_HEAD. Проверенная локальная ссылка / фиксация имеет значение только тогда, когда вы дойдете до слияния. - person Cascabel; 27.07.2017
comment
@jefromi согласно ответам здесь местное государство имеет значение. FETCH_HEAD может хранить только один удаленный sha1. Он не отслеживает пульт, как вы говорите. Таким образом, когда выборка вызывает более одной ссылки, здесь в ответах говорится, что локальная ветвь удаленного отслеживания определяет, какая из удаленных ссылок становится FETCH_HEAD. Так что мой вопрос все еще в силе. - person void.pointer; 27.07.2017
comment
@Alexey: на ваш вопрос можно ответить с помощью моего недавно добавленного ответа ниже: stackoverflow.com/a/45543739/1290368. - person Carsten Führmann; 07.08.2017
comment
Как предлагает @Alexey, а @ CarstenFührmann дополнительно поясняет, нет, FETCH_HEAD не содержит только одну ветвь. Он содержит всю информацию об удаленной ветви, которая была извлечена последней. - person Edward Thomson; 28.05.2018

FETCH_HEAD - это ссылка на конец последней выборки, независимо от того, была ли эта выборка инициирована непосредственно с помощью команды выборки или как часть извлечения. Текущее значение FETCH_HEAD хранится в папке .git в файле с именем, как вы уже догадались, FETCH_HEAD.

Итак, если я выдам:

git fetch https://github.com/ryanmaxwell/Fragaria

FETCH_HEAD может содержать

3cfda7cfdcf9fb78b44d991f8470df56723658d3        https://github.com/ryanmaxwell/Fragaria

Если у меня удаленное репо настроено как ветка удаленного отслеживания, я могу отслеживать свою выборку с помощью слияния ветки отслеживания. Если я этого не сделаю, я могу объединить кончик последней выборки напрямую, используя FETCH_HEAD.

git merge FETCH_HEAD
person Jonathan Mitchell    schedule 10.12.2012
comment
Чтобы добавить свои 5 центов. Что меня смутило, так это то, что мой FETCH_HEAD стоял за последними коммитами, даже если выполнял новую выборку, которая не возвращала никаких изменений (в eclipse). Я думаю, причина в том, что все изменения с момента моей последней загрузки исходят от меня и были отправлены мной на сервер. Таким образом, последующая выборка не имела ничего общего и даже не обновляла FETCH_HEAD. Однако я не уверен, является ли это недостатком реализации GIT или Eclipse Git. - person Torge; 01.08.2018

Как упоминалось в ответе Джонатана, FETCH_HEAD соответствует файлу .git/FETCH_HEAD. Обычно файл будет выглядеть так:

71f026561ddb57063681109aadd0de5bac26ada9                        branch 'some-branch' of <remote URL>
669980e32769626587c5f3c45334fb81e5f44c34        not-for-merge   branch 'some-other-branch' of <remote URL>
b858c89278ab1469c71340eef8cf38cc4ef03fed        not-for-merge   branch 'yet-some-other-branch' of <remote URL>

Обратите внимание, как все ветви, кроме одной, помечены как not-for-merge. Необычная ветка - это ветка, которая была проверена перед выборкой. В итоге: FETCH_HEAD по существу соответствует удаленной версии ветки, которая в настоящее время проверена.

person Carsten Führmann    schedule 07.08.2017

Я только что обнаружил и использовал FETCH_HEAD. Мне нужна была локальная копия некоторого программного обеспечения с сервера, и я сделал

git fetch gitserver release_1

gitserver - это имя моей машины, на которой хранятся репозитории git. release_1 - это тег версии программного обеспечения. К моему удивлению, release_1 на моей локальной машине нигде не было. Я должен был напечатать

 git tag release_1 FETCH_HEAD 

для завершения копирования отмеченной цепочки коммитов (release_1) из удаленного репозитория в локальный. Fetch нашла удаленный тег, скопировала фиксацию на мою локальную машину, не создала локальный тег, но установила FETCH_HEAD в значение фиксации, чтобы я мог ее найти и использовать. Затем я использовал FETCH_HEAD для создания локального тега, который соответствовал тегу на пульте дистанционного управления. Это практическая иллюстрация того, что такое FETCH_HEAD и как его можно использовать, и может быть полезно для кого-то еще, задающегося вопросом, почему git fetch не делает того, чего вы наивно ожидали.

На мой взгляд, для этой цели этого лучше избегать, и лучший способ добиться того, что я пытался сделать, - это

git fetch gitserver release_1:release_1

т.е. получить release_1 и называть его release_1 локально. (Это источник: dest, см. https://git-scm.com/book/en/v2/Git-Internals-The-Refspec; на всякий случай, если вы захотите дать ему другое имя!)

Хотя иногда вы можете захотеть использовать FETCH_HEAD: -

git fetch gitserver bugfix1234
git cherry-pick FETCH_HEAD

может быть хорошим способом использовать исправление ошибки номер 1234 с вашего сервера Git и оставить сборку мусора Git для удаления копии с сервера после того, как исправление было выбрано в вашу текущую ветку. (Я предполагаю, что есть хорошая чистая помеченная фиксация, содержащая все исправление ошибки на сервере!)

person Ivan    schedule 08.09.2014
comment
Интересный отзыв. +1 - person VonC; 26.01.2018
comment
Спасибо. Я отредактировал свой исходный пост, написанный, когда я впервые обнаружил FETCH_HEAD пару лет назад, поскольку он, казалось, поощрял копирование тега с использованием FETCH_HEAD, а не синтаксиса source: dest для refspecs. Надеюсь, теперь я привел лучший пример того, как можно использовать FETCH_HEAD. - person Ivan; 26.01.2018

git pull - это комбинация выборки с последующим слиянием. Когда происходит git fetch, он отмечает головной коммит того, что он получил в FETCH_HEAD (просто файл с таким именем в .git), и эти коммиты затем объединяются в ваш рабочий каталог.

person manojlds    schedule 11.02.2012
comment
@manjolds, что вы имеете в виду под фиксацией головы того, что он получил? Git получает все с помощью fetch. - person Alexey; 15.07.2012
comment
@Alexey из руководства git: git-scm.com/docs/git-fetch: Имена получаемых ссылок вместе с именами объектов, на которые они указывают, записываются в .git / FETCH_HEAD - person PJ_Finnegan; 01.01.2018

FETCH_HEAD - это кратковременная ссылка, чтобы отслеживать, что только что было извлечено из удаленного репозитория.

На самом деле ... не всегда, учитывая, что в Git 2.29 (4 квартал 2020 г.) _ 2_ (человек) изучил параметр --no-write-fetch-head, чтобы избежать записи FETCH_HEAD файла.

См. commit 887952b (18 августа 2020 г.) по Junio ​​C Hamano (gitster).
(Объединено Junio ​​C Hamano - gitster - в фиксации b556050, 24 августа 2020 г.)

fetch: при необходимости разрешить отключение FETCH_HEAD update

Подписано: Деррик Столи

Если вы запускаете выборку, но записываете результат в ветки удаленного отслеживания, и либо если вы ничего не делаете с полученными ссылками (например, вы просто зеркалируете), либо если вы всегда работаете из ссылок удаленного отслеживания (например, вы извлекаете и затем объединяете origin/branchname отдельно), вы можете обойтись без FETCH_HEAD вообще.

Научите git fetch (man) параметр командной строки --[no-]write-fetch-head.

  • По умолчанию используется запись FETCH_HEAD,, и эта опция в первую очередь предназначена для использования с префиксом --no-, чтобы переопределить это значение по умолчанию, потому что нет соответствующей переменной конфигурации fetch.writeFetchHEAD, которая бы отключила значение по умолчанию (в этом случае может потребоваться положительная форма для победить его).

Обратите внимание, что в режиме --dry-run FETCH_HEAD никогда не записывается; в противном случае вы увидите в файле список объектов, которых у вас на самом деле нет.

Передача --write-fetch-head не заставляет [git fetch](https://github.com/git/git/blob/887952b8c680626f4721cb5fa57704478801aca4/Documentation/git-fetch.txt)<sup>([man](https://git-scm.com/docs/git-fetch))</sup> записывать файл.

fetch-options теперь включает в свою страницу руководства:

--[no-]write-fetch-head

Напишите список удаленных ссылок, полученных в файле FETCH_HEAD, прямо под $GIT_DIR.
Это значение по умолчанию.

Передача --no-write-fetch-head из командной строки указывает Git не записывать файл.
В параметре --dry-run файл никогда не записывается.


Также обратите внимание: по-прежнему с Git 2.29 (4 квартал 2020 г.) FETCH_HEAD теперь всегда читается из файловой системы независимо от используемого бэкэнда ref, поскольку его формат намного богаче, чем у обычных ссылок, и записывается непосредственно с помощью _ 28_ (man) в виде простого файла ..

См. фиксацию e811530, совершить 5085aef, > 4877c6c, совершить e39620f (19 августа 2020 г.) от Han-Wen Nienhuys (hanwen).
(объединено Junio ​​C Hamano - gitster - в commit 98df75b, 27 августа 2020 г.)

refs: читать FETCH_HEAD и MERGE_HEAD в целом

Подписано: Хан-Вен Ниенхуйс

Ссылки FETCH_HEAD и MERGE_HEAD должны храниться в файле, независимо от типа серверной части ссылки. Это потому, что они могут содержать больше, чем одну ссылку.

Чтобы разместить их для альтернативных бэкэндов ref, прочтите их в общем виде из файла в refs_read_raw_ref().


В Git 2.29 (4 квартал 2020 г.) обновления для получения кода по требованию в лениво клонированных репозиториях.

См. фиксацию db3c293 (2 сентября 2020 г.) и зафиксировать 9dfa8db, совершить 7ca3c0a, зафиксировать 5c3b801, = "https://github.com/git/git/commit/abcb7eeb31d0267ada469646be993ad25e127d0d" rel = "nofollow noreferrer"> совершить abcb7ee, совершить e5b9421, Junio ​​C Hamano - gitster - в commit b4100f3, 3 сен 2020 г.)

fetch: не отображается FETCH_HEAD, если --no-write-fetch-head

Подписано: Джонатан Тан

887952b8c6 (fetch: можно дополнительно отключить FETCH_HEAD обновление, 2020-08-18, Git v2 .29.0 - слияние, перечисленное в batch # 10) представила возможность отключить запись в FETCH_HEAD во время выборки, но не подавила сообщение <source> -> FETCH_HEAD" при использовании этой возможности.

В данном случае это сообщение вводит в заблуждение, потому что FETCH_HEAD не написано.

Кроме того, поскольку fetch используется для отложенной выборки отсутствующих объектов в частичном клоне, это значительно загромождает вывод в этом случае, поскольку извлекаемых объектов потенциально много.

Поэтому подавляйте это сообщение, когда передается --no-write-fetch-head (но не когда установлено --dry-run).

person VonC    schedule 31.08.2020