modifying working directory and staging area temporarily in git pre-commit hook

时间秒杀一切 提交于 2020-01-02 08:10:29

问题


I'm using an an approach similar to this one to use a pre-commit hook to track changes to my database schema (as well as a few metadata-ish tables).

I like to try to keep my commits clean so I want to be loudly warned in the commit message when there are automatic changes being staged/committed. Here are my pre-commit and pre-commit-msg hooks:

.git/hooks/pre-commit

#!/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/hooks/prepare-commit-msg

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

Here's how it behaves:

  1. If I have made changes to db/ but haven't staged them yet, they are kept in the working tree without disturbing the commit, thanks to stash save --keep-index and stash pop. Good!
  2. However, if I have staged changes to db/ and they are overwritten by the automatic commit, then the user-intended changes are gone after the commit. Bad!

Here's what I would like to happen: if there are user-staged changes to db/ and they don't exactly match the automatic changes, then the whole thing should abort. I'm having a lot of trouble figuring out how to implement this: how can I save the staged changes made by the user, then see if the automatic changes don't match?


回答1:


It's not pretty, and it's slow, but with some of @torek's suggestions I came up with the following.

  1. Check if user has staged changes to the db/ directory (user_staged=1 if so)
  2. Stash user changes, while preserving the staging area
  3. Auto-generate the contents of the db/ directory
  4. Compare the staged version of the db/ directory to the auto-generated version (auto_changes=1 if they differ)
  5. Restore the user's working directory (modulo the bug torek identified), while preserving a copy of the auto-generated version of db/
  6. Decision:
    • If user-staged and auto-generated db/ matched, all is well
    • If user-staged and auto-generated db/ didn't match, abort
    • If user hadn't staged any changes to db/ but there are auto-generated changes, stage them and continue, but warn about them in the commit message

The pre-commit hook code:

# 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's 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


来源:https://stackoverflow.com/questions/25536034/modifying-working-directory-and-staging-area-temporarily-in-git-pre-commit-hook

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!