Тем, кто работает с Git, хорошо знаком способ отредактировать последний коммит командой git commit --amend
. Это удобно для мелких правок (изменить комментарий к коммиту, поправить строчку в коде и т.п.), потому что частенько хорошие мысли по поводу коммита приходят в голову уже после того, как этот коммит сделан.
Но с данным способом правки коммитов следует быть осторожным в случае, когда вы работаете с удалённым репозиторием и ещё более осторожным, когда вы работаете над исходным кодом в составе команды. Область безопасного использования опции --amend
заканчивается там, где начинается область использования команды git push
.
При коммите с опцией --amend
создаётся новый коммит (с новым хешем), который заменяет собой предыдущий, а тот предыдущий коммит удаляется из истории.
Если вы отредактируете свой уже опубликованный коммит (отправленный в удалённый репозиторий командой git push
), то в будущем создадите проблемы себе (когда попытаетесь опубликовать свой отредактированный коммит) и (самое важное!) создадите проблемы другим разработчикам, которые успели получить в свои локальные репозитории ваш старый коммит. В таком случае, и вам, и другим разработчикам обеспечена головная боль по чистке истории коммитов для исправления ситуации.
Большинство рекомендаций сводятся к совету: НЕ ПРАВЬТЕ ОПУБЛИКОВАННЫЕ КОММИТЫ!
И всё было бы отлично, если бы команда git commit --amend
не была так хороша и удобна! Ею хочется пользоваться, не оглядываясь на историю коммитов в удалённом репозитории. Поэтому у меня возникло желание автоматизировать такие проверки.
Для подобной автоматизации в системе Git отлично послужат перехватчики (hooks), а именно те, которые работают на стороне клиента. Хранятся они в служебном каталоге .git/hooks
и представляют собой файлы скриптов с предопределёнными именами, соответствующими их функциональному предназначению. Для моей задачи подойдёт перехватчик формирования сообщения для коммита prepare-commit-msg.
Суть идеи такова:
- Перехватываем команду
git commit --amend
; - Получаем значение хеша последнего коммита в локальной ветке;
- Получаем значение хеша последнего коммита в удалённой ветке;
- Сравниваем их, и если они равны, то выводим предупреждение и комментируем содержательную часть сообщения коммита — для того, чтобы при выходе из редактирования коммит отменялся из-за пустого сообщения (“Aborting commit due to empty commit message”).
Содежимое prepare-commit-msg
#!/bin/bash case "$2,$3" in commit,HEAD) # получаем short SHA-1 последнего коммита в локальной ветке sha1_local=$(git branch -vv | \ perl -lne 'print "$1" if /\*{1}\s+\S+\s+(\w+)\s+\[(\S+)\/(\S+).*\]\s+.*/') # получаем имя удалённой ветки (remote branch) remote_branch=$(git branch -vv | \ perl -lne 'print "$1/$2" if /\*{1}\s+\S+\s+\w+\s+\[(\S+)\/(\S+).*\]\s+.*/') # получаем short SHA-1 последнего коммита в удалённой ветке (remote branch) sha1_remote=$(git branch -rv | \ awk -v branch=$remote_branch '{ if ($1 == branch) print $2 }') if [ -n "$sha1_local" ] && [ -n "$sha1_remote" ] && [ "$sha1_local" = "$sha1_remote" ] then # Закомментируем сообщение коммита, чтобы выход из редактора приводил # к отмене коммита из-за отсутствия сообщения ci_comment=$(cat "$1" | grep -v '#' | perl -lne 'print "# $_"') ci_autogen=$(cat "$1" | grep '#') echo -e "$ci_comment" > "$1" # добавим текст предупреждения echo -e "# ВНИМАНИЕ! ВЫ ПЫТАЕТЕСЬ ОТРЕДАКТИРОВАТЬ УЖЕ ОПУБЛИКОВАННЫЙ КОММИТ!\n" >> "$1" echo -e "$ci_autogen" >> "$1" fi ;; *) ;; esac
Пример работы данного хука приведён ниже:
Как видно, у пользователя остаётся возможность при желании произвести коммит — для этого ему следует раскомментировать сообщение коммита. Если стоит задача более жёсткого пресечения попыток правки опубликованных коммитов, то в системе Git имеется перехватчик pre-commit, который запускается ещё до создания сообщения коммита.
ссылка на оригинал статьи http://habrahabr.ru/post/221819/
Добавить комментарий