Git hook, изменить файлы коммитов
Я пытаюсь написать скрипт git pre-commit hook, он должен записывать дату коммита в начале измененных файлов. Моя проблема в том, что я не могу добавить измененные файлы в предыдущий коммит. Когда я пытаюсь снова вызвать git commit, он запускается рекурсивно. Как я могу написать скрипт, который добавляет время модификации в конце измененных файлов?
Мой код:
#!/bin/bash
files_modified=`git diff-index --name-only HEAD`
for f in $files_modified; do
if [[ $f == *.groovy ]]; then
$line = $(head -1 f)
if [[ $line == "/%%*" ]];
then
sed -i 1d
fi
echo "/%% " + $(date +"%m_%d_%Y") + " %%\\" >> f
git add f
fi
done
git commit --amend #recursive
exit
3 ответа
Вы не можете изменить коммит в хуке предварительной фиксации.
И то, что вы делаете, похоже на механизм раскрытия ключевых слов, который не является наилучшей практикой в Git (или любой DVCS), как описано в разделе " Чтобы поставить префикс" ?<revision-number>
на коды Git / Svn ".
Другие подходы включают в себя:
- создание отдельного файла с нужной вам информацией (а затем фиксация).
Смотрите, например, " Развертывание информации Git SHA1 в регистрацию без архивирования? ". - хранение этой информации в git note (которые отделены от коммитов и не изменяют SHA1).
Смотрите раздел " Добавление заметок Git к BLOB-объектам ".
Глядя на ваш хук до фиксации, вы почти что-то работали. Вот минимальные изменения, которые я считаю необходимыми:
#!/bin/bash
files_modified=`git diff --cache --name-only --diff-filter=ACM`
### fix: use current branch; cached; and only files
for f in $files_modified; do ### broken: if space in filename(s)
if [[ $f == *.groovy ]]; then
line=$(head -1 $f) ### fix: forgot a $ before f
if [[ $line == "/%%*" ]];
then
sed -i 1d "$f" ### fix: forgot file argument
fi
echo "/%% " + $(date +"%m_%d_%Y") + " %%\\" >> $f
### fix: forgot a $ before f
git add -u $f ### fix: forgot a $ before f
fi
done
### undesired ### git commit --amend #recursive
### unneeded ### exit
Тем не менее, я заметил несколько проблем с вашей реализацией. Вы удалите строку, соответствующую "/%%*", в верхней части файла и добавите новую в конец. Каждый раз, когда вы запускаете это, вы всегда будете добавлять новые /%% mm_dd_YYYY %%\
строка в конец файла. Это может быть не то, что вы хотите (1000 коммитов позже, ранее пустой файл будет иметь 1000 строк). Я думаю, что вы хотели сделать, это заменить существующую линию. В этом случае будет работать перевод sed для замены совпадающих строк.
Вот рецепт, который, я думаю, приближается к тому, что вы хотели:
#!/bin/sh
TMPFILE="/tmp/${0##*/}.$$"
for f in $( git diff --cached --name-only --diff-filter=ACM ); do
# XXX broken: if space in filename(s)
case "$f" in
*.groovy) : fall through ;;
*) continue
esac
cp "$f" "$TMPFILE" || continue
awk -v new="/%% $(date +%m_%d_%Y) %%\\" \
'NR==1{sub("^/%% .* %%\\\\$",new)}1' \
< "$TMPFILE" > "$f"
git add -u -- "$f"
done
Если первая строка файла совпадает /%% ... %%\
затем он обновляется с текущей датой / временем (во время ловушки перед фиксацией).
Однако это было просто для того, чтобы проиллюстрировать, как это можно сделать просто. Это на самом деле не полное решение. Вышеприведенный скрипт не будет работать с файлами, в имени которых есть пробелы, двойные кавычки, обратная косая черта, вкладки и т. Д.
Для полного решения:
Используйте следующий хук pre-commit:
#!/bin/sh git diff --cached --name-only -z --diff-filter=ACM | xargs -r0 .filters/myfilter
Создайте ".filters / myfilter" со следующим содержимым:
#!/bin/sh TMPFILE="/tmp/${0##*/}.$$" for f in "$@"; do ### the only difference from above recipe case "$f" in *.groovy) : fall through ;; *) continue esac cp "$f" "$TMPFILE" || continue awk -v new="/%% $(date +%m_%d_%Y) %%\\" \ 'NR==1{sub("^/%% .* %%\\\\$",new)}1' \ < "$TMPFILE" > "$f" git add -u -- "$f" done
Вышеприведенная реализация может обрабатывать любое имя файла, которое вы кидаете.
Может быть, вам нужен атрибут git с операцией smudge/clean:
Связанный: используйте git smudge/clean для замены содержимого файла