Временно изменить рабочую директорию и промежуточную область в git pre-commit hook

Я использую подход, похожий на этот, чтобы использовать привязку pre-commit для отслеживания изменений в моей схеме базы данных (а также несколько метаданных - ish).

Мне нравится пытаться сохранить мои коммиты в чистоте, поэтому я хочу, чтобы их громко предупреждали в сообщении о фиксации, когда были произведены автоматические изменения. Вот мои крюки pre-commit и pre-commit-msg:

.git/крючки/предварительной фиксации

#!/bin/sh

# Save user changes to db/ (if any)
git diff --quiet db/
user_dirty=$?
[[ $user_dirty > 0 ]] && git stash save --keep-index

# Regenerate db/ automatically
db/save_schema_and_meta_tables.sh

# Were any automatic changes made? If so, commit them but warn about it
git diff --quiet db/
auto_dirty=$?
if [[ $auto_dirty > 0 ]]; then
    git add db/
    echo "WARNING: automatic changes to db/ added to commit" | tee .git/COMMIT_WARNING
fi

[[ $user_dirty > 0 ]] && git stash pop
exit 0

.git/крючки/подготовить фиксации-MSG

#!/bin/sh
msgf=$1
wf=.git/COMMIT_WARNING
if [ -e $wf ]; then
    msg=$(<$msgf)
    ( cat $wf; echo "$msg" ) > $msgf
    rm -f $wf
fi

Вот как он себя ведет:

  • Если я внес изменения в db/, но еще не поставил их, они сохраняются в рабочем дереве, не нарушая фиксацию, благодаря stash save --keep-index и stash pop. Хорошо!
  • Однако, если у меня поставлено изменяется на db/, и они перезаписываются автоматическим фиксацией, то после фиксации пользовательские изменения исчезают. Плохо!

Вот что я мог бы как: если есть внесенные пользователем изменения в db/, и они точно не соответствуют автоматическим изменениям, то все это должно быть прервано. У меня много проблем с выяснением того, как это реализовать: как я могу сохранить поэтапные изменения, сделанные пользователем, а затем посмотреть, не совпадают ли автоматические изменения?

Ответ 1

Это не очень, и это медленно, но с некоторыми предложениями @torek я придумал следующее.

  • Убедитесь, что пользователь выполнил изменения в каталоге db/ (user_staged=1 если это так)
  • Пользователь смены пользовательских настроек, сохраняя область промежуточного уровня
  • Автоматическое создание содержимого каталога db/
  • Сравните поэтапную версию каталога db/ с автоматически сгенерированной версией (auto_changes=1, если они отличаются)
  • Восстановить пользовательский рабочий каталог (modulo обнаружена ошибка torek), сохраняя при этом копию автоматически сгенерированной версии db/
  • Решение:
    • Если пользовательский и автоматически сгенерированный db/ соответствует, все хорошо
    • Если пользовательский и автоматически сгенерированный db/ не совпадают, прервать
    • Если пользователь не выполнил никаких изменений в db/, но есть автоматически сгенерированные изменения, выполните их этап и продолжите, но предупредить о них в сообщении фиксации

Код крюка pre-commit:

# Has user staged changes to db/?
git diff --quiet --staged db/
user_staged=$?

# Stash any user changes in the working tree
old_stash=$(git rev-parse -q --verify refs/stash)
git stash save -q --keep-index
new_stash=$(git rev-parse -q --verify refs/stash)
[[ "$old_stash" != "$new_stash" ]] && stashed=1 || stashed=0

# Automatically regenerate db/
db/save_schema_and_meta_tables.sh
cp -a db db_AUTO

# Compare automatically-generated changes to what the user had already staged
git diff --quiet db/
auto_changes=$?

# Restore user state
[[ $stashed ]] && git reset --hard -q && git stash apply --index -q && git stash drop -q

# abort: if user had staged changes to db/, and automatic changes would overwrite them
# add but warn: automatic changes added, but no user changes to db/
# silent: no user-staged changes, no automatic changes
if (( $auto_changes > 0 )); then
    if (( $user_staged > 0 )); then
        echo "ERROR: automatic changes to db/ conflict with staged changes"
        rm -rf db_AUTO
        exit 1
    else
        rm -rf db/
        mv db_AUTO db
        git add db/
        echo "WARNING: automatic changes to db/ added to commit" | tee .git/COMMIT_WARNING
        exit 0
    fi
else
    rm -rf db_AUTO
fi