当 git commit-msg 挂钩失败时,如何恢复提交消息?

How can I recover the commit message when the git commit-msg hook fails?

我正在使用 git 的钩子之一 commit-msg 来验证特定格式和内容的提交消息。

但是,每当提交消息未能通过挂钩时,我有时会丢失消息中的一段或更多文本。

我试过将其保存在某处,但我不确定如何在用户尝试修复失败的提交消息时将其恢复给用户,只显示最后一条正确的提交消息。

有没有其他人处理过这个问题?你是怎么解决的?

信息:我正在使用 python 脚本进行验证。

提交消息存储在 .git/COMMIT_EDITMSG 中。在 "failed" 次提交尝试后,您可以 运行:

git commit --edit --file=.git/COMMIT_EDITMSG

或更短,例如:

git commit -eF .git/COMMIT_EDITMSG

这将在您的 $EDITOR(或您在 Git 配置中设置的编辑器)中加载错误的提交消息,以便您可以尝试修复提交消息。您还可以为上述内容设置一个别名,使用:

git config --global alias.fix-commit 'commit --edit --file=.git/COMMIT_EDITMSG'

然后改用git fix-commit

背景

,当 运行 git commit,git 启动你的编辑器指向 $GIT_DIR/COMMIT_EDITMSG 文件。除非 commit-msg 钩子有问题 moves/deletes/damages文件,消息应该还在。

我想重复使用邮件不是默认行为,因为它可能 干扰 prepare-commit-msg 挂钩。理想情况下,会有一个切换 默认情况下可启用重用,以避免数据丢失。这 下一个最好的事情是 override a git sub-command with a git alias, 但不幸的是,目前这是不可能的,那就是 unlikely to change。所以我们只剩下为它创建一个自定义别名了。 我使用了类似于已接受答案中的别名:

git config alias.recommit \
'!git commit -F "$(git rev-parse --git-dir)/COMMIT_EDITMSG" --edit'

然后,当运行 git recommit时,被拒绝提交消息的内容应该 出现在编辑器中。

加法

请注意,对于存储库中的第一次提交,这两个别名都会失败,因为 COMMIT_EDITMSG 文件尚未创建。为了让它也能在 那样的话,它看起来有点复杂:

git config alias.recommit \
'!test -f "$(git rev-parse --git-dir)/COMMIT_EDITMSG" &&
git commit -F "$(git rev-parse --git-dir)/COMMIT_EDITMSG" --edit ||
git commit'

可以缩短为:

git config alias.recommit \
'!cm="$(git rev-parse --git-dir)/COMMIT_EDITMSG" &&
test -f "$cm" && git commit -F "$cm" --edit || git commit'

无论哪种方式,考虑到增加的安全性,对于交互式使用,您甚至可以 默认使用上述别名之一,而不是 git commit.

可以make a wrapper for git itself并转移电话 关于论点(即:关于子命令),尽管这需要确保 所有对 git 的后续调用都引用原始二进制文件,以免它们 导致无限递归:

git () {
    cm="$(git rev-parse --git-dir)/COMMIT_EDITMSG"

    case "" in
    commit)
        shift
        test -f "$cm" && command git commit -F "$cm" --edit "$@" ||
        command git commit "$@"
        ;;
    *)
        command git "$@";;
    esac
}

请注意,如果将以上内容添加到您的 rc 文件中(例如:~/.bashrc),则每 调用其中存在的 git 将引用包装器,除非您将它们放在前面 还有 command

新奇

最后,我刚刚了解到 使用不同的包装文件别名 name 是一个选项:

PATH="$HOME/bin:$PATH"
export PATH
alias git='my-git'

所以包装器(例如:~/bin/my-git)可以简单得多:

#!/bin/sh
cm="$(git rev-parse --git-dir)/COMMIT_EDITMSG"

case "" in
commit)
    shift
    test -f "$cm" && git commit -F "$cm" --edit "$@" ||
    git commit "$@"
    ;;
*)
    git "$@";;
esac

同时避免干扰,因为 别名在外部使用时不会扩展 脚本.