Как создать тег с определенными коммитами и направить его в исходное?

Скажите, что текущий журнал в моем gerrit выглядит следующим образом:

  • commit10 (мастер)
  • commit9
  • commit8
  • commit7
  • commit6 v1.72.0
  • commit5
  • commit4 v1.71.0
  • commit3
  • commit2
  • commit1

Моя цель - создать новый тег (v1.73.0), который должен содержать commit8 и commit9 и нажать его в начало. Мне было предложено создать новый локальный филиал на основе последнего стабильного тега и вишни - выбрать необходимые коммиты и пометить его. Тем не менее, у меня возникла проблема с нажатием тега до уровня master.

Вот что я сделал:

  • создать локальную ветвь на основе последнего тега: git checkout -b branchforv1.73.0 v1.72.0
  • cherry-pick commit8 и commit9
  • Создать новый тег: git tag v1.73.0

... так теперь, как я могу нажать v1.73.0 для master?

Результат:

  • commit10 (мастер)
  • commit7
  • commit9 v1.73.0
  • commit8
  • commit6 v1.72.0
  • commit5
  • commit4 v1.71.0
  • commit3
  • commit2
  • commit1

Ответ 1

Как работают теги

В git каждый тег называется "указывать на" (один, единственный) фиксатор. Фактически, то же самое относится к ветке: имя ветки также просто указывает на одно коммит.

Что делает эта работа двух вещей:

  • каждая фиксация также указывает на другую фиксацию (или, возможно, несколько), и
  • для ветвей (и только для ветвей), фиксация, на которую ветвь указывает "движется вперед" автоматически. То есть, когда вы добавляете новые коммиты - в некотором смысле, что в основном все git: добавляет новые коммиты в свой коллектив, вроде как Borg из старой серии Star Trek TNG - независимо от того, в какой ветке вы находитесь, что ветвь, которая получает повторную настройку, чтобы указать на новую фиксацию.

Таким образом, основное различие между веткой и тегом заключается в том, что тег не перемещается.

Чтобы узнать, как это работает, рассмотрите простой репозиторий git с тремя коммитами. Пусть эти метки обозначают A, B и C. Первая фиксация (A) указывает на ничего, поскольку первая фиксация и ветвь master указывают на A:

A   <-- master

Когда вы совершаете вторую фиксацию, git создает B, обращаясь к A, и продвигает имя ветки, чтобы указать на B:

A <- B   <-- master

Затем, когда вы делаете третий фиксатор, git снова заставляет его указывать на свой родительский коммит и продвигает ветвь:

A <- B <- C   <-- master

Если вы создадите тег, этот тег по умолчанию укажет на commit C:

A <- B <- C   <-- master
               \- sometag

Если вы затем создаете новый фиксатор D, git продвигает ветвь, но не тег:

A <- B <- C <- D   <-- master
           \
            `--------- sometag

Вы можете в любое время создать или удалить любой тег, указывающий на какое-либо конкретное сообщение:

$ git tag -d sometag

удалит тег sometag, после чего:

$ git tag sometag master~2

добавит sometag, указывающий на commit B. 1

(Мы только что доказали, что тег может двигаться. Реальная разница в том, что теги не должны двигаться, а ветки - и git не будет автоматически перемещать теги. 2 Предполагается, что ветки перемещаются в направлении "вперед", т.е. Если master используется для указания на фиксацию C и теперь указывает на фиксацию D, commit C обычно должен быть найден, начиная с D и работа в обратном направлении. Каждый раз, когда вы перемещаете ветвь так, чтобы это правило нарушалось, вы "переписываете историю", смотрите другие статьи, когда это нормально, и когда это вызывает у людей проблемы.)

Нажатие тегов

Когда вы используете git push, то, что вы действительно делаете, инструктирует какой-то другой репозиторий git принимать какие-либо новые коммиты, которые у вас есть, а они задают некоторые имена (-а) - обычно ветки и/или теги - чтобы указать на некоторые коммиты (по одному в каждом) в результирующем наборе. 3 Эти имена (ветки, теги и т.д.) в целом называются "ссылками", но позволяют просто использовать "ветвь" и "tag" на данный момент.

Аргумент after git push называет репозиторий (обычно с помощью имени "remote", например origin) для push-to. Если вы оставите это, git попытается определить один из них, но если вы хотите добавить название ветки или тега, вам нужно включить его явно, так как первое слово здесь считается удаленным именем. (То есть git push master пытается использовать master как имя удаленного, а не имя ветки.)

Чтобы вывести все ваши теги, вы можете просто добавить --tags в команду git push:

git push --tags origin

Чтобы нажать конкретный тег, вы можете его назвать:

git push origin sometag

так же, как вы можете нажать конкретную ветвь:

git push origin master

(На самом деле, этот четвертый аргумент представляет собой пару имен, таких как master:master или sometag:sometag, но по умолчанию он использует одно и то же имя с обеих сторон в большинстве случаев. 4)

Вы можете оставить имя origin, если вам не нужно, чтобы все аргументы, например, git push --tags совпадали с git push --tags origin (при условии, что все ваши нажатия идут на origin, в любом случае).

Совмещение

Чтобы установить тег на пульте дистанционного управления, сначала установите его локально, git tag name commit-identifier. Используйте любой зритель, который вам нравится, чтобы убедиться, что он установлен правильно. Затем нажмите его, либо git push origin name, либо git push --tags.


1 Синтаксис master~2 инструктирует git начать с фиксации, найденной с помощью master, затем выполнить резервное копирование на два шага. Вместо этого вы можете написать raw SHA-1 для фиксации B здесь.

2 Старые версии git (pre 1.8.4) случайно применяли правила ветвления к тэгам при нажатии (на удаленной стороне, т.е. они позволяют тегу перемещаться, если он был "быстрым" вперед ").

3 В некоторых случаях вы можете указать имя на "аннотированный тег", и ничто не мешает имени указывать на объект "tree" или "blob", но это не так нормальная настройка.

4Фактически, dst refspec по умолчанию для ветки сложный: это зависит от вашей конфигурации push.default и есть ли параметр remote.repository.push, а также настроен ли восходящий поток и т.д. Для тегов правила проще, поскольку нет такой вещи, как "восходящий поток".

Ответ 2

Как только вы создадите тег (который, похоже, вы это сделали), просто запустите

git push --tags origin

Ответ 3

Вот конкретный пример:

git add .
git commit -m "some description"
git tag v0.1.9 # or any other text
git push origin master # push the commit
git push --tags origin # push the tags