我可以让 git 重置 --hard 更安全或禁用它吗?



我已经养成了经常使用git reset --hard的坏习惯。

我现在发现有git reset --keep,如果我真的需要删除某些东西,我甚至可以git stash && git stash drop做。

所以我想要么禁用硬重置,要么让他们在不可恢复地删除未提交的更改之前询问,或者至少创建一个备份。这可以在不将git包装在 shell 函数中的情况下完成吗?

git

本质上并不支持您的要求。

您可以编写一个名为git的脚本或 Bash 函数,并将其放在PATH中的git之前。 脚本或函数将只检查"禁止的命令",否则运行常规git程序(例如/usr/bin/git)。

Git 因在执行潜在危险操作时不警告用户而臭名昭著。无论如何,对于什么构成危险,意见可能会有所不同。基本上,当你在命令行上使用 Git 时,你说你是一个高级用户,你知道你在做什么。没有办法让 Git 滥用你的这个概念。

相反,您可以使用GUI,例如Sourcetree。它知道reset --hard是潜在的危险,并发出警报,迫使你停下来认真思考你正在做的事情。

这个问题询问是否有办法做到这一点,并以添加"有没有办法在没有 shell 脚本的情况下做到这一点"结束。 我认为这意味着 OP 想要一种方法,如果可能的话,最好没有包装器。 由于没有包装器是不可能的,以下是我所做的,以添加一些额外的检查来使用git。 它涉及编写一个包装器脚本,我将其别名为在我的 shell 启动文件中 git。 如果我做了一些我试图不再做的事情,该脚本会进行检查并退出一条消息,否则它会调用command git "$@"

如果存储库存在未提交(暂存或未暂存)更改,则以下脚本禁用"git reset --hard"。

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 "$@"

关于它如何工作的一些说明:

  • has_arg检查其第一个参数是否存在于以下参数列表中,以便has_arg --hard "$@"检查传递给脚本的参数是否包含--hard
  • repo_is_clean:如果没有未暂存的更改,则git diff --no-exit-diff --quiet以 0 存在,而具有--cached的对暂存更改执行相同的操作。 因此,如果函数失败(返回非零),则存在一些未提交的更改。
  • while 循环来自 git-completion.bash,我找到了它用来确定 git 命令是什么的代码,并剥离了本脚本不必要的内容。
  • 检查之一:如果命令已重置且存在--hard并且存储库具有未提交的更改,请打印消息并退出。
  • 如果我们到达脚本的末尾,委托给实际的git命令转发所有参数。

要使用它,请使此脚本可执行,并在 shell 启动文件中为其创建别名

alias git=<your-script>

打破习惯

因为这个问题提到了打破习惯,这里有一些更"强烈"的东西,我做了一些更"强烈"的事情来打破一个不同的习惯。

出于下面解释的原因,我想打破做git commit -m的习惯,并通过执行git commit来使用编辑器(没有-m):

if [[ "${git_command}" == commit ]] && has_arg -m "$@"; then
echo "PHIL: Don't use -m for commits"
exit 1
fi

有一段时间,我仍然总是做git commit -m "message",然后得到消息,然后在编辑器中做。 我希望改变这一点,所以我通过将简单的echo替换为以下内容来使其更加痛苦:

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

SIGINT上的trap会导致当用户按 shell 中的Ctrl-C以尝试摆脱 5 秒的惩罚时运行echo -n ...

请注意,只要您编写格式正确的提交消息,使用git commit -m就没有错。 但是有些人写了一个超长线提交消息,我希望能够鼓励他们始终使用编辑器,为此我必须自己做。

现在我喜欢一直使用编辑器还有其他原因,但这与问题无关,我的"惩罚"系统几乎不是。

git 重置的替代方案 --hard

虽然git reset --hard可以用来移动到分支指向的位置,但事实上,这是你的一种习惯,你git stash && git stash drop提到,这让我相信你用它来摆脱不需要的未提交更改,并有可能意识到为时已晚,你摆脱了一些你想要保留的更改。

在这种情况下,git checkout -p命令很有用。 这就像git add -p一样,它以交互方式向您显示大量更改,并要求您做出决定。 你按"y"丢弃大块头

最新更新