(Для написания этого ответа потребовалось некоторое время, и ответ CodeWizard верен по своей цели и сути, но не полностью, поэтому я все равно опубликую это.)
Не существует такого понятия, как «удаленный тег Git». Есть только «теги». Я указываю все это не быть педантичным, 1 , а потому что есть большая путаница по этому поводу со случайными пользователями Git, и документация Git не очень полезно 2 для начинающих. (Непонятно, возникает ли путаница из-за плохой документации или плохой документации из-за того, что это несколько смущает, или как.)
Там есть «удаленные ветви», более правильно называют «дистанционное отслеживание ветвей», но стоит отметить , что это на самом деле местные организации. Тем не менее, нет никаких удаленных тегов (если только вы не изобретаете их). Есть только локальные теги, поэтому вам нужно получить тег локально, чтобы использовать его.
Общая форма имен для конкретных коммитов, которые Git называет ссылками, - это любая строка, начинающаяся с refs/
. Строка, которая начинается с refs/heads/
имен ветки; строка, начинающаяся с refs/remotes/
имен ветки удаленного отслеживания; и строка, начинающаяся с refs/tags/
имен тега. Имя refs/stash
является ссылкой на тайник (используется git stash
; обратите внимание на отсутствие косой черты).
Есть некоторые необычные имена для особых случаев , которые не начинаются с refs/
: HEAD
, ORIG_HEAD
, MERGE_HEAD
, и , CHERRY_PICK_HEAD
в частности , все также имена , которые могут относиться к конкретным фиксациям (хотя HEAD
обычно содержит название филиала, то есть содержит ). Но в целом ссылки начинаются с .ref: refs/heads/branch
refs/
Единственное, что Git делает, чтобы запутать это, - это то, что он позволяет вам опускать refs/
, а часто и слово после refs/
. Например, вы можете опустить refs/heads/
или refs/tags/
при обращении к локальной ветви или тегу - и на самом деле вы должны опустить refs/heads/
при проверке локальной ветви! Вы можете сделать это, когда результат будет однозначным, или, как мы только что отметили, когда вы должны это сделать (для ).git checkout branch
Это правда, что ссылки существуют не только в вашем собственном хранилище, но и в удаленных хранилищах. Тем не менее, Git предоставляет вам доступ к ссылкам удаленного репозитория только в очень определенные моменты времени, а именно: во время fetch
и во время push
операций. Вы также можете использовать git ls-remote
или, git remote show
чтобы увидеть их, но fetch
и push
являются более интересными точками контакта.
Refspecs
Во время fetch
и push
Git использует строки, которые он вызывает refspecs, для передачи ссылок между локальным и удаленным репозиторием. Таким образом, именно в это время и с помощью refspecs два репозитория Git могут синхронизироваться друг с другом. Как только ваши имена синхронизируются, вы можете использовать то же имя, которое использует кто-то с удаленного компьютера. Здесь есть некоторая особая магия fetch
, которая влияет как на имена веток, так и на имена тегов.
Вы должны думать о том, чтобы git fetch
направить ваш Git на вызов (или, возможно, текстовое сообщение) другого Git - «удаленного» - и поговорить с ним. В начале этого разговора пульт дистанционного управления перечисляет все его ссылки: все в нем refs/heads/
и все в нем refs/tags/
, а также любые другие ссылки, которые он имеет. Ваш Git просматривает их и (на основе обычного refspec fetch) переименовывает их ветви.
Давайте посмотрим на нормальный refspec для пульта с именем origin
:
$ git config --get-all remote.origin.fetch
+refs/heads/*:refs/remotes/origin/*
$
Этот refspec указывает вашему Git взять каждое совпадение имени - refs/heads/*
т.е. каждую ветку на удаленном компьютере - и изменить его имя на refs/remotes/origin/*
, то есть оставить совпадающую часть неизменной, изменив имя ветви ( refs/heads/
) на имя ветви удаленного отслеживания ( refs/remotes/
особенно , refs/remotes/origin/
).
Именно через эту refspec , что origin
ветви «S стать вашими дистанционного отслеживания ветвей для удаленного origin
. Имя ветви становится именем ветви удаленного отслеживания, в том числе и имя удаленного origin
. Знак «плюс» +
в начале refspec устанавливает флаг «force», т. Е. Ветка удаленного отслеживания будет обновлена в соответствии с именем ветки удаленного сервера, независимо от того, что требуется для его сопоставления. (Без этого +
обновления веток ограничиваются изменениями «ускоренной перемотки», а обновления тегов просто игнорируются начиная с Git версии 1.8.2 или около того - до этого применялись те же правила ускоренной перемотки.)
Теги
Но как насчет тегов? Там нет refspec для них - по крайней мере, не по умолчанию. Вы можете установить один, в этом случае форма refspec зависит от вас; или ты можешь бежать git fetch --tags
. Использование --tags
приводит к добавлению refs/tags/*:refs/tags/*
в refspec, т. Е. Переносит все теги ( но не обновляет ваш тег, если у вас уже есть тег с таким именем, независимо от того, что говорит тег удаленного устройства Edit, Jan 2017: начиная с Git 2.10 тестирование показывает, что --tags
принудительно обновляет ваши теги из тегов пульта, как если бы refspec читал +refs/tags/*:refs/tags/*
; это может отличаться по поведению от более ранней версии Git).
Обратите внимание, что здесь нет переименования: если у пульта origin
есть тег xyzzy
, и у вас нет, и у вас git fetch origin "refs/tags/*:refs/tags/*"
, вы refs/tags/xyzzy
добавлены в свой репозиторий (указывая на тот же коммит, что и на удаленном). Если вы используете, +refs/tags/*:refs/tags/*
то ваш тег xyzzy
, если он у вас есть, заменяется на тег из origin
. То есть +
флаг force в refspec означает «заменить значение моей ссылки на значение, которое мой Git получает из их Git».
Автоматические метки во время выборки
По историческим причинам 3, если вы не используете ни --tags
опцию, ни --no-tags
опцию, git fetch
предпринимает специальные действия. Помните, что мы говорили выше, что удаленный компьютер начинает с отображения в вашем локальном Git всех своих ссылок, хочет ли ваш локальный Git их видеть или нет. 4 Ваш Git принимает к сведению все теги, которые он видит на данный момент. Затем, когда он начинает загружать любые объекты коммитов, которые ему нужны для обработки того, что он выбирает, если один из этих коммитов имеет тот же ID, что и любой из этих тегов, git добавит этот тег - или эти теги, если несколько тегов имеют этот идентификатор - в ваш репозиторий.
Редактирование, январь 2017: тестирование показывает, что поведение в Git 2.10 теперь такое: если их Git предоставляет тег с именем T , и у вас нет тега с именем T , а идентификатор фиксации, связанный с T, является предком одной из их ветвей что ваш git fetch
изучает, ваш Git добавляет T к вашим тегам с или без --tags
. Добавление --tags
заставляет ваш Git получать все свои теги, а также принудительно обновлять.
Нижняя граница
Возможно, вам придется использовать, git fetch --tags
чтобы получить их теги. Если их имена тегов конфликтуют с существующими именами тегов, вам, возможно, (в зависимости от версии Git) даже придется удалить (или переименовать) некоторые из ваших тегов, а затем запустить git fetch --tags
, чтобы получить их теги. Поскольку теги - в отличие от удаленных веток - не имеют автоматического переименования, имена ваших тегов должны совпадать с именами их тегов, поэтому у вас могут возникнуть проблемы с конфликтами.
Однако в большинстве обычных случаев простое git fetch
будет выполнять свою работу, перенося свои коммиты и соответствующие им теги, и, поскольку они - кем бы они ни были - будут отмечать коммиты во время публикации этих коммитов, вы будете следить за их тегами. Если вы не создаете свои собственные теги и не смешиваете их репозиторий и другие репозитории (через несколько пультов), у вас также не будет коллизий имен тегов, поэтому вам не придется возиться с удалением или переименованием тегов, чтобы получить их теги.
Когда вам нужны квалифицированные имена
Я уже упоминал выше , что вы можете опустить refs/
почти всегда, и refs/heads/
и refs/tags/
и так далее большую часть времени. Но когда ты не можешь?
Полный (или почти полный в любом случае) ответ в в gitrevisions
документации . Git преобразует имя в идентификатор фиксации, используя последовательность из шести шагов, приведенную в ссылке. Любопытно, что теги переопределяют ветви: если есть тег xyzzy
и ветка xyzzy
, и они указывают на разные коммиты, то:
git rev-parse xyzzy
даст вам идентификатор, на который указывает тег. Однако - а это то, чего не хватает gitrevisions
- git checkout
предпочитает имена веток, поэтому git checkout xyzzy
вы будете помещены в ветку, игнорируя тег.
В случае двусмысленности, вы почти всегда можете прописать имя ссылки, используя его полное имя, refs/heads/xyzzy
или refs/tags/xyzzy
. (Обратите внимание , что это делает работу с git checkout
, но в возможно неожиданным образом: git checkout refs/heads/xyzzy
вызывает отдельностоящую-ГОЛОВУ проверку , а не отраслевая проверки Вот почему вы просто должны отметить , что. git checkout
Будет использовать короткое имя в качестве имени ветви первого: вот как ты проверить ветку, xyzzy
даже если тег xyzzy
существует. Если вы хотите проверить тег, вы можете использовать refs/tags/xyzzy
.)
Поскольку (как gitrevisions
заметки) Git попытается , вы также можете просто написать, чтобы идентифицировать тэг с тегом . (Однако если кому-то удалось записать правильную ссылку с именем в , это разрешится как . Но обычно должны быть указаны только различные имена .)refs/name
tags/xyzzy
xyzzy
xyzzy
$GIT_DIR
$GIT_DIR/xyzzy
*HEAD
$GIT_DIR
+1 Ладно, ладно, «не просто быть педантичным». :-)
2 Кто-то скажет «очень бесполезно», и я бы согласился на самом деле.
3 По сути, git fetch
и вся концепция удаленных и refspecs была немного поздним дополнением к Git, появившимся во времена Git 1.5. До этого было только несколько специальных особых случаев, и выборка тегов была одной из них, поэтому она была обнаружена с помощью специального кода.
4 Если это поможет, подумайте об удаленном Git как о мигалке в сленге.
git checkout A
, что такоеA
? Как вы создалиA
?