Как достичь схемы числового управления версиями с помощью Git?

131

Моя организация рассматривает возможность перехода от SVN к Git. Один аргумент против переезда заключается в следующем:

Как мы делаем управление версиями?

У нас есть дистрибутив SDK, основанный на платформе NetBeans. Поскольку ревизии SVN являются простыми числами, мы можем использовать их для расширения номеров версий наших плагинов и сборок SDK. Как мы справимся с этим, когда переедем в Git?

Возможные решения:

  • Использование номера сборки от Hudson (проблема: вы должны проверить Hudson, чтобы соотнести это с реальной версией Git)
  • Ручное повышение версии до ночной и стабильной (проблема: кривая обучения, человеческая ошибка)

Если кто-то еще сталкивался с подобной проблемой и решил ее, мы хотели бы услышать, как.

Эрленд
источник
3
Не могли бы вы заставить свой сервер hudson (не jenkins ?) Автоматически добавлять gitтег после каждой успешной сборки? Это дает дополнительное преимущество, так как позволяет четко gitопределить, какие коммиты имеют проблемы со сборкой или неудачные тесты, поскольку они остаются без тегов.
Марк Бут
Как примечание, вы можете добавить счетчик сборок к тегу, отслеживая время сборки .
Шахбаз
Не уверен, что это жизнеспособное решение, но как насчет экспорта из git в репозиторий SVN прямо перед каждой сборкой? Затем просто соберите из репозитория SVN - если мы хотим централизованного, просто используйте это вместо.
Джонни

Ответы:

152

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

git tag -a v2.5 -m 'Version 2.5'

Нажмите теги вверх по течению - это не сделано по умолчанию:

git push --tags

Затем с помощью описания команды:

git describe --tags --long

Это дает вам строку в формате:

v2.5-0-gdeadbee
^    ^ ^^
|    | ||
|    | |'-- SHA of HEAD (first seven chars)
|    | '-- "g" is for git
|    '---- number of commits since last tag
|
'--------- last tag
Джон Перди
источник
Согласитесь - должно быть легко автоматизировать ночную нумерацию тегов, если вам это нужно, и в любом случае повышение до стабильного происходит вручную.
бесполезно
20
Небольшие улучшения: git describe --long --tags --dirty --always. «Грязный» скажет вам, были ли локальные изменения, когда «описать» было сделано (то есть он не может полностью описать состояние репо). «Всегда» означает, что вы не получите ошибку, если нет тегов. Это откатится на хеш коммита. Таким образом, вы можете получить 76001f2-dirtyв качестве примера. Очевидно, что видеть «грязный» означает, что кто-то напутал.
Майк Веллер
1
Как это может работать, когда тег генерируется последним . Обычно вы хотите, чтобы сборки собирались в следующей версии вашего продукта. Но они всегда будут вынуждены использовать последнюю версию в этом случае. Только окончательная поставленная сборка будет иметь правильный номер.
void.pointer
@ void.pointer: Конечно, этот номер версии отвечает на вопрос «на каком выпуске был основан этот коммит?», а не на «каком выпуске будет этот коммит?». Однако вы можете по-разному интерпретировать теги. Например, если вы пометите HEADкак v2.5, вы также можете интерпретировать это как начало цикла выпуска 2.5, затем пометить v2.5-releaseили что угодно.
Джон Перди
8
Еще одно небольшое улучшение. Если вы хотите использовать и другие теги, но для генерации ревизий использовать тег с определенным шаблоном, вы можете использовать такую --matchопцию:git describe --long --tags --dirty --always --match 'v[0-9]\.[0-9]'
Александр Амелькин
42

Это придумало несколько проектов для меня. Лучшее решение, которое у меня было до сих пор, - это создать номер версии, подобный этому:

xy <количество коммитов> .r <git-hash>

Как правило, он генерируется нашей системой сборки с использованием комбинации некоторого статического файла или тега для получения основных номеров ревизий git rev-list HEAD | wc -l(что было быстрее, чем при использовании git log), и git rev-parse HEAD. Рассуждение было следующим:

  1. Нам нужна была возможность явного управления версиями на высоком уровне (iexy)
  2. Когда происходила параллельная разработка, нам НИКОГДА не нужно было генерировать один и тот же номер версии.
  3. Мы хотели легко отследить, откуда появилась версия.
  4. Когда параллельные линии были объединены, мы хотели, чтобы новая версия имела разрешение выше, чем любая из ветвей.

Номер 2 невидим для большинства людей, но он действительно важен и действительно сложен с распределенным контролем версий. SVN помогает с этим, давая вам один номер ревизии. Оказывается, что количество коммитов настолько близко, насколько вы можете получить, и при этом волшебным образом решаете и №4. При наличии ветвей это все еще не уникально, и в этом случае мы добавляем хеш, который также аккуратно решает # 3.

Большая часть этого заключалась в размещении через пипс Python. Это гарантировало, что pip installэто может быть немного странно во время параллельной разработки (то есть пакеты от людей из разных ветвей будут смешиваться, но детерминированным образом), но после слияний все будет разобрано. За исключением наличия открытой перебазировки или поправки, это работало довольно хорошо для вышеуказанных требований.

Если вам интересно, мы решили поставить r перед хешем из-за некоторой странности с тем, как упаковка Python обрабатывает буквы в номерах версий (то есть ae меньше 0, что означает «1.3.10.a1234» < «1.3.10» <«1.3.10.1234»).

Jayson
источник
1
Кстати, как вы справились с проблемой куриного яйца при определении git-hash перед тем, как проверить его? Вы использовали какую-то форму .gitignore или какой-то другой трюк?
kfmfe04
3
Я не Я не использую хэш до времени сборки пакета, которое является долгим после регистрации. У разных языков есть разные способы это внедрить. Для Python я использую './setup.py egg_info -b ". $ {BUILD_VERSION}" sdist ". Для C и C ++ я определяю макрос во время компиляции с помощью 'CFLAGS = -D "$ {BUILD_VERSION}"'. Для Go я определяю символ во время ссылки с помощью 'go install -ldflags appmodule.BuildVersion "-X. $ {BUILD_VERSION}"'.
Джейсон
1
Это должен быть лучший ответ.
Альвинабад
очень хороший ответ
Хейликс
9

Это может быть немного излишним, но я дам вам знать, как мы это делаем.

Мы используем ветвящуюся структуру, очень похожую на эту .

Хадсон строит наши ветки "разработка" и увеличивает номера сборки, начиная с 0. Номер сборки уникален для каждого проекта и помечается тегами в управлении версиями. Причина в том, что вы можете точно сказать, например, из какой сборки разработки произошла 42 ветка (каждый проект может иметь несколько параллельных ветвей разработки, поскольку в каждом проекте может быть несколько команд, работающих над различными аспектами проекта).

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

Пример: 2.1.0 сборка 1337

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

деревенщина
источник
8

Версии идентифицируются хэшированием SHA1-хэшей всех файлов в хранимом дереве каталогов во время регистрации. Этот хеш хранится вместе с хешами родительских проверок, чтобы можно было прочитать всю историю.

Взгляните на процесс использования 'git-description' с помощью GIT-VERSION-GEN и на то, как вы можете добавить это через процесс сборки, когда помечаете свой релиз.

Вот хороший блог, который дает пример того, как получить то, что вы хотите:

http://cd34.com/blog/programming/using-git-to-generate-an-automatic-version-number/

SoftwareCarpenter
источник
0

У Джона Перди правильная идея. git flowтакже упрощает фактическое управление этими филиалами, а управление филиалами является аргументом для перехода к git.

Давайте начнем с основным выбегом git, так как вы пришли с svn-До- gitточки зрения. Учтите gitследующее:

master--...............-.....-..............-
        \             /     /              /
         ---develop---------............../
                            \            /
                             --feature---

Выше вы переходите masterна develop(обозначается \) и переходите developна featureветку. Мы объединяем эти ветви обратно (обозначается /) с помощью commits ( -) вдоль ветви. (Если коммита нет, но слияние направо, есть .индикаторы, показывающие, что -следующий коммит следующий).

Достаточно просто. Что если у нас есть исправление в нашем основном выпуске?

master--...............-.....-................-...........-.........-
        \             /     /                / \         /|        /
         \           /     /                /   -hotfix-- V       /
          ---develop---------............../..............-...----
                             \            / \             V   /
                              --feature---   --feature2...----

Выше, developразветвленный от master. Обнаруженная ошибка masterбыла исправлена ​​путем ветвления master, исправления и слияния с master. Затем мы слились masterв develop, а затем developвfeature2 , который свернул новый код из hotfixэтих веток.

При слиянии feature2обратно develop, его история включает в себя developс hotfix. Аналогично, developобъединяется feature2с новым кодом из master, так что объединение с developобратно masterбудет происходить без проблем, так как оно основано на этом коммите в masterто время - как если бы вы разветвились с masterэтого момента.

Так вот еще один способ сделать это.

master--..........-........-
        \        /\       /
         ---1.0--  --1.1-- 

Ваши 1.0 релизы получить tagged- 1.0.1, 1.0.2, 1.0.3и так далее.

Теперь вот хитрость: вы обнаружили ошибку в 1.0, и она затрагивает 1.1, 1.2 и 1.3. Чем ты занимаешься?

Вы отключаете свой последний или самый ранний поддерживаемый выпуск и исправляете его. Затем слить свой новый hotfixфилиал в 1.3й в 1.2, 1.1и 1.0. Не переходите от каждой ветки версии обслуживания; не сливаются 1.0в masterили сливаться masterобратно в 1.0. Возьмите одну hotfixветку и объедините ее со всеми ветками вашей версии. Если будут конфликты, это скажет вам; проверьте ваш код, чтобы убедиться, что изменения верны ( git diffэто ваш друг).

Теперь это конкретное изменение применяется везде. Род разветвленный, но все в порядке. Это не случайно. Тег в 1.3голову, 1.3.17, объединить его в каждый прогресс особенность-в-разветвленного с 1.3, и двигаться дальше.

git flowРасширение помогает управлять этим обслуживание, функцией и ветвью исправлений для вас. Как только вы отключите рабочий процесс, это будет тривиально и избавит вас от проблем с управлением исходным кодом.

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

Джон Мозер
источник
-6

Pro Git в разделе 7.2 «Атрибуты Git» в «Ключевом слове» Часть расширения содержит хороший пример использования грязных и чистых фильтров для генерации ключевых слов в стиле RCS. Вы можете использовать ту же технику для встраивания some-version-string в код, отформатированный и рассчитанный в соответствии с вашими правилами . Вы все еще можете использовать git describeв качестве отправной точки, но у вас есть возможность преобразовать в любую более подходящую форму и получить из v2.5-14-feebdaed, например, clean 2.5.14.

Ленивый Барсук
источник
9
-1 за испорченный хороший ответ с совершенно неуместными атаками ad hominem.
Йорг Миттаг
9
Кто сказал, что это были парни, которые голосовали за тебя? Это могут быть люди, которые предпочитают немного вежливости .
Марк Бут
К вашему сведению, я только что отредактировал ответ.
Кит Томпсон
git describeвыводит имя тега, если --longоно не было передано или нет коммитов с момента последнего тега, так что он уже совершенно чистый. Если бы вы не меняли значения по умолчанию, это дало бы вам именно то, что вы хотели.
strcat 25.01.15