function has_arg(){
local arg=$1; shift
for a in "$@" ; do
if [[ "${a}" == "${arg}" ]] ; then
return 0
fi
done
return 1
}
function repo_is_clean(){
git diff --no-ext-diff --quiet 2>/dev/null \
&& git diff --no-ext-diff --cached --quiet 2>/dev/null
}
# Copied straight from git-completion.bash to determine the git command
# with minor adaptations (using ${!c} to get the c-th argument instead
# of ${COMP_WORDS[c]} and some stuff removed).
declare i c=1 git_command
while [ $c -le ${#} ]; do
i=${!c}
case "$i" in
--git-dir=*) ;;
--git-dir) ((c++)) ;;
--bare) ;;
--help) git_command="help"; break ;;
-c|--work-tree|--namespace) ((c++)) ;;
-C) ((c++)) ;;
-*) ;;
*) git_command="$i"; break ;;
esac
((c++))
done
if [[ ${git_command} == reset ]] && has_arg --hard "$@" && ! repo_is_clean ; then
echo "PHIL: You have uncommitted changes, use stash to get rid of them"
echo " and git stash drop later which will allow you an extra"
echo " opportunity to realize if you made a mistake"
exit 1
fi
command git "$@"
if [[ "${git_command}" == commit ]] && has_arg -m "$@"; then
trap 'n=0; echo "sorry, you gotta wait! setting counter back to 0"' SIGINT
echo "To help break the habit of using git commit -m, please endure"
echo "uh, I mean 'enjoy' this 5 second uninterruptible sleep"
for((n=1;n<=5;n++)); do
sleep 1
printf "\r${n}"
done
echo ""
exit 1
fi
3条答案
按热度按时间uurv41yg1#
git
本质上不支持您所要求的内容。您可以编写一个名为
git
的脚本或Bash函数,并将其放在PATH
中的git
之前。脚本或函数将只检查“禁止的命令”,否则将运行常规的git
程序(例如/usr/bin/git
)。rxztt3cl2#
Git因在执行有潜在危险的操作时不警告用户而臭名昭著。在任何情况下,对什么构成危险的看法都是不同的。基本上,当你在命令行中使用Git时,你就是在说你是一个高级用户,你知道你在做什么。没有办法让Git消除你对这个概念的误解。
相反,您可以使用GUI,例如Sourcetree。它知道
reset --hard
有潜在的危险,并发出警告,迫使你停下来仔细想想你在做什么。fykwrbwg3#
这个问题询问是否有一种方法可以做到这一点,并以添加“是否有一种方法可以在没有shell脚本的情况下做到这一点”结束。我认为这意味着OP希望有一种方法来完成它,如果可能的话,最好没有 Package 器。由于没有 Package 器是不可能的,所以我在使用git时添加了一些额外的检查。它涉及到编写一个 Package 器脚本,我在shell启动文件中将其别名为git。如果我做了一些我不想再做的事情,脚本会进行检查并退出,否则它会调用
command git "$@"
。下面的脚本在仓库中有未提交(staged或unstaged)的更改时禁用“git reset --hard”。
关于它如何工作的一些说明:
has_arg
检查它的第一个参数是否出现在后面的参数列表中,因此has_arg --hard "$@"
检查传递给脚本的参数是否包含--hard
。repo_is_clean
:如果没有未暂存的更改,则git diff --no-exit-diff --quiet
以0存在,而--cached
对暂存的更改也是如此。因此,如果函数失败(返回非零值),则存在一些未提交的更改。--hard
存在,并且存储库具有未提交的更改,则打印消息并退出。git
命令转发所有参数。要使用它,请使此脚本可执行,并在shell启动文件中为其创建别名
打破习惯
因为这个问题提到了打破习惯,这里有一些更“激烈”的事情,我做了打破一个不同的习惯。
出于下面解释的原因,我想打破执行
git commit -m
的习惯,转而使用编辑器执行git commit
(没有-m
):有一段时间,我仍然总是在做
git commit -m "message"
,然后得到消息,然后在编辑器中做。我想改变这一点,所以我把简单的echo
替换为下面的代码,让它变得更痛苦:SIGINT
上的trap
会导致当用户在shell中按下Ctrl-C
以试图摆脱5秒惩罚时运行echo -n ...
。请注意,只要您编写了格式正确的提交消息,使用
git commit -m
就没有什么问题。但是有些人会写一个超长的提交消息,我希望能够鼓励他们总是使用编辑器,为此我必须自己做。还有其他的原因,为什么我喜欢使用编辑器的所有时间,但这是不相关的问题,我的“惩罚”系统几乎是无论如何。
git reset的替代方法--hard
虽然
git reset --hard
可以用来移动分支所指向的位置,但这是你的习惯,而且你提到了git stash && git stash drop
,这让我相信你用它来摆脱不需要的未提交的更改,可能意识到你摆脱了一些你想保留的更改时已经太晚了。在这种情况下,
git checkout -p
命令很有用。它就像git add -p
一样,以交互方式向您显示大量更改,并要求您做出决定。你按y键就可以丢弃大块