"git rebase --continue" 适用哪些 Git 钩子?

19

我正在为我的组织构建一组git hook脚本,其中一个我想使用的脚本(仅适用于自己的多个项目)是检查在执行git rebase --continue时,我的代码中是否有任何冲突标记(<<<<<=====>>>>>)。

我已经为我的pre-commit编写了这样的脚本,但哪种脚本适用于rebase --continue?


pre-rebase 钩子触发太早了? - Ludder
@Ludder:是的,它在变基开始之前运行。 - sleske
我不明白为什么pre-commit钩子没有被调用?毕竟,重新设置基线(尤其是在合并解决之后!)是提交新代码吧? - Brondahl
https://git-scm.com/docs/git-rebase#_hooks - Devin Rhode
3个回答

14
该手册githooks列出了可用的git钩子列表。没有钩子适用于git rebase --continue(该列表是详尽的)。
有一个名为“post-rewrite”的钩子,它“由重写提交的命令调用”,如git rebase。然而,它只会在命令完成后运行(即当rebase完成时)。它将为您提供重写创建的新提交列表,因此您可以检查提交是否引入任何冲突标记并进行投诉,但此时中止rebase为时已晚。当然,您仍然可以使用reflog还原rebase。
总的来说,编写一些git rebase的包装器或单独的检查工具可能更容易。无论如何,在调用git rebase --continue之前,您应该(在我看来)始终审查所做的更改。如果您坚持这样做,就不会意外地将冲突标记包含在内。

1
这是使用该钩子的一个具体示例:https://dev59.com/v3A85IYBdhLWcg3wCe5Z#53516609 - Ciro Santilli OurBigBook.com

3
TL;DR: git rebase --exec --reschedule-failed-exec "run-your-tests" <sha>命令将在<sha>提交之后的每次提交后运行测试:https://git-scm.com/docs/git-rebase#Documentation/git-rebase.txt---execltcmdgt =======
如果能让git rebase --continue自动运行所有普通的提交钩子就好了。
没有这个功能,但是可以使用“post-rewrite”和“pre-push”,以验证刚刚变基的代码的质量并在推送前检查它。
但是如何验证每个中间提交是否通过测试/构建工作正常/没有语法错误?
Git的创建者/维护者有一个答案:
git rebase --exec "run-your-tests" <base-commit-ish>

这比“围绕git rebase的包装器”或“单独的检查工具”更好,正如@sleske所提到的,这是一个本地git功能! 当提交存在问题时,您将看到:
... output from failed tests ...
warning: execution failed: run-your-tests
You can fix the problem, and then run

  git rebase --continue

这是一些“伪”代码,您可以在重写之后或推送之前运行它:
rm -rf node_modules
git rebase
  --exec "no-conflict-markers"
  --exec "npm install"
  --exec "ensure-clean-git-status"
  --exec "npm run lint"
  --exec "npm run test"
  --exec "npm run type-check"
 master

若想同时运行npm/node的linttesttype-check,请参考run-p

当你自己执行交互式变基时,你可能需要执行以下操作:

git rebase -i --exec "run-your-tests" --reschedule-failed-exec <sha>

你可以给这个起一个更短的别名:
git quality-rebase <sha>

使用--rescheduled-failed-exec命令会执行其所描述的操作。如果您未通过质量检查,请修复问题,然后运行git rebase --continue,这将再次运行您的质量检查(这是显然所需的)。
感谢git worktree,您可以使质量检查变得更严格。 在等待质量检查完成时,您可以打开一个新终端,运行cd myapp; git worktree add ../myapp2 master; git checkout <whatever>,并在一个新的工作目录中继续编码,而不受重新执行质量检查状态的影响。
我认为,在您有良好的可工作代码时,最好将其备份到您的git远程存储库中,这也允许其他人发现它,并且您还可以使用其他webhook工具“广播”已发布的新分支。此外,如果您的质量检查需要一些时间,您肯定不想坐着看着它。因此,我建议最好将任何较重的检查用作pre-push hook。只需尝试git push,然后当并且重新执行质量检查完成时,它将被推送上去。您可以使用say命令告诉您它们是否失败:git push && say "successfully pushed changed" || say "quality checks failed" 这是我建议在过渡期间使用的具体命令,您需要为您的特定项目编辑--exec命令:
CURRENT_BRANCH=`git branch --show-current`
git checkout master
git pull # this step should probably be automated via post-checkout hook. Or maybe warning should be generated when you create branch off an old local master branch.
git checkout $CURRENT_BRANCH
git fetch origin master # ensure latest origin/master, even if checkout commands fail
git rebase -i --reapply-cherry-picks --empty=ask --reschedule-failed-exec --rerere-autoupdate --exec "yarn install && yarn test -u && yarn run-p --print-label lint type-check" origin/master

如果您有一个commit-msg钩子,它会向提交消息添加元数据(我有一个名为git-guilt-staged的npm包,它会将“建议的评审人:”添加到每个提交消息中),也许我们可以“重新编辑”所有提交并查看此钩子运行 - 不确定。 - Devin Rhode
我非常勤奋地分解更改,以便创建一个干净、易于跟踪的提交历史记录。因此,我喜欢将配置更改/git钩子/质量检查与实际应用程序源代码更改分开。这带来了一个困境:您是先使质量检查更严格,并使用“--no-verify”进行提交,这反映了您正在工作的时间顺序,并且更容易跟踪;还是反转提交,避免使用“--no-verify”? - Devin Rhode
我认为解决这个问题的方法是:使质量检查更加严格的提交应该在提交消息中有一个特殊的“标志”。也许它可以是 #no-verify 或 `NO-VERIFY: add new lint rule"。这样你就可以得到更容易跟踪的提交历史记录。 - Devin Rhode
如果我们能够允许一个提交包含失败的测试,只要下一个提交不包含失败的测试,那将是理想的。这样可以正确地展示历史记录。首先,你遇到了一个问题,然后你解决了它。这不仅适用于TDD。你可能会更改类型、升级某些内容、重写某些方法、新的lint规则、更严格的类型检查等等。 - Devin Rhode
今天有不同有趣的用法:vscode 的 on-save 格式化出了问题,为了保持专注,我只是将它们提交为 "vscode formatting is on the fritz"。后来,我在清理提交日志时想要修复糟糕格式错误的历史记录。请参见:https://dev59.com/LHMOtIcB2Jgan1znQQO4#71812873 - Devin Rhode

0

我发现了另一个技巧。这应该是一条评论,但是当发布答案时需要可用的格式。

如果您正在进行交互式变基并使用edit命令在变基期间编辑提交,则实际上必须使用git commit而不是git rebase --continue。这意味着将运行提交挂钩(pre-commit、commit-msg、post-commit等)。在其他重新基础的情况下,您可以选择显式使用git commit,然后使用git rebase --continue

在交互式变基期间,您可能会有一些纯粹是运行某些命令的提交。

pick 12fo233jj Run `yarn add eslint prettier --dev`
pick 2y98tafkk Setup eslint+prettier
pick 19047ed9a Run `yarn run lint:fix:all`

避免合并冲突的一个小技巧是,简单地放弃那些原始提交,并重新运行以下命令:
drop 12fo233jj Run `yarn add eslint prettier --dev`
# pardon the verbosity:
#   Stash $MSG, undo commit, toss yarn.lock changes, `yarn add`, commit.
exec MSG=$(git log -1 --format=%B HEAD); git reset --soft HEAD~ && git restore --staged yarn.lock && git restore yarn.lock && yarn add eslint prettier --dev && git add yarn.lock package.json && git commit -m "$MSG" --no-verify
pick 2y98tafkk Setup eslint+prettier
drop 19047ed9a Run `yarn run lint:fix:all`
exec MSG=$(git log -1 --format=%B HEAD); git reset --hard HEAD~ && yarn run lint:fix:all && git commit -am "$MSG" --no-verify

如果您想要重新编辑一个提交,您可以使用相同的方法,但在调用git commit时添加--reedit-message=

如果要压缩提交,您需要创建一个新的方法,在此处撤销两次,可能会以某种方式获取两个提交消息?如果您喜欢使用git gui,则rebase break命令可能很有用:

pick 2y98tafkk Setup eslint+prettier
pick 19047ed9a Setup new eslint rules+hooks plugin
pick 18047ed34 Setup new prettier config
break
# Use gui tool to undo last two commits, `git commit` as "Setup new eslint rules+prettier config"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接