Как я могу заполнить идентификатор фиксации Git в файл при совершении?

Я хотел бы создать Git hook (s), который заполнит идентификатор фиксации коммита, который я собираюсь внести в файл (в основном, переменную замену) в моем исходном коде. Возможно ли это с помощью Git? Или это тот факт, что, разрешив переменную на id Git, я собираюсь изменить sha 1, тем самым завершая проблему с курицей или яйцом.

Ответ 1

Решение, которое я использовал для аналогичной ситуации, таково:

  • Поместите строку $Id$ где-нибудь в файл, который вы хотите идентифицировать (например, test.html), вероятно, в комментарии или в другом нефункциональном разделе файла, где это не вызовет проблем.
  • В вашем .gitattributes, укажите соответствующий файл с ключевым словом ident (например, *.html ident).

В результате этого, когда git checkout копирует файл из базы данных объекта в ваш рабочий каталог, он расширяет строку $Id$ для чтения $Id: <sha-1 of file>$, а git add меняет это преобразование, когда вы хотите проверьте его, поэтому версии этого файла в вашей базе данных объектов всегда содержат $Id$, а не расширенные формы.

Это начало, но, к сожалению, найти коммит, содержащий файл с конкретным хешем, не так просто, и не обязательно одно к одному. Таким образом, кроме того, я также помещаю те файлы с атрибутом export-subst (например, *.html ident export-subst в .gitattributes) и добавляю дополнительную строку, например $Format:%ci$ ($Format:%h$) где-то в файле.

git checkout и git add не влияют на эти теги, поэтому версии в моем репозитории всегда имеют именно эту строку. Чтобы расширить те теги, вы должны использовать git archive для создания tar-шара (или .zip) конкретной версии вашего проекта, который затем используется для развертывания этой версии, - вы не сможете просто скопируйте файлы или make install или что-то еще, поскольку git archive - это единственное, что расширит эти теги.

Два тега, которые я дал в качестве примера, расширяются до YYYY-MM-DD HH:MM:SS +TZOFFSET (HASH), где HASH в этом случае является фактическим хешем фиксации, поэтому он более полезен.

Вы можете найти другие потенциально полезные спецификаторы $Format:$ на странице справки git log в спецификаторах --pretty-format.

Ответ 2

Вы можете создать фильтр, который выполняет подстановку в файлах при фиксации и контроле. Они называются "размытыми" и "чистыми" фильтрами, а их работа контролируется через .gitattributes. Например:

*.c     filter=yourfilter

Это сообщает git запустить фильтр yourfilter для всех файлов .c. Затем вы должны сообщить git, что yourfilter означает:

git config --global filter.yourfilter.clean script1
git config --global filter.yourfilter.smudge script2

Затем вы пишете script (sed, Perl, Python или что-то еще), чтобы заменить выражение $LastSha$ на $LastSha: <sha>$ на checkout ( "smudge" ). Другой script отменяет расширение перед фиксацией ( "clean".)

Найдите в Pro git книгу для расширенного расширения ключевого слова.

Ответ 3

Невозможно выполнить то, что вы хотите: хеш фиксации SHA-1 вычисляется по всему снимку репозитория, включая каждый файл-член, так что проблема с цыпленком и яйцом — для вычисления хеша фиксации вам необходимо знать содержимое всех файлов, которые его содержат.

Ответ 4

Вы можете сделать это с помощью post-commit hook. Здесь выдержка из веб-сайта git -scm

После завершения всего процесса фиксации запускается крюк после фиксации. Он не принимает никаких параметров, но вы можете легко получить последнюю фиксацию, запустив git log -1 HEAD. Как правило, этот script используется для уведомления или чего-то подобного.

Это будет случай получения результата git log -1 HEAD, а затем с помощью инструмента, такого как sed, заменить переменные в вашем файле. Тем не менее, это изменяет ваш рабочий каталог, и если вы не собираетесь выбросить эти изменения, то у вас будет постоянно измененный рабочий каталог.

Если вы просто хотите использовать текущий хеш фиксации в переменной где-то в вашем коде, вы можете просто выполнить git log -1 HEAD или cat .git/HEAD и сохранить вывод в своей переменной

Если вам нужен только идентификатор (хэш), как в заголовке вопроса, вы можете использовать флаг --format. git log -1 HEAD --format=%H

Ответ 5

Ключ здесь состоит в том, чтобы поместить ваш идентификатор ревизии в какой-либо файл, который не имеет значения Git. Вот фрагмент из одного из моих проектов:

.
.
.
AssemblyCS="Properties/AssemblyInfo.cs"
rev="$(git log -n 1 --date=short --format=format:"rev.%ad.%h" HEAD)"
sed  "$AssemblyCS"
.
.
.

Этот script выполняется как часть моего процесса сборки (это также может быть крюк после фиксации). В этом случае Properties/AssemblyInfo.cs находится в .gitignore, тогда как Properties/AssemblyInfo.cs.in находится под управлением версии. В сборке используется файл .cs, который включает идентификатор ревизии, который заканчивается в развернутом исполняемом файле.

Ответ 6

Как уже упоминалось, вы не можете поместить SHA-1 коммита в файл во время одного и того же коммита. В любом случае это будет ограниченным использованием, так как вы смотрите на два файла, которые вы не могли бы сразу определить, что является более новым.

Таким образом, фактически существует возможность автоматически передавать информацию о отслеживании версии в файлы с фиксацией. Я сделал это для моего текущего проекта (FrauBSD; развилка FreeBSD, над которой я работаю).

Я достиг этого не с помощью фильтра git -attributes. В то время как фильтры git -attributes облегчают достижение противоположного значения (помещают информацию в файл в кассе), я хотел бы расширить определенные ключевые слова во время фиксации, чтобы данные попадали в репозиторий (например, после "начального хозяина git push", github показывает расширенные значения в файле (-ах), который был зафиксирован. Достижение последнего оказалось чрезвычайно сложным с помощью фильтра git -attributes именно потому, что простой "git diff" будет ссылаться на атрибут filter.clean и, как это было в моем случае, если вы помещаете информацию о дате/времени в расширение, изменяющее значение каждый раз, когда вы выполняете "git diff", является нежелательным и неприемлемым.

Итак, я разработал крюк pre-commit и hook-commit-msg, которые, действуя сообща, решают проблему того, как (в частности, в случае FrauBSD) заменить следующие в файлах:

$FrauBSD $

С чем-то похожим на следующее до регистрации (расширенные значения идут вверх по течению для других для проверки):

$FrauBSD: путь к файлу YYYY-MM-DD HH: MM: ZZ GMTOFFSET committer $

Когда кто-либо просматривает файл в github или выполняет проверку или слияние файлов (файлов), расширенная информация идет по пути.

ПРИМЕЧАНИЕ. Расширенное значение никогда не изменится, если не будет другого (несвязанного) изменения, сопровождающего соответственно.

Например, см. следующий коммит, в котором я просто удаляю конечную новую строку файла. Коммит содержит как удаление конечной новой строки, так и рельеф даты/времени в ключевом слове $FrauBSD $:

https://github.com/freebsdfrau/FrauBSD/commit/060d943d86bb6a79726065aad397723a9c704ea4

Чтобы произвести это коммитирование, я сделал то, что большинство разработчиков [ git] знакомы с:

  • vi ЛИЦЕНЗИЯ
  • Shift-G # перейти к концу файла
  • dd # удалить текущую строку
  • ZZ # сохранить файл и выйти
  • git diff # diff показывает удаление завершающей строки новой строки ПРИМЕЧАНИЕ: diff не показывает изменение значения $FrauBSD $[пока]
  • git добавить ЛИЦЕНЗИЮ
  • git diff # ничего (без неустановленных изменений)
  • git diff --cached # diff показывает удаление завершающей строки новой строки ПРИМЕЧАНИЕ: diff [still] не показывает изменения значения $FrauBSD $
  • git статуС# показывает измененную ЛИЦЕНЗИЮ
  • git commit # $появляется EDITOR
  • Ctrl-Z # положить $EDITOR в фоновом режиме, чтобы мы могли исследовать
  • git diff --cached # diff [now] показывает обновление $FrauBSD $, а также удаление конечной новой строки
  • fg # resume $EDITOR
  • : д! # quit Редактор без изменений ПРИМЕЧАНИЕ. Поскольку вы прервали фиксацию, исправлено $FrauBSD $.
  • git diff --cached # diff [снова] показывает только завершение удаления новой строки
  • git commit # на этот раз мы не отменим
  • BumpZZ # Вставить "Bump", сохранить и выйти
  • Файл зафиксирован как-есть

ПРИМЕЧАНИЕ. Ничего не нужно делать для файла post-commit

Это потому, что в моем проекте есть следующие файлы:

  • .git/hooks/pre-commit (символическая ссылка на.. /../. hooks/pre-commit)
  • .git/hooks/commit-msg (символическая ссылка на.. /../. hooks/commit-msg)
  • .hooks/предварительной фиксации
  • .hooks/фиксации-сообщ
  • .filters/fraubsd-ключевые слова

Исходные изменения, которые вы можете получить здесь:

"Добавить крючки/фильтры для смазывания с предварительной фиксацией"

https://github.com/freebsdfrau/FrauBSD/commit/63fa0edf40fe8f5936673cb9f3e3ed0514d33673

ПРИМЕЧАНИЕ. Фильтры используются крючками (не используются в git -attributes).

И обновление здесь:

HTTPS -//github.com/freebsdfrau/FrauBSD/commit/b0a0a6c7b2686db2e8cdfb7253aba7e4d7617432

Или вы можете посмотреть изменения главы здесь:

HTTPS -//github.com/freebsdfrau/FrauBSD/tree/master/.filters

HTTPS -//github.com/freebsdfrau/FrauBSD/tree/master/.hooks

ПРИМЕЧАНИЕ: двоеточие изменилось на - над URL-адресами, поэтому я могу разместить более двух ссылок (поскольку репутация низкая)

Enjoy, FreeBSDFrau

Ответ 7

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

version.h:
        git log -n 1 --format=format:"#define GIT_COMMIT \"%h\"%n" HEAD > [email protected]

Это не совсем общее решение, но оно может пригодиться. Я знаю место или два, где я буду использовать его.

Ответ 8

Я искал что-то подобное, потому что мне нужна уникальная переменная, которую я мог бы добавить в конец файлов ресурсов (например, CSS/JS) в нашем интерфейсе, что позволило бы нам установить очень длительное время кеша, чтобы уменьшить пропускную способность и повысить производительность, но легко заставить их перезагружаться после любого фиксации. По сути, управление версиями файлов, но полностью автоматизированное. Меня не волновало, что это был последний день, пока он был уникальным, автоматизированным и последовательным во всех наших серверах приложений.

Наше развертывание script просто использует git clone ', чтобы вытащить копию последнего кода на наши серверы приложений, но мы ограничиваем доступ через .htaccess к этим файлам и каталогам.

Каталог /.git/ содержит файл с именем ORIG_HEAD, который обновляется после любого слияния (или любой другой опасной операции) с идентификатором Commit ID его предшественника. Поскольку мы используем поток git, это идеально, потому что он обновляется каждый раз, когда мы нажимаем release или fix на основную ветвь и развертываем.

Вы можете сделать это Я предполагаю на любом языке сценариев, но в нашем случае PHP, я сделал это как это...

define("MY_VERSION",substr(file_get_contents(realpath(__DIR__.'/../.git/ORIG_HEAD')),0,3));

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

Надеюсь, что кто-то поможет в той же ситуации.

Ответ 9

Я искал ответ на этот вопрос. Идентификатор Commit уже записан в файл, который вам нужно знать, где искать. После совершения фиксации на главной ветке вы можете найти хеш фиксации в ./.git/refs/heads/master Поэтому в нашем решении непрерывной доставки (он загружает папку .git вместе с исходным кодом) мы можем просто cat ./.git/refs/heads/${BRANCH} чтобы связать текущий хеш фиксации с нашей сборкой