有时从肌肉记忆中,当我有一些文件或部分文件小心地上演并准备好提交时,我运行git commit -a
,导致我失去了我的谨慎的分期行动。
如果当前有任何内容(文件或补丁)上架,有没有办法让git commit -a
发出警告?
(显然我应该少用-a
来缓解我的问题,但我的问题仍然存在。)
答案 0 :(得分:2)
不幸的是,Git不允许别名覆盖现有命令,否则您可以通过别名轻松添加此功能。
但是,你可以在那里分道扬..它需要自己重新训练才能键入内容而不是git commit
- 也许git c
。
以下是你如何做到的:
将以下shell代码放在某个脚本文件中(例如/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
代替git commit
。如果Git被更改为允许现有命令的别名,请将最后一行更改为"$(git --exec-path)"/git-commit "$@"
以避免无限循环。
答案 1 :(得分:1)
在您的仓库中添加pre-commit
hooke,如下所示:
#!/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
这应该可以帮助你克服“肌肉记忆”。
不幸的是,预提交钩子不能足够强大以进行更多检查(例如,如果你已经为提交提供了-a
参数。)此外,当你执行-a
时,预提交钩子会看到所有文件都被暂存,但是在执行之后,你会看到它们是未分级的。因此,您无法区分之前暂停的内容和因-a
而暂存的文件。
答案 2 :(得分:1)
您可以使用自己喜欢的脚本语言来创建git2
命令,该命令将检查您是否使用参数commit -a
运行它。如果是这种情况,请运行/usr/bin/git status --porcelain
并检查索引是否有一些更改(瓷格式输出更容易解析,我的第一个猜测是通过grep '^[AMD]'
运行它并检查它是否现在,您可以打印警告并退出,或者运行/usr/bin/git
所有原始参数继续,就像没有git2一样(如果你没有使用commit运行,那也是你做的事情-a )。
以下是Perl中的一个示例(无论如何git都需要):
#!/usr/bin/env perl
use strict;
use warnings;
my %aliases = map { split(/\n/, $_, 2) }
split /\0/,
`git config -z --get-regexp alias\\.`;
my %commit_aliases = (( commit => 1 ),
map { s/alias\.//; $_ => 1 }
grep $aliases{$_} =~ /^commit\b/,
keys %aliases);
my ($command, @args) = @ARGV;
if ($commit_aliases{$command} && $args[0] =~ /^-a|^--all/) {
my @staged = grep /^M/, split /\0/, `git status -z`;
if (@staged) {
print "There are staged changes, are you sure you want to commit all? (y/N) ";
chomp(my $answer = <STDIN>);
if ($answer =~ /^y/i) {
run_command()
}
} else {
run_command()
}
} else {
run_command()
}
sub run_command {
system 'git', $command, @args;
exit $? >> 8;
}
然后,创建一个bash别名alias git2 git
,然后就可以了。
答案 3 :(得分:0)
我不知道任何自动方式,但手动完成就像在这个问题中一样: How do I show the changes which have been staged?
本质上是:
git diff --cached