【问题标题】:Calling git in pre-commit hook在预提交挂钩中调用 git
【发布时间】:2020-01-10 17:33:19
【问题描述】:

运行我的 git pre-commit 挂钩时,我得到了奇怪的结果,例如当我这样做时 git diff --name-only 在终端它似乎给出不同的结果 当它在 .git/hooks/pre-commit 中执行时

所以我的问题是:

  1. 我可以在 git hooks 中调用 git 吗?
  2. 如果 1. 没问题:如果我执行 git commit,什么时候调用 pre-commit 钩子 -am“bla”?特别是 git 是否先进行暂存,然后调用 pre-commit 钩子?

我问这个是因为我尝试了 2 到 3 次: 我修改了一个文件,我手动运行脚本,它会打印出来

#! /bin/sh -xv
files=$(git diff --name-only)
+ git diff --name-only
+ files=path/to/file.h
echo $files
+ echo path/to/file.h
path/to/file.h
...

当我执行 git commit -am"eh" 然后输出不同

#! /bin/sh -xv
files=$(git diff --name-only)
+ git diff --name-only
+ files=
echo $files
+ echo

【问题讨论】:

    标签: git pre-commit-hook


    【解决方案1】:
    1. 我可以在 git hooks 中调用 git 吗?

    是的,但您必须谨慎行事,因为环境中设置了许多东西,并且您正在处理一些正在完成的事情:

    • GIT_DIR 设置为 Git 目录的路径。
    • GIT_WORKTREE 可以设置为工作树的路径(来自git --work-tree)。
    • 也可以从命令行设置其他 Git 变量,例如 GIT_NO_REPLACE_OBJECTS。

    (如果您继续使用当前存储库,则应保留这些设置,但如果您使用的是不同存储库,请将它们清除。)

    1. 如果 1. 没问题:如果我执行 git commit -am"bla",什么时候会调用预提交挂钩?特别是 git 是否先进行暂存,然后调用 pre-commit 钩子?

    这很复杂。

    git commit 在内部使用了三种“模式”。 (对此没有任何承诺,但这就是多年来一直实施的方式,所以这三种模式的东西看起来相当稳定。)模式是:

    • git commit 不带 -a、--include、--only 和/或任何命令行指定的文件名。这是默认或正常模式。底层实现细节没有显示出来。

    • git commit 带有 -a 或带有命令行指定的文件名。这分为两个子模式:

      • --include 这样的提交,或者
      • --only 这样的提交。


      至此,底层实现就显露出来了。

    这里的底层实现细节涉及 Git 调用的东西,不同的是,index、暂存区和(现在很少)缓存 em>,它通常实现为一个名为 $GIT_DIR/index 的文件(其中 $GIT_DIR 是关于第 1 点的注释中的环境变量)。通常,只有以下之一: 索引。它包含您打算提交的内容。1 当您运行git commit 时,Git 会将索引中的任何内容打包作为下一次提交。

    但是,在操作 git commit 的过程中,最多可能有三个 索引文件。对于普通的git commit,只有一个索引,您的预提交钩子可以使用它,甚至可以更新它。 (我建议不要更新它,原因我们稍后会看到。)

    但是,如果您执行git commit -a 或git commit --include file.ext,则现在有两个 索引文件。有准备提交的内容——常规索引——和一个额外索引,它是原始索引加上在file.ext上执行git add的结果或所有文件(相当于git add -u)。所以现在有两个索引文件。

    在这种模式下,Git 将常规索引文件作为常规索引文件。该文件像往常一样位于$GIT_DIR/index。 second 索引文件以及额外添加的内容位于$GIT_DIR/index.lock 中,并且环境变量GIT_INDEX_FILE 设置为保存该路径。如果提交失败,Git 将删除index.lock 文件,一切都好像你根本没有运行git commit。如果提交成功,Git 会将index.lock 重命名为index,同时释放锁并更新(标准、常规)索引。

    最后,还有 third 模式,例如,当您运行 git commit --only file.ext 时会得到该模式。这里,现在有三个索引文件:

    • $GIT_DIR/index:标准索引,保存它通常做的事情。
    • $GIT_DIR/index.lock:file.ext 已成为 git add-ed 的标准索引的副本。
    • $GIT_DIR/index<em>suffix</em>:file.ext 已成为 git add-ed 的 HEAD 提交2 的副本。

    环境变量GIT_INDEX_PATH 指向第三个索引。如果提交成功,Git 会将index.lock 文件重命名为index,使其成为 索引。如果提交失败,Git 将删除 index.lock 文件,以便索引恢复到您开始之前的状态。 (无论哪种情况,Git 都会删除第三个索引,它现在已经达到了它的目的。)

    请注意,通过预提交挂钩,您可以检测 git commit 是标准提交(GIT_INDEX_FILE 未设置或设置为 $GIT_DIR/index)还是两种特殊模式之一。在标准模式下,如果要更新 索引,可以照常进行。在这两种特殊模式下,您可以使用git add 修改GIT_INDEX_FILE 命名的文件,这将修改提交的内容;如果您在--include 样式提交中,这也会修改将成为成功标准索引的内容。但如果您处于--only 模式,修改提议的提交不会影响标准index,也不index.lock 将成为标准索引。

    考虑一个具体的例子,假设用户做了:

    git add file1 file2
    

    以便标准索引与HEAD 匹配,file1 和 file2 除外。然后用户运行:

    git commit --only file3
    

    因此提议的提交是HEAD 的副本,添加了file3,并且,如果此提交成功,Git 将替换标准索引为其中file1,@ 987654381@ 和 file3 都已添加(但由于 file3 将匹配新的 HEAD 提交,因此只有文件 1 和 2 将在新索引中修改)。

    现在假设您的提交挂钩运行git add file4 并且整个过程成功(新提交成功)。 git add 步骤会将file4 的工作树版本复制到临时索引中,以便提交将同时更新file3 和 file4。然后 Git 将重命名 index.lock 文件,以便 file3 将匹配新的 HEAD 提交。但是index.lock 中的file4 从未更新,因此它不会 匹配HEAD 提交。在用户看来,file4 以某种方式被还原了! git status 将显示对它的待定更改,暂存于提交,git diff --cached 将显示HEAD 和索引之间的区别在于file4 已更改回以匹配@987654402 中的file4 @。

    您可以对此模式进行预提交挂钩测试,并在此模式下拒绝git add 文件,以避免出现问题。 (或者,您甚至可以偷偷地将file4 添加到index.lock,使用第二个git add 命令!)但通常最好让您的钩子拒绝提交,并建议用户执行任何git adds他们自己,这样您就不必首先了解所有这些实现秘密关于 git commit。


    1索引还包含一些额外的信息:缓存数据关于工作树。这就是为什么它有时被称为缓存。我在这里描述的这些额外副本是通过复制原始索引制作的,因此额外副本也具有相同的缓存数据,除非它们通过git add 更新。

    2未指定 Git 是否通过内部等效项制作此副本:

    TMP=$GIT_DIR/index<digits>
    cp $GIT_DIR/index $TMP
    GIT_INDEX_FILE=$TMP git reset
    GIT_INDEX_FILE=$TMP git add file3
    

    或其他方式(例如,git read-tree 的内部等效项),但由于此特定副本总是在进程结束时被删除,所以没关系:工作树的任何缓存信息都变为无关紧要。

    【讨论】:

      【解决方案2】:

      是的,更改似乎已被缓存。使用git diff --cached --name-only 列出即将提交的文件。

      【讨论】:

        猜你喜欢
        • 2021-09-10
        • 2010-12-22
        • 1970-01-01
        • 1970-01-01
        • 2019-12-25
        • 1970-01-01
        • 1970-01-01
        • 2014-01-03
        • 2015-09-10
        相关资源
        最近更新 更多