Подтвердить что ты не робот

Git - проверка удаленного тега, когда два пульта имеют одно и то же имя тега

Я надеялся, что это сработает:

git checkout remote/tag_name

но это не так. Это делает:

git checkout tags/tag_name

но я делаю что-то странное, где у меня много пультов, и я беспокоюсь о том, что произойдет, если у двух пультов есть один и тот же тег. Есть ли способ указать пульт при проверке тега?

4b9b3361

Ответ 1

Исполнительное резюме: то, что вы хотите достичь, возможно, но сначала вы должны изобрести удаленные теги.

Вы делаете это с помощью серии refspecs, по одному для каждого пульта. В остальном это касается того, что это такое, как они работают и т.д.


В вашем вопросе возникает вопрос о проверке "удаленного тега", но Git не имеет удаленных тегов, и это:

но я делаю что-то странное, где у меня много пультов, и я беспокоюсь о том, что произойдет, если у двух пультов есть один и тот же тег. Есть ли способ указать пульт при проверке тега?

показывает (я думаю) источник вашей путаницы.

Вернитесь на минутку и просто расскажите о том, что Git имеет в общем смысле, которые являются "ссылками". Чтобы упростить идею, конкретные формы ссылок включают в себя ваши имена локальных ветвей (master, devel, feature и т.д.), "Имена удаленных веток", такие как origin/master и stuff_from_bobs_computer/master, и имена тегов, Такие вещи, как Git "stash", также используют ссылки, и даже HEAD является ссылкой, хотя и очень особенной, и обычно является "символической" ссылкой. Дело здесь в том, что Git имеет множество форм ссылок, и все они действительно работают одинаково в конце: имя ссылки в конце концов разрешает одно из этих больших значений SHA-1, 676699a0e0cdfd97521f3524c763222f1c30a094 или что угодно.

Большинство ссылок - это такие вещи, как HEAD, ORIG_HEAD, MERGE_HEAD и некоторые другие в этих строках - на самом деле написаны имена, начинающиеся с refs/. Они хранятся в виде каталожной или папковой структуры, 1 с подкаталогами: refs/tags/ содержит ваши теги, 2refs/heads/ содержит все ваши ветки, и refs/remotes/ содержит все ваши удаленные ветки.

Удаленные ветки далее подразделяются на имя пульта: refs/remotes/origin/ содержит все удаленные ветки origin, а refs/remotes/stuff_from_bobs_computer/ содержит все удаленные ветки stuff_from_bobs_computer. Если у вас много пультов, у вас есть много подкаталогов внутри refs/remotes/.

Я только что упомянул, что ваши теги находятся в refs/tags/. Что относительно тегов пультов, все теги на всех различных пультах? Ну, опять же, Git не имеет "удаленных тегов" . Git имеет "удаленные ветки" , но на самом деле все локально. Они хранятся в вашем репозитории под заголовком refs/remotes/.

Когда ваш Git связывается с "remote" - обычно через git fetch remote, но также и для push (и начального шага clone), ваш Git запрашивает удаленный Git 3 вопрос: "Какие у вас локальные ветки? Каковы их значения SHA-1?" Фактически это работает как fetch: как упрощенное описание, процесс выборки состоит в том, чтобы запросить удаленный Git "эй, ададдаа получил?". и он дает вам набор имен и SHA-1. Затем ваш Git проверяет, имеет ли он один и тот же SHA-1. Если это так, разговор будет выполнен; если нет, ваш Git затем говорит: "Хорошо, мне нужно что-то в фиксации для этих SHA-1", что на самом деле оказывается еще одной связкой SHA-1, а ваш Git и их говорят об этом чтобы выяснить, какие файлы и что вам нужно, все идентифицированы SHA-1. Ваш Git переносит эти объекты и загружает новые SHA-1 в ваш refs/remotes/ под именем пульта, а затем под их именами локальных ветвей.

Если вы запрашиваете теги с помощью fetch, ваш Git делает немного больше. 4 Вместо того, чтобы просто спрашивать их Git об их ветвях, ваш Git также спрашивает их об их тегах. Опять же, их Git просто дает вам список имен и SHA-1. Затем ваш Git переносит все необходимые объекты, а затем - вот ключ ко всей проблеме - он записывает свои имена тегов в ваш refs/tags/.

Итак, что происходит, когда вы переходите к удаленному origin и задаете ему теги, и он говорит: "У меня есть refs/tags/pinky и refs/tags/brain", заключается в том, что это создает для вас локальные теги pinky и brain, также называемый refs/tags/pinky и refs/tags/brain в вашем ссылочном пространстве имен.

Теперь вы перейдете на компьютер Боба (удаленный с именем stuff_from_bobs_computer выше) и спросите его о тегах. Он в неврологии, а не в Warner Brothers и Sister, а его теги refs/tags/spinal_cord и refs/tags/brain, а второй, вероятно, не связан с тем, что находится на origin. Ох!

То, что здесь происходит, немного усложняется, 5но, короче говоря, это всего лишь плохая ситуация, и вам, вероятно, следует избегать ее, если это возможно. Есть два простых (ну...) способов избежать этого. Один, с очевидным недостатком, заключается в следующем: просто не получайте их теги. Тогда у вас не будет конфликтов тегов. Другой способ: хранить все свои теги отдельно друг от друга (и, возможно, от вас тоже). Оказывается, второе не так уж сложно. Вам просто нужно "изобретать" удаленные теги.

Позвольте взглянуть на то, как Git действительно реализует "удаленные ветки" и как работает fetch --tags. Они оба используют один и тот же базовый механизм, что Git вызывает "refspecs".

В своей простейшей форме refspec выглядит как два имени ref с двоеточием между ними: refs/heads/master:refs/heads/master, например. Фактически, вы даже можете оставить без изменений refs/heads/ и Git, вставьте его для вас, 6 и иногда вы также можете оставить двоеточие и повторное имя. Это то, что вы используете с git push: git push origin branch означает нажать на origin, используя ваш refs/heads/branch, и называть его refs/heads/branch, когда он прибывает и на "их" Git.

Для fetch, однако, делая удаленные ветки, вы получаете refspec, который выглядит следующим образом:

+refs/heads/*:refs/remotes/origin/*

+ спереди означает "сила", а * - очевидная вещь. Ваш Git разговаривает с ними и получает список ссылок. Те, которые соответствуют refs/heads/*, ваш приносит (вместе с их объектами репозитория по мере необходимости), но затем он привязывает их к вашему репо под именами, смотрящими на refs/remotes/origin/, и теперь у вас есть все "удаленные ветки" из origin. 7

При запуске git fetch --tags ваш Git добавляет +refs/tags/*:refs/tags/* к используемым refspec. 8 Это приносит свои теги и помещает их в ваши локальные теги. Итак, все, что вам нужно сделать, это дать fetch refspec, который выглядит так:

+refs/tags/*:refs/rtags/origin/*

и вдруг у вас будет новое имя-пространство "удаленных тегов" под refs/rtags/ (только для origin). Безопасно использовать флаг силы + здесь, так как вы просто обновляете свою копию своих тегов: если они имеют принудительное перемещение (или удаление и повторное создание) тега, вы принудительно перемещаете свою копию. Вы также можете хотеть или даже нуждаться в поведении --no-tags, которое вы можете получить, указав --no-tags в командной строке или, ну, см. Следующий абзац.

Единственный оставшийся полезный элемент, который нужно знать, заключается в том, что git fetch получает свои refspecs по умолчанию для любого заданного пульта из конфигурационного файла Git. 9 Если вы изучите конфигурационный файл Git, вы увидите строку fetch = под каждым удаленным, используя строку +refs/heads/*:refs/remotes/remote-name/*. Вы можете иметь столько строк fetch =, сколько хотите на каждый пульт, поэтому вы можете добавить их, чтобы вывести их теги, но поместите их в свое новое (повторно) изобретенное "удаленные теги". Вы также можете сделать --no-tags значение по умолчанию для этого пульта, установив tagOpt = --no-tags в этом же разделе. Подробнее см. этот комментарий пользователя200783.

Как и во всех командах Git, которые разрешают имя для необработанного SHA-1, вы можете git checkout заполнить полное имя для перехода в режим "отсоединенного HEAD" на соответствующем SHA-1:

git checkout refs/rtag/stuff_from_bobs_computer/spinal_cord

Поскольку Git не имеет идеи создания "удаленных тегов" , вы должны указать длинную форму (см. gitrevisions для деталей).


1 Фактически, это реальный каталог, в .git/refs. Тем не менее, есть также "упакованная" форма для ссылок, которая заканчивается в .git/packed-refs. Упакованная форма предназначена для экономии времени и усилий с помощью ссылок, которые не часто меняются (или вообще, как это часто встречается с тегами). Также предпринимаются постоянные усилия по перезаписи системы хранения "back end" для ссылок, поэтому в какой-то момент многое может измениться. Это изменение необходимо для систем Windows и Mac. Git считает, что имена ветвей и тегов чувствительны к регистру: у вас может быть ветка polish для вашего материала для обуви и polish для ваших колбас. Упакованные версии чувствительны к регистру, поэтому это работает; но версии с сохраненными в файлах иногда нет, поэтому нет!

2 Я замалчиваю разницу между легкими и аннотированными тегами. Аннотированные теги являются фактическими объектами в репозитории, а легкие теги - это метки в пространстве refs/tags/. Однако, как правило, каждый аннотированный тег имеет один соответствующий легкий тег, поэтому для этого конкретного использования они работают одинаково.

3Это почти всегда другое репо Git, хотя теперь есть адаптеры для Git для Mercurial, svn и т.д. У них есть свои трюки, претендующие на то, чтобы быть репозиториями Git. Кроме того, это описание не должно быть окончательным: фактическая последовательность операций кодируется для эффективности передачи, а не для создания смысла для людей.

4 Я замалчивал немного особой странности об простых fetch и clone здесь, то есть версии без --tags. Версии с --tags просты в объяснении: они используют все теги, используя описанные здесь refspecs, и, по крайней мере, в Git 2.10 и 2.11, --tags также выполняет принудительные обновления, как если бы + установлен флаг силы. Но если вы явно не вызываете --no-tags, простой выборка (и клон) вызывает некоторые теги. Скрытая вещь, которую он делает, - это искать теги, которые соответствуют объектам, поступающим из-за выборки, и добавляет эти (без принудительного обновления) к вашему глобальному тегу имя-пространства. Без --tags ваш Git не перезапишет ваши собственные теги; с --tags ваш Git перезапишет ваши собственные теги, по крайней мере, в Git 2.10, на фактические эксперименты, выполненные в начале 2017 года.

5 Старые версии Git применяют правила "ветки" к тэгам во время push (но не обязательно выборки), позволяя обновлять теги, если это была быстрая перемотка вперед, и в противном случае требуется сила флаг. Для более новой версии git push требуется только тег force. Функция refcpec из --tags не имеет набора флагов силы, но действует так, как если бы она была. Я не экспериментировал с push с помощью --tags. Там еще одна специальная git fetch странность о --tags vs --no-tags против явного refspecs, связанная с тем, как работает --prune. В документации указано, что --prune применяется к любой явной командной строке refs/tags/ refspecs, но не к неявному --tags refspec. Я также не экспериментировал, чтобы проверить это.

6 Для вашего Git для заполнения refs/heads/ или refs/tags/ для вас ваш Git должен быть в состоянии выяснить, какой из них вы имели в виду. В некоторых случаях это происходит, а некоторые - нет. Если ваш Git не сможет понять это, вы получите сообщение об ошибке и сможете повторить попытку с заполнением, но в скриптах вы должны всегда заполнять его явно, чтобы получить более предсказуемое поведение. Если вы просто запускаете git push, чтобы нажимать существующую ветку, вы почти всегда можете указать свой Git.

7 Оставив двоеточие, а второе имя не работает так хорошо для git fetch: он сообщает вашему Git не обновлять свои собственные ссылки вообще! Это кажется бессмысленным, но на самом деле может быть полезным, потому что git fetch всегда записывает специальный файл FETCH_HEAD. Вы можете ловить идентификаторы объектов Git (SHA-1) из специального файла и посмотреть, что получилось. Это в основном сдерживание с самых ранних версий Git, до того, как были изобретены ветки удаленного отслеживания.

8 refspec, который использует git fetch --tags и git push --tags, предварительно скомпилирован внутри, в Git версии 2.10 и обрабатывается каким-то специальным кодом кода. В предварительно скомпилированной форме не установлен флаг +; но эксперимент показывает, что извлеченные теги обновляются с усилием в Git 2.10/2.11. Я помню, как экспериментировал много лет назад с Git 1.x и обнаружил, что эти теги --tags не были обновлены по силе, поэтому я думаю, что это изменилось, но это может быть просто неисправная память. В любом случае, если вы (повторно) изобретаете удаленные теги, вы, скорее всего, не захотите использовать явный --tags.

9 Фактически, именно так работают зеркала. Например, при fetch = +*:* вы получаете чистое зеркало извлечения. Процесс выборки может видеть все ссылки. Вы можете увидеть их самостоятельно с помощью git ls-remote. Это также работает --single-branch: если вы используете --single-branch во время клонирования, ваш конфигурационный файл Git будет перечислять только одну ветвь в строке выборки. Чтобы преобразовать из одной ветки во все ветки, просто отредактируйте строку, чтобы содержать обычную запись шаблона шара.

Ответ 2

1 - Извлеките тег из пульта с помощью:

git fetch origin --tags 

Или, чтобы проверить тег с другого удаленного использования:

git fetch your_remote --tags

2 Проверьте тег, запустив

git checkout tags/<tag_name>

Подробнее здесь: Загрузите определенный тег Git

Ответ 3

В моем случае, когда новый тег был добавлен в удаленный репозиторий [я использую Stash], новый тег не был доступен в результате git tag -l.
Но я смог просмотреть добавленный тег с помощью git ls-remote --tags.
Мне пришлось запустить следующую команду, чтобы получить все последние теги в моем локальном репозитории:
git pull --tags Запуск git tag -l теперь отображает вновь добавленные теги.

Чтобы проверить тег, используйте:
git checkout <tag_name>

Примечание. Нормально запускать git статус и найти такое сообщение:
HEAD detached at tag_name

Ответ 4

На мой взгляд, есть несколько вопросов:

  • Почему разные пульты имеют разные коды (в одном и том же дереве)?
  • Почему удаленный код влияет на проверку тегов?

Дело в следующем:

Когда вы проверяете тег с помощью git checkout tags/fancytag, он будет выглядеть в вашем текущем репозитории (на вашем компьютере) для подходящего тега.

Если вы хотите проверить тег с определенного пульта, сначала нужно fetch его (дерево конкретного пульта), а затем проверить его.