Различия между git fetch и git fetch origin master
Я делал выборки / слияния и хотел знать, есть ли разница между
git fetch
а также
git fetch origin master
У меня нет никаких других веток и точек происхождения к моим remote repository
на GitHub.
Когда я делаю:
git fetch origin master
remote: Counting objects: 4, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From github.com:XXXXXXXXXXXXXXX
* branch master -> FETCH_HEAD
Но просто:
git fetch
From github.com:XXXXXXXXXXXXXXX
531d466..aaf6df0 master -> origin/master
Обратите внимание, что мастер указывает на разные вещи; в одном случае FETCH_HEAD
а в другом случае origin/master
? Они разные?
1 ответ
Вот версия "TL;DR" (которая закрывает множество особых случаев): git fetch
всегда обновления FETCH_HEAD
с более чем одной строкой в разных случаях. Иногда обновляются "удаленные ветки", которые являются ссылками, полное имя которых начинается с refs/remotes/
, Остальное в основном касается "иногда", которое варьируется в зависимости от количества аргументов git fetch
и версия git.
У меня был шанс проверить это. Давайте выделим три случая, каждый из которых предполагает выполнение git fetch
без дополнительных опций, таких как -a
или даже --all
, Давайте также исключим более странные варианты git fetch
например, использование URL-адреса напрямую или insteadOf
записи или файлы, перечисленные в .git/remotes
или же .git/branches
, (Признаюсь, я просто догадываюсь, но я думаю, что это остатки за несколько дней до [remote "name"]
записи вошли в конфигурационные файлы git.)
git fetch
и других аргументов нет.Git определяет вашу текущую ветку (обычным способом, читая
HEAD
, но вы, конечно, можете увидеть, что это такоеgit branch
или жеgit status
). Затем он ищет запись конфигурации для этой ветви, называя ееremote
, Например, предположим, что вы находитесь на веткеdummy
а также.git/config
имеет (среди других записей):[branch "dummy"] remote = remote-X
В этом случае
git fetch
эквивалентноgit fetch remote-X
, После этой точки это эквивалентно случаю 2, который:git fetch remote
(и больше никаких аргументов кроме этого).Git не смотрит на вашу текущую ветку на этот раз. Удаленный для использования тот, который указан в командной строке. Он ищет раздел конфигурации для данного пульта. Допустим, вы используете
remote-X
в этом случае он ищет:[remote "remote-X"] url = ...
Если этот раздел не существует, или нет
url =
запись, вы получаете ошибку:fatal: 'remote-X' does not appear to be a git repository
, 1 В противном случае, который дает URL, иgit fetch
будет пытаться подключиться к там. Предполагая, что это может соединиться...Обычно есть также по крайней мере одна запись конфигурации, возможно, больше, читая:
fetch = +refs/heads/*:refs/remotes/remote-X/*
(название пульта здесь жестко запрограммировано). Предполагая, что есть...
Следующий,
git fetch
спрашивает у пульта, какие ссылки у него есть (в основном ветки и теги, хотя вы можете получить все ссылки, но большинство людей просто заботятся о ветках и тегах). Вы можете сделать то же самое самостоятельно сgit ls-remote remote-X
, который разливает такие вещи:676699a0e0cdfd97521f3524c763222f1c30a094 HEAD 222c4dd303570d096f0346c3cd1dff6ea2c84f83 refs/heads/branch 676699a0e0cdfd97521f3524c763222f1c30a094 refs/heads/master
Лечение
HEAD
ref не совсем последовательный (я видел, что он ведет себя странно), но обычно здесь он просто сбрасывается. 2 Остальные ветви переименованы и обновлены в соответствии сfetch =
refspec. (Если есть несколькоfetch =
refspecs, они переименованы и обновлены в соответствии со всеми ними. Это в основном полезно для привлеченияrefs/notes/
или сделать ваше собственное пространство имен "удаленных тегов" подrefs/rtags/
, например.)В этом случае fetch перенесет любые объекты, необходимые для двух веток.
branch
а такжеmaster
и обновите (локальные) имена "удаленных филиалов",refs/remotes/remote-X/branch
а такжеrefs/remotes/remote-X/master
, по мере необходимости. Для каждого, который обновляется,fetch
печатает строку как это:22b38d1..676699a master -> remote-X/master
Если
fetch =
линии отсутствуют, вы получаете что-то совсем другое. Вывод будет читать:* branch HEAD -> FETCH_HEAD
В этом случае это как будто (отсутствует)
fetch =
линия была там и содержалаfetch = HEAD
,git fetch remote refspec
(refspec
part - это один или несколько refspecs, как описано ниже).Это похоже на случай 2, только на этот раз "refspecs" указывается в командной строке, а не из
fetch =
записи конфигурации для пульта. Тем не менее, поведение выборки здесь совсем другое.
Давайте на минуту остановимся и опишем refspec должным образом, в данном конкретном случае. (Refspecs также встречаются для git push
но, как обычно в git, детали реализации просачиваются и работают там немного по-другому.) У refspec есть дополнительный начальный плюс (+
) знак, который я здесь проигнорирую; 3 затем две части, разделенные двоеточием (:
). Оба часто являются просто именем ветви, но вы можете (и fetch =
строки делают) прописать "полное" ref-имя, refs/heads/branch
в случае названия филиала.
Для операций извлечения имя слева - это имя самого пульта (как показано git ls-remote
например). Имя справа - это имя, которое будет сохранено / обновлено в вашем локальном git-репозитории. Как особый случай, у вас может быть звездочка (*
) после косой черты как последний компонент, вроде refs/heads/*
, в этом случае соответствующая часть слева заменяется справа. следовательно refs/heads/*:refs/remotes/remote-X/*
это то, что вызывает refs/heads/master
(как видно на пульте, с git ls-remote
) становиться refs/remotes/remote-X/master
(как видно из вашего локального хранилища, и в более короткой форме, на правой стороне ->
линия git fetch
печать).
Если вы не вставите в :
, хоть, git fetch
не имеет хорошего места, чтобы положить копию "ветки там". Допустим, это принесет с собой пульт refs/heads/master
(master
ветка на пульте). Вместо обновления вашего refs/heads/master
- очевидно, что было бы плохо, если бы у вас были свои коммиты в ветке master
- он просто сбрасывает обновление в FETCH_HEAD
,
Вот где дела обстоят особенно коротко. Допустим, вы бежите git fetch remote-X master branch
т. е. дать хотя бы один, а может и несколько, refspecs, но все без двоеточий.
Если ваша версия git старше 1.8.4, обновление входит только в
FETCH_HEAD
, Если вы дали два рефспека без двоеточия,FETCH_HEAD
теперь содержит две строки:676699a0e0cdfd97521f3524c763222f1c30a094 branch 'master' of ... 222c4dd303570d096f0346c3cd1dff6ea2c84f83 branch 'branch' of ...
Если ваша версия git 1.8.4 или новее, обновление идет туда - эта часть не изменяется - но также выборка использует возможность для постоянной записи этих веток в их надлежащие удаленные ветви, как указано
fetch =
линии для пульта.По какой-то причине, однако,
git fetch
только распечатывает обновление->
линия для удаленных веток, которые фактически обновляются. Поскольку он всегда записывает все обновления вFETCH_HEAD
здесь всегда печатаются названия веток.(Другой проблемой, помимо необходимости использования git 1.8.4 или новее, с обновлением удаленных веток, является то, что
fetch =
линии должны существовать. Если они этого не делают, нет сопоставления, с помощью которого выборка знает, чтобы переименоватьrefs/heads/*
вrefs/remotes/remote-X/*
.)
Другими словами, git 1.8.4 и новее действительно "обновляют" все удаленные ветви. Старые версии git делают это на git push
так что это было противоречивым раньше. Даже в git 1.8.4 все равно несовместимо с git pull
Я думаю (хотя я не использую git pull
достаточно заметить:-)); это должно быть исправлено в git 1.9.
Теперь давайте вернемся к разнице между git fetch remote
а также git fetch remote refspec ...
,
Если вы бежите
git fetch remote
то есть, если опустить все refspecs, выборка возвращается кfetch =
линии как обычно. Операция извлечения переносит все ссылки изfetch
линий. Все это входит вFETCH_HEAD
, но на этот раз они помечены как "не для слияния" (с вкладками, которые я изменил на один пробел, чтобы лучше разместить на веб-страницах):676699a0e0cdfd97521f3524c763222f1c30a094 not-for-merge branch ...
Ссылки, которые не являются ветвями, например,
refs/notes/
ссылки, которые приводятся, читайте вместо:f07cf14302eab6ca614612591e55f7340708a61b not-for-merge 'refs/notes/commits' ...
Между тем, ссылки на удаленные ветки обновляются, если необходимо, с сообщениями, сообщающими, какие из них были обновлены:
22b38d1..676699a master -> remote-X/master
Опять все сбрасывается в
FETCH_HEAD
, но только ссылки, которые "нуждаются в обновлениях" обновляются и печатаются. На новых ветвях напечатана "новая ветвь", а на старых напечатаны сокращенные "старые и новые" SHA-1, как дляmaster -> remote-X/master
выше.Если, с другой стороны, вы запускаете
git fetch remote refspec ...
, выборка приносит только указанные refspecs. Все это входит вFETCH_HEAD
как обычно 6, но на этот раз каждый из них напечатан. Затем, если ваш git 1.8.4 или новее, любые ссылки-обновления, которые могут быть сопоставлены (через разумныйfetch =
строки) и нуждаются в обновлении, также обновляются и печатаются:* branch master -> FETCH_HEAD * branch branch -> FETCH_HEAD 22b38d1..676699a master -> remote-X/master
Если ваша версия git старше 1.8.4, обновление
remote-X/master
не происходит в этом случае, или, скорее, это не происходит, если один из ваших refspecs командной строки не былrefs/heads/master:refs/remotes/remote-X/master
, или жеrefs/heads/*:refs/remotes/remote-X/*
или варианты с плюсиками впереди.
1 Это не большое сообщение об ошибке. remote-X
Аргумент никогда не должен был быть "хранилищем", он должен был быть "удаленным"! Было бы неплохо, если бы Git сказал что-то более информативное.
2 В git remote protocol есть недостаток: HEAD обычно является косвенным ref, поскольку это текущая ветка на пульте, поэтому он должен называться, например, "ref: refs/head /master", но вместо этого он появляется как полностью решен SHA-1. Хотя бы одна команда git (git clone
) пытается "угадать" текущую ветку на удаленном компьютере, сравнивая этот SHA-1 с тем из каждого из ветвей. Например, в приведенном выше примере ясно, что удаленный узел находится "на главном филиале", так как HEAD
а также refs/heads/master
имеют тот же SHA-1. Но если несколько имен веток указывают на один и тот же коммит, и HEAD
соответствует этому коммит-идентификатору, нет способа узнать, какая ветвь (если есть) HEAD
включен Пульт дистанционного управления также может находиться в состоянии "отсоединенный HEAD", и в этом случае он не находится ни в одной ветви, независимо от значений SHA-1.
3 Знак "плюс" означает "принимать принудительные обновления", то есть принимать обновления, которые будут отклонены правилом "ничего, кроме перемотки вперед" 4 для ветвей, или "никогда не менять теги" 5 для тегов.
4 "Перемотка вперед" для метки, изменение ее со старого SHA-1 на новый, возможна, когда старый SHA-1 в коммит-ориентированном ациклическом графе является предком нового SHA-1.
5 Правило "никогда не меняйте теги" было впервые введено в git 1.8.2. Если ваш git старше этого, git также использует правила ветвления для тегов, что позволяет выполнять быструю перемотку без "принудительного обновления".
6 Но без not-for-merge
этот раз. В основном, когда вы предоставляете refspecs без двоеточия, git fetch
предполагает, что они "для слияния" и помещает их в FETCH_HEAD
чтобы git merge FETCH_HEAD
могу найти их. (Я не проверял, что происходит с ссылками не из ветвей.)