В чем разница между этими синтаксисами `git fetch`?

Я обнажил репозиторий (git clone --bare) и, по-видимому, git fetch не обновляет его, но git fetch origin master:master делает. Я не понимаю всех нюансов между этими синтаксисами:

  • git fetch
  • git fetch origin
  • git fetch origin master
  • git fetch origin master:master

origin является моим единственным удаленным, а master является моей единственной ветвью, а help говорит:

Если пульт не указан, по умолчанию используется пульт дистанционного управления

Итак, почему эти четыре строки не совпадают?

Изменить: три первые команды, по-видимому, извлекаются во временную ветвь с именем FEATCH_HEAD. Но поскольку я использую голой клон, я не могу использовать git merge для получения полученных результатов.

Edit2: Из ответа @torek я сделал небольшой тест и разделил каталоги --bare и -mirror clone. Вот результат:

diff -ru mesa.bare.git/config mesa.mirror.git/config
--- mesa.bare.git/config    2014-10-14 20:01:42.812226509 -0400
+++ mesa.mirror.git/config  2014-10-14 20:00:53.994985222 -0400
@@ -4,3 +4,5 @@
    bare = true
 [remote "origin"]
    url = git://anongit.freedesktop.org/mesa/mesa
+   fetch = +refs/*:refs/*
+   mirror = true
Only in mesa.bare.git/objects/pack: pack-17005b7e1020d291eb86d778a174ecf0d60d92a9.idx
Only in mesa.bare.git/objects/pack: pack-17005b7e1020d291eb86d778a174ecf0d60d92a9.pack
Only in mesa.mirror.git/objects/pack: pack-c08b44b7f290ef0bc9abe3a0b974695c85a69342.idx
Only in mesa.mirror.git/objects/pack: pack-c08b44b7f290ef0bc9abe3a0b974695c85a69342.pack

Спасибо!

Ответы

Ответ 1

Комментарий Andrew C содержит ключ здесь, но я немного изложу:

  • git fetch, без дополнительных аргументов, выбирает удаленное имя, просматривая текущую ветку или используя origin (подробности см. в документации). Выбрав пульт дистанционного управления, он переходит к следующей форме.

  • git fetch remote, снова без дополнительных аргументов, использует данный пульт и извлекает строки fetch = для этого пульта, чтобы получить набор "refspecs". Затем он выполняется аналогично последнему случаю.

  • git fetch remote refspec использует данный удаленный и данный refspec (здесь вы можете указать несколько refspec), чтобы выбрать, какие ссылки на обновление.

Как только git fetch имеет удаленное или URL-имя имени удаленного, он извлекает строку url = для получения URL-адреса, он связывается с другими командами git на удаленном сервере и запрашивает их список всех удаленных ссылок репозитория (ветки, теги и другие ссылки, все в пространствах имен refs/*, со специальным добавлением для HEAD, которое также можно получить, но обычно не используется здесь, - это там для исходного клона шаг).

Для каждой полученной ссылки git fetch видит, попросил ли вы попросить эту ссылку, и если да, то какое имя вы задали git для использования в вашем репозитории.

Опять же, доступные имена получаются с пульта. Имена, которые вы хотите получить, получены из ваших refspecs, а имена, которые будут указаны в вашем репозитории, также получаются из ваших refspecs.

Ссылка на форму a:b означает "взять ссылку a, но назовите ее b локально".

Функция refspec, отсутствующая в части b, означает "взять ссылку a, но поместите ее в специальный файл FETCH_HEAD". (FETCH_HEAD затем становится как нормальная ссылка, например MERGE_HEAD и ORIG_HEAD и т.д., за исключением того, что у нее есть дополнительный текст, написанный для него, для pull script, поэтому он иногда работает так вы можете ожидать.)

Функция refspec может содержать подстановочный знак: refs/heads/* означает "принимать все ветки" (ветки, по определению, ссылки, начинающиеся с refs/heads/). Обычно строка fetch = в конфигурации git говорит refs/heads/*:refs/remotes/origin/*. 1 Как и раньше, это означает переименование согласованной ветки с * справа, расширяющимся до того, что * слева от двоеточия. Таким образом, это приводит все ветки, но переименовывает их как origin/master и тому подобное. Обычно это требуется для репозитория не --bare.

Иногда это также то, что вы хотите для репозитория --bare, а иногда и нет. В частности, иногда вам нужен "зеркальный" репозиторий, который является голой клон, который просто подчиняет копии другому репозиторию. Чтобы изменить обычный голый репозиторий в такое зеркало, вам просто нужно изменить строку fetch =: вместо refs/heads/*:refs/remotes/origin/* строка должна читать fetch = refs/heads/*:refs/heads/*. Фактически, вы можете взять все (теги и даже заметки) с помощью fetch = refs/*:refs/*. Если вы действительно хотите, чтобы это было только то, что вы можете решить, конечно.

Обратите внимание, что это достаточно распространено, что git clone имеет флаг для автоматической настройки: клонировать с --mirror и вы получаете голой клон с измененной строкой fetch =.


1 На самом деле строка читает +refs/heads/*:refs/remotes/origin/*, т.е. имеется также ведущий символ +. Этот знак плюса устанавливает "флаг силы", как если бы вы использовали git fetch --force для этого конкретного обновления ссылки. Это не особенно актуально для вопросов правописания здесь, но я хотел бы отметить, что обычно вам требуется принудительное обновление для удаленных веток, таких как перечисленные здесь, а также для чистых зеркальных репозиториев.

Если вы зеркалируете теги, вы, вероятно, хотите, чтобы они принудительно обновляли. В идеале, конечно, теги никогда не меняются (и не удаляются), поэтому в идеальном мире это не имеет значения, но в реальном мире они иногда меняются или удаляются.

Чтобы выполнить удаление ссылки, вы должны указать git fetch на --prune (или, аналогично, поставить --prune на git remote update). Нет синтаксиса в refspecs для автоматической обрезки (хотя это было бы разумно, я не видел никаких предложений для него).