Включает ли «git fetch --tags» «git fetch»?


270

Хороший и простой вопрос - является ли функция git fetch строгим подмножеством git fetch --tags?

Т.е., если я бегу git fetch --tags, есть ли причина немедленно бежать git fetchпрямо после этого?

Что о git pullи git pull --tags? Такая же ситуация?


11
Начиная с Git 1..9 / 2.0 (Q1 2014), ответ будет да . Смотрите мой ответ ниже
VonC

3
Для редактора, который «исправил мой текст» редактированием - не обязательно использовать заглавные буквы после дефиса или аббревиатуры, поэтому ваше редактирование было грамматически неверным, поэтому я отклонил его.
Давид А

Ответы:


177

Примечание: начиная с git 1.9 / 2.0 (первый квартал 2014 года) , git fetch --tagsизвлекает теги в дополнение к тем, которые выбираются той же командной строкой без опции.

См совершить c5a84e9 по Michael Хаггерти (mhagger) :

Ранее --tagsопция " " fetch считалась эквивалентной указанию refspec

refs/tags/*:refs/tags/*

в командной строке; в частности, это привело remote.<name>.refspecк игнорированию конфигурации.

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

Если пользователь хочет получить только теги, то все еще можно указать явный refspec:

git fetch <remote> 'refs/tags/*:refs/tags/*'

Обратите внимание, что документация до 1.8.0.3 была неоднозначной об этом аспекте " fetch --tags" поведения.
Коммит f0cb2f1 (2012-12-14) fetch --tagsсделал документацию соответствующей старому поведению.
Этот коммит изменяет документацию, чтобы соответствовать новому поведению (см. Documentation/fetch-options.txt).

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


Поскольку Git 2.5 (2-й квартал 2015 года) git pull --tagsявляется более надежным:

См. Коммит 19d122b от Paul Tan ( pyokagan) , 13 мая 2015 г.
(объединено с Junio ​​C Hamano gitster- в коммите cc77b99 , 22 мая 2015 г.)

pull: устранить --tagsошибку в случае отсутствия кандидатов на слияние

Так как 441ed41 (" git pull --tags": ошибка с лучшим сообщением., 2007-12-28, Git 1.5.4+), git pull --tagsнапечатает другое сообщение об ошибке, если git-fetchне вернет никаких кандидатов на слияние:

It doesn't make sense to pull all tags; you probably meant:
       git fetch --tags

Это связано с тем, что в это время git-fetch --tagsбудут переопределены любые настроенные refspecs, и, следовательно, не будет кандидатов на слияние. Таким образом, сообщение об ошибке было введено для предотвращения путаницы.

Однако, поскольку c5a84e9 ( fetch --tags: извлекать теги в дополнение к другим материалам, 2013-10-30, Git 1.9.0+), git fetch --tagsбудет извлекать теги в дополнение к любым настроенным refspecs.
Следовательно, если не возникает ситуация с кандидатами на слияние, это не потому, что --tagsбыла установлена. Таким образом, это специальное сообщение об ошибке теперь не имеет значения.

Чтобы избежать путаницы, удалите это сообщение об ошибке.


С Git 2.11+ (4 квартал 2016 г.) git fetchбыстрее.

См. Коммит 5827a03 (13 октября 2016 г.) Джеффа Кинга ( peff) .
(Слиты Junio C Hamano - gitster- в фиксации 9fcd144 , 26 окт 2016)

fetch: используйте «быстрый» has_sha1_fileдля отслеживания тегов

При выборке с пульта дистанционного управления, у которого есть много тегов, которые не имеют отношения к ветвям, за которыми мы следуем, мы использовали слишком много циклов, когда проверяли, существует ли объект, на который указывает тег (который мы не собираемся выбирать!), В нашем хранилище слишком осторожно

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

Вот результаты из включенного сценария perf, который устанавливает ситуацию, аналогичную описанной выше:

Test            HEAD^               HEAD
----------------------------------------------------------
5550.4: fetch   11.21(10.42+0.78)   0.08(0.04+0.02) -99.3%

Это относится только к ситуации, когда:

  1. У вас есть много пакетов на стороне клиента, чтобы сделать их reprepare_packed_git()дорогими (самая дорогая часть - найти дубликаты в несортированном списке, который в настоящее время является квадратичным).
  2. Вам нужно большое количество ссылок на теги на стороне сервера, которые являются кандидатами для автоматического следования (то есть, что у клиента нет). Каждый из них запускает перечитывание каталога пакета.
  3. При нормальных обстоятельствах клиент будет автоматически следовать этим тегам, и после одной большой выборки (2) больше не будет истинным.
    Но если эти теги указывают на историю, которая не связана с тем, что клиент извлекает иначе, он никогда не будет автоматически следовать, и эти кандидаты будут влиять на нее при каждой выборке.

Git 2.21 (февраль 2019), кажется, ввел регрессию, когда конфигурация неremote.origin.fetch является конфигурацией по умолчанию ( '+refs/heads/*:refs/remotes/origin/*')

fatal: multiple updates for ref 'refs/tags/v1.0.0' not allowed

Git 2.24 (Q4 2019) добавляет еще одну оптимизацию.

См. Коммит b7e2d8b (15 сентября 2019 г.) от Masaya Suzuki ( draftcode) .
(Слиты Junio C Hamano - gitster- в фиксации 1d8b0df , 7 октября 2019)

fetch: используйте, oidsetчтобы сохранить нужные OID для быстрого поиска

В течение git fetchэтого времени клиент проверяет, есть ли уже идентификаторы OID объявленных тегов в заданном OID запроса на выборку.
Эта проверка выполняется при линейном сканировании.
Для репозитория с большим количеством ссылок повторение этого сканирования занимает более 15 минут.

Чтобы ускорить это, создайте oid_setOID для других ссылок.


В этой теме в git-list обсуждается возможность изменения поведения git fetch <remote> <branch>тегов с автоматическим следованием (поскольку оно уже обновляет удаленные отслеживания ПРОТИВ первоначальных намерений): public-inbox.org/git/…
ankostis

@ankostis Интересно: как упоминает Junio ​​в public-inbox.org/git/… , « возврат к старому поведению может быть одним из вариантов решения проблемы, обсуждаемой в этой теме». (но они не будут: public-inbox.org/git/… )
VonC

Возможно ли, чтобы Git предоставил конечному пользователю более ненужную сложность, требуя использования синтаксических команд до уровня, похожего на хаки, для выполнения обычных операций? Я не думаю, что достаточно внутренним знаниям требуются знания.
Джон Фантастико

1
@JohnFantastico Я могу понять эту точку зрения. Я видел это раньше: news.ycombinator.com/item?id=16587496 . Или hackernoon.com/… («Команды Git - просто утечка абстракции над хранилищем данных.»)
VonC

1
@Vadorequest Спасибо. Я обновил ответ и буду следить за списком рассылки: public-inbox.org/git/?q=fetch
VonC

131

Примечание: этот ответ действителен только для git v1.8 и старше.

Большая часть этого была сказана в других ответах и ​​комментариях, но вот краткое объяснение:

  • git fetchизвлекает все заголовки веток (или все указанные в параметре конфигурации remote.fetch), все необходимые коммиты и все теги, которые доступны из этих веток. В большинстве случаев все теги достижимы таким образом.
  • git fetch --tagsизвлекает все теги, все необходимые для них коммиты. Он не будет обновлять заголовки веток, даже если они достижимы из выбранных тегов.

Резюме: Если вы действительно хотите быть полностью в курсе, используя только выборку, вы должны сделать оба.

Это также не «вдвое медленнее», если только вы не имеете в виду ввод в командной строке, в этом случае псевдонимы решают вашу проблему. По сути, нет никаких накладных расходов при выполнении двух запросов, поскольку они запрашивают разную информацию.


2
Спасибо за ваш комментарий. Я запускаю git в Cygwin по сети с высокой задержкой - он работает вдвое медленнее, когда ничего не получается получить (около 5 секунд).
Дэвид

Ух ты. Git-Remote работает лучше? Если коротко взглянуть на источник, я думаю, что он может сделать только один вызов - но я не совсем уверен, хватит ли он тегов, не входящих в ветку. Честно говоря, я не знаю, видел ли я когда-либо какие-либо теги не на ветке. С вещами, которые я извлекаю, единственный путь, который случится, если я так долго жду, что пропущу выпуск технической поддержки, выпуск функций и прекращение обслуживания старой версии.
Каскабель

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

Я еще не пробовал git-remote, но он в моем постоянно растущем списке дел :)
davidA

7
Обратите внимание, что на git remote updateсамом деле не является заменой git fetchи git fetch --tags. git remote updateне будет обновлять существующие теги, которые были изменены, хотя это принесет новые теги. Только git fetch --tagsобновит уже существующие теги.
Жаворонки

48

Я собираюсь ответить на это сам.

Я определил, что есть разница. "git fetch --tags" может содержать все теги, но не вводить новые коммиты!

Оказывается, нужно сделать это, чтобы быть полностью «актуальным», то есть реплицировать «git pull» без слияния:

$ git fetch --tags
$ git fetch

Это позор, потому что это в два раза медленнее. Если бы только у «git fetch» ​​была возможность сделать то, что он обычно делает, и ввести все теги.


Интересно, что я не испытывал этого (вероятно, потому что мое репо было актуальным во время моего теста.) +1
VonC

1
Как насчет ' git remote update myRemoteRepo': это будет извлекать удаленный контент и теги?
VonC

1
Я делаю git fetchвсе время, и это последовательно сбрасывает любые новые коммиты и любые новые теги. Какую версию Git вы используете?
Тим Вишер

4
FTR, «git remote update myRemoteRepo» не работает должным образом - похоже, не делает то, что делает «git fetch && git fetch --tags», тем более что последующее объединение не имеет никакого эффекта.
Дэвид

1
@TimVisher git fetchне будет захватывать теги, которых нет в журнале фиксации ветви. Пользовательский интерфейс jQuery делает это, например, в теге выпуска. Мы делаем git checkout -b temp-branch, делаем наш выпуск, добавляем файлы, необходимые для выпуска, обновляем версию и т. Д., А затем git commit -m "1.10.x" ; git tag 1.10.x; git push --tagsудаляем нашу локальную временную ветку. Не существует удаленной ветви, которая достигает этого тега и git fetchникогда не загрузит его.
gnarf

31

Общая проблема здесь заключается в том, что git fetchбудет доставать +refs/heads/*:refs/remotes/$remote/*. Если какой-либо из этих коммитов имеет теги, эти теги также будут выбраны. Однако, если есть теги, недоступные для какой-либо ветви на удаленном компьютере, они не будут выбраны.

--tagsОпция переключает refspec в +refs/tags/*:refs/tags/*. Вы могли бы спроситьgit fetch захватить оба. Я уверен, что просто сделаю, git fetch && git fetch -tвы бы использовали следующую команду:

git fetch origin "+refs/heads/*:refs/remotes/origin/*" "+refs/tags/*:refs/tags/*"

И если вы хотите сделать это по умолчанию для этого репо, вы можете добавить второй refspec к выборке по умолчанию:

git config --local --add remote.origin.fetch "+refs/tags/*:refs/tags/*"

Это добавит секунду fetch = строку .git/configдля этого пульта.


Я потратил некоторое время на поиски способа справиться с этим для проекта. Это то, что я придумал.

git fetch -fup origin "+refs/*:refs/*"

В моем случае я хотел эти функции

  • Возьмите все головы и теги с пульта, поэтому используйте refspec refs/*:refs/*
  • Перезаписывать локальные ветви и теги без ускоренной перемотки вперед + перед ссылкой
  • При необходимости перезаписать текущую проверенную ветку -u
  • Удалить ветки и теги, которых нет в удаленном -p
  • И заставить быть уверенным -f

Это должно быть ответом.
благородный

+1 для « --tagsОпция переключает ссылку на +refs/tags/*:refs/tags/*». Хотя, man git-fetchкажется, указывает, что refspec без ведущего +( refs/tags/*:refs/tags/*).
Дмитрий Минковский

remote.origin.fetchпо умолчанию +refs/heads/*:refs/remotes/origin/*, т.е. +версия, не так ли? (Это означает, что происхождение / ветвь будут перезаписаны, независимо от того, где происхождение / ветвь находятся сейчас локально.)
Роберт Симер

... и на момент написания, последние git --tagsизвлекали теги в дополнение ко всему остальному. Смотрите ответ @VonC.
Роберт Симер

10

В большинстве случаев git fetchследует делать то, что вы хотите, а именно: «получить что-то новое из удаленного хранилища и поместить его в локальную копию, не сливая с локальными филиалами». git fetch --tagsделает именно это, за исключением того, что он не получает ничего, кроме новых тегов.

В этом смысле git fetch --tagsникоим образом не является надмножеством git fetch. На самом деле все с точностью до наоборот.

git pullКонечно, это всего лишь обертка для git fetch <thisrefspec>; git merge. Рекомендуется привыкнуть к ручному git fetchвводу и git mergeвыводу до того, как вы совершите переход, git pullпросто потому, что это поможет вам понять, что git pullв первую очередь происходит.

При этом отношения точно такие же, как и с git fetch. git pullэто надмножество git pull --tags.


1
«git pull - это расширенный набор git pull --tags» - но ... «git fetch» не является расширенным набором «git fetch --tags», поэтому отношения не совсем такие ...?
Дэвид

9
Только что нашел этот вопрос ... ну, мне кажется, git pullон не получает все теги, а только те, которые доступны из текущих глав филиалов. Однако git pull --tagsизвлекает все теги и, по-видимому, эквивалентно git fetch --tags.
Archimedix

2
git fetch upstream --tags

работает просто отлично, он получит только новые теги и не получит никакой другой базы кода.


1
upstreamобычно называется origin. Я думаю, что upstreamэто имя используется GitHub. В любом случае, используемое имя - это то, что показано git remote.
Фабио говорит восстановить Монику
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.