Sometimes from muscle memory, I run git commit -a
when I have some files or parts of files carefully staged and ready to commit, causing me to lose my careful staging action.
Is there a way to make git commit -a
warn if there is anything (file or patch) currently staged?
(Clearly I should just use -a
less to alleviate my problem, but my question stands.)
Unfortunately, Git doesn't allow aliases to override existing commands, otherwise you could easily add this functionality via an alias.
But, you can get part way there. It would require retraining yourself to type something instead of git commit
—perhaps git c
.
Here's how you could do it:
Put the following shell code in a script file somewhere (e.g., /path/to/commit-wrapper
)
#!/bin/sh
# avoid echo because some implementations treat backslashes specially
log() { printf '%s\n' "$*"; }
error() { log "ERROR: $*" >&2; }
fatal() { error "$*"; exit 1; }
check_for_staged() {
git diff-index --cached --quiet HEAD || {
# simply exit with an error if run non-interactively
tty >/dev/null \
|| fatal "don't use '$1' when you have staged changes"
# this script is being run interactively; prompt the user to
# continue
error "'$1' option used when there are staged changes"
while true; do
printf 'Continue anyway? [y/N] ' >&2
read answer || { printf '\n'; answer=N; }
[ -n "${answer}" ] || answer=N
case ${answer} in
y|Y) break;;
n|N) echo "aborted" >&2; exit 1;;
*) error "Please answer 'y' or 'n'.";;
esac
done
}
}
# TODO: use 'git rev-parse --parseopt' to reliably detect '-a' (e.g.,
# to properly handle invocations such as 'git commit -sa')
for i in "$@"; do
case ${i} in
--) break;;
-a|--all) check_for_staged "${i}"; break;;
esac
done
git commit "$@"
chmod a+x /path/to/commit-wrapper
git config --global alias.c '!/path/to/commit-wrapper'
git c
instead of git commit
.If Git is ever changed to allow aliases for existing commands, change the last line to say "$(git --exec-path)"/git-commit "$@"
to avoid an infinite loop.
Add a pre-commit
hooke in your repo, with something like below:
#!/bin/sh
echo "Make sure you haven't used the -a flag or verify git diff --cached returns nothing"
echo "Run commit again with --no-verify if ok to proceed"
exit 1
That should help you overcome your "muscle memory".
Unfortunately, pre-commit hook cannot be powerful enough to do more checks ( like if you had supplied the -a
argument to the commit. ) Also, when you do -a
, the pre-commit hook will see as though all the files were staged, eventhough after the execution, you will see them as unstaged. So you cannot differentiate between what you had staged previously and the files staged because of the -a
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With