При разработке программного обеспечения основной задачей является отслеживание версий созданного программного обеспечения с течением времени. Это становится особенно важным всякий раз, когда двоичные файлы передаются клиентам или QA для оценки. Всякий раз, когда заинтересованное лицо комментирует программное обеспечение (например, сообщает об ошибке), ключевой информацией для воспроизведения ситуации является используемая версия программного обеспечения.

Возможным подходом было бы увеличение номера версии всякий раз, когда создается двоичный файл. Однако это влечет за собой две проблемы. С одной стороны, необходимо обеспечить, чтобы номер версии увеличивался при каждой сборке. С другой стороны, потребуется последовательное сопоставление номеров версий двоичных файлов с моментальными снимками исходного кода, чтобы воспроизвести исходные коды, используемые для создания двоичного файла.

Альтернативный подход — включить генерацию номеров версий непосредственно в цепочку инструментов компиляции. Всякий раз, когда создается двоичный файл (либо с помощью Makefile, либо с помощью Microsoft Visual Studio 2015), номер версии генерируется с использованием функций системы контроля версий Git и записывается в произвольно используемый макрос C++. Этот номер версии обеспечивает точную идентификацию моментального снимка исходного кода в системе контроля версий, используемого для создания двоичного файла.

Использование Git для создания номера версии

Система контроля версий Git предлагает мощную команду для получения описания текущего коммита: git description [1]. В этом случае команда, включающая необходимые параметры:

git describe --abbrev=40 --dirty --always --tags

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

Параметр abbrev=40 устанавливает длину вывода хеш-значения равной 40. Добавление параметра dirty включает суффикс -dirty, если рабочее дерево грязное, т. е. есть незафиксированные изменения. Параметр всегда включает резервный вариант уникального объекта фиксации, параметр теги улучшает отображение имен тегов (подробности см. в [1]).

Linux (Makefile)

Если программное обеспечение собрано с использованием Make, Makefile должен быть дополнен некоторыми дополнительными строками:

GITREF = $(shell git describe --abbrev=40 --dirty --always --tags)
# ...
all : versionfile ...
# ...
versionfile: 
   @echo "#define VERSION \"$(GITREF)\"" > ../src/version.h

Сначала результат введенной выше команды git записывается в переменную GITREF. Эта строка версии впоследствии используется как #define в version.h, так что ее можно легко использовать в качестве макроса в исходном коде.

Windows (Visual Studio 2015)

В настройках проекта откройте диалоговое окно свойств и установите событие перед сборкой следующим образом:

В поле командной строки задайте следующую команду:

set cmd="git describe --abbrev=40 --always --dirty --tags "
FOR /F "tokens=*" %%i IN (' %cmd% ') DO SET X=%%i
echo #define VERSION ^"%X%^" > "..\src\version.h"

Эта команда в основном представляет собой способ чтения результата команды в переменную оболочки Windows и последующей записи его в файл. Обратите внимание, что команда git должна быть доступна в оболочке Windows, т. е. путь к каталогу установки Git должен быть частью переменной среды PATH.

Использование номера версии

В исходном коде C++ номер версии вставляется путем включения version.h и использования макроса VERSION подобно обычной строковой переменной:

cout << "Version: " << VERSION << endl;

Вывод программы, в зависимости от текущего состояния локального репозитория Git, имеет вид

Version: 1686aa61001cd232b9af01671c5f99450cd28851