Полуавтоматическое выставление номера версии с помощью git

в 3:43, , рубрики: Git, версии, разработка, Системы управления версиями, метки: , ,

Гуляя по github'у я много раз видел в разных репозиториях одновременно и теги вида «v2.3.4» и коммиты с сообщениями типа «Bump version» и сменой номеров версии где-нибудь в lib/version.rb. И всегда мне казалось — что-то тут лишнее.

И когда пришло время задуматься и мне над расставлением номеров версий, я сказал: «Нет! Я не буду прописывать эти номера в файлы руками. Пусть это делает за меня моя система контроля версий!»

Итак, как вижу это я:

  1. Номер версии выглядит как тройка чисел: мажорная.минорная.патч-версия и увеличивается согласно рациональной политике назначений версий;
  2. При выпуске каждой новой минорной версии я для определённого коммита в истории создаю тег вида v<мажорная>.<минорная>;
  3. Git автоматически выдаёт мне номер версии, основываясь на последнем тэге (для этого коммита) и количестве коммитов, после него.

Как это работает:

В составе git есть много полезных команд, нас будут интересовать две:

  1. git describe — показывает информацию о самом последнем тэге, доступном из данного коммита;
  2. git show — отображает различные типы объектов (но нас будет интересовать только текущий коммит).

Вооружившись этими знаниями, я в свой rails проект в папку config/initializers поместил файл version.rb следующего содержания:

module AppName
  module Version
    Described = (IO::popen('git describe --long') { |gs| gs.read }).strip
    Number = Described.gsub('-', '.').gsub(/^v/, '').split('.')[0..-2].join('.')
    Date = Date.strptime( IO::popen('git show -s --format="%ct"') { |gs| gs.read } , "%s")
    Revision = (IO::popen('git show -s --format="%H"') { |gs| gs.read }).strip
  end
end

Здесь происходит следующее:

Команда git describe --long выводит сообщение примерно следующего вида: v0.8-3-g387f83f, где

  • v0.8 — имя тега
  • 3 — количество коммитов после этого тега (0 если тэг поставлен на текущий коммит)
  • 387f83f — короткий хэш текущего коммита.

Строчка Described.gsub('-', '.').gsub(/^v/, '').split('.')[0..-2].join('.') приводит это сообщение к виду 0.8.3

Командой git show -s --format="%ct" мы получаем дату создания текущего коммита в формате Unix.

А git show -s --format="%H" возвращает нам полный хэш коммита.

Результат

Теперь при старте приложения нам автомагически становится доступен текущий номер версии и дата выпуска. И теперь, где-нибудь на страничке мы можем написать:

"Приложение AppName. Версия #{AppName::Version::Number} от #{I18n.l AppName::Version::Date, :format => :long} года."

И получить

"Приложение AppName. Версия 0.8.3 от 27 марта 2012 года."

Плюсы и минусы

Плюсы
  • Париться над номерами версий теперь приходиться меньше, да и случаи «А, блин, забыл увеличить номер версии!» теперь будут реже (всё-таки минорные и мажорные версии не каждый день выходят, правда?);
  • (Как результат предыдущего пункта) Устраняется потенциальная возможность несоответствия номеров версий в репозитории и в коде (в коде их больше нет);
  • Идеально подойдёт для компилируемых программ (С++), как часть процесса сборки.

Минусы
  • Вне репозитория работать не будет (а кто и зачем собрался держать код вне репозитория?);
  • Жёсткая привязка количества коммитов к патч-номеру версии (с другой стороны — не делайте коммит на каждую строчку кода);
  • Иногда номер версии всё-таки должен быть прописан жёстко;
  • Не подойдёт для, например, PHP, так как вызывать пару тройку shell-комманд на каждый запрос — накладно.

Что почитать?

Ну, во-первых, мануалы по git describe и git show.

А вообще, поиск по "<CVS> autoversioning" (где <CVS> — название вашей любимой системы контроля версий) выдаст вам немалое количество рецептов для любых случаев, программ и технологий.

Успехов вам в наведении порядка (хотя бы в версиях).

Автор: Envek

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js