Гуляя по github'у я много раз видел в разных репозиториях одновременно и теги вида «v2.3.4» и коммиты с сообщениями типа «Bump version» и сменой номеров версии где-нибудь в lib/version.rb. И всегда мне казалось — что-то тут лишнее.
И когда пришло время задуматься и мне над расставлением номеров версий, я сказал: «Нет! Я не буду прописывать эти номера в файлы руками. Пусть это делает за меня моя система контроля версий!»
Итак, как вижу это я:
- Номер версии выглядит как тройка чисел: мажорная.минорная.патч-версия и увеличивается согласно рациональной политике назначений версий;
- При выпуске каждой новой минорной версии я для определённого коммита в истории создаю тег вида v<мажорная>.<минорная>;
- Git автоматически выдаёт мне номер версии, основываясь на последнем тэге (для этого коммита) и количестве коммитов, после него.
Как это работает:
В составе git есть много полезных команд, нас будут интересовать две:
git describe
— показывает информацию о самом последнем тэге, доступном из данного коммита;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