【问题标题】:How to lint the commit, rather than the working directory?如何 lint 提交,而不是工作目录?
【发布时间】:2017-10-16 23:40:36
【问题描述】:

我有一个烦人的问题。我们将 linting 作为预提交挂钩运行。问题是它正在检查工作目录而不是实际提交。这样做有两个问题:

  1. 提交错误,但 linting 通过。
    如果您在修复 linting 问题后忘记暂存更改,就会发生这种情况。

  2. 提交很好,但 linting 失败。
    我经常有一些我不打算提交的调试代码。对这些更改进行 linting 确实没有意义,而且处理起来很烦人。

现在,问题是我如何编写一个更智能的预提交挂钩来检查实际提交而不是工作目录,最好不更改工作目录?

【问题讨论】:

  • 仅对暂存差异进行 Lint。
  • 听起来很奇怪。不要构建依赖于预提交钩子的进程。它们只是为了方便,可以很容易地禁用。我们使用不同的分支来代表我们产品的主要版本,并偶尔将错误修复发布到旧分支。因为我们使用的是最新版本的 eslint,所以在基于旧版本的分支上 linting 会失败。我们只是使用--no-verify 推送到服务器,但我们的构建过程更加健壮,并确保 linting(使用正确的版本)在合并到发布分支(通过 PR)之前通过
  • @JDB Jenkins 也会在提交合并到 master 之前运行 linting,因此该过程不依赖于 pre-commit 钩子。问题是 Jenkins 通常是超载的,它可能需要很长时间才能真正运行。预提交钩子很好,因为它可以提供更快的反馈并防止 Jenkins 上不必要的负载。
  • 是的,这就是为什么我们有钩子......以防止不必要的构建无论如何都会失败。您是否经常遇到这个问题,或者这更具理论性?在我看来,定期推送不反映您的工作目录的提交会导致一系列问题(想到单元测试)。

标签: git eslint lint pre-commit-hook


【解决方案1】:

这通常是相当困难的。

最直接的方法是将索引提取到临时目录中。这有一些明显的缺点:特别是,工作树中被忽略的文件不会被带到临时目录中。更糟糕的是,临时目录只有 this 存储库的文件:任何环境(例如子模块和/或超级项目)都不会被继承。

携带这些东西是可能的,但可能会消耗大量空间和/或时间。

这是一个简单的方法,可以将整个工作树(包括子模块)转移到一个临时目录,然后提取它上面的索引内容:

#! /bin/sh -e

tmpdir=$(mktemp -d)
trap "rm -rf $tmpdir" 0 1 2 3 15

# remainder assumes we are at top of work-tree, which is true in
# practice in git hooks, even if it is not documented anywhere.

# step 1: copy current tree to tmp dir
tar cf - . | (cd $tmpdir; tar xf -)

# step 2: extract current index to tmp dir
git --work-tree=$tmpdir checkout -- .

# step 3: run tests
... tests go here ...

对于想要修改文件的预提交挂钩(例如,使用 gofmtclang-format),这与一般想法相混淆,因为现在修改后的文件位于被删除的临时目录中。

【讨论】:

  • 我建议使用rsynccp -ap 而不是2 个tars。除此之外——完美的答案!
  • 谢谢。我还没有时间尝试这个。一旦我确认它有效,我就会接受你的回答。
猜你喜欢
  • 2022-01-12
  • 2011-11-21
  • 1970-01-01
  • 2015-06-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多