在预提交钩子中调用git

问题描述 投票:0回答:2

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

所以我的问题是:

  1. 我可以在git hooks中调用git吗?
  2. 如果1没问题:如果我执行git commit,则确切地调用预提交钩子的时间-am“ bla”?特别是git是否先进行登台,然后再调用预提交钩子?

我问这个,因为我尝试了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
2个回答
2
投票
  1. 我可以在git hooks中调用git吗?

是的,但是您必须谨慎,因为环境中设置了很多东西,并且您正在做的事情正在完成中:

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

((如果继续使用当前存储库,则应保留这些设置;如果使用different存储库,请清除它们。)

  1. 如果1.可以:如果我执行git commit -am“ bla”,则何时调用预提交钩子?特别是git是否先进行登台,然后再调用预提交钩子?

这很复杂。

git commit内部使用三种“模式”。 (对此没有任何保证,但是这已经实现了很多年,因此这三种模式似乎很稳定。)这些模式是:

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

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

    • 具有--include的提交,或
    • 具有--only的提交。

    至此,基础实现得以显示。

这里的基本实现细节涉及Git调用的各种内容,分别是indexstaging area和(现在很少)cache,它们通常以文件形式实现名为$GIT_DIR/index(其中$GIT_DIR是关于点1的注释中的环境变量)。通常,只有以下一项:the索引。它保存您打算提交的内容。1运行git commit时,Git会将<< [in索引中的任何内容打包为下一次提交。

但是,在操作[[of git commit期间,最多可能有

三个个索引文件。对于普通的git commit,只有一个索引,您的预提交钩子可以使用它甚至可以更新它。 (我建议不要对其进行更新,出于稍后我们将要看到的原因。)

但是,如果您执行git commit -agit commit --include file.ext,则现在有two个索引文件。已经准备好要提交的内容-常规索引-

一个extra索引,它是原始索引加上在git add或所有文件上执行file.ext的结果(相当于git add -u)。因此,现在有two个索引文件。在此模式下,Git保留常规索引文件as常规索引文件。该文件照常位于$GIT_DIR/index中。具有附加内容的

second

索引文件位于$GIT_DIR/index.lock中,并且环境变量GIT_INDEX_FILE设置为保留该路径。如果提交失败,Git将删除index.lock文件,一切将好像您根本没有运行git commit。如果提交成功,Git会将index.lock重命名为index,释放锁并一次更新the(标准,常规)索引。最后,有third模式,例如,当您运行git commit --only file.ext时会得到。在这里,现在有

三个

索引文件:$GIT_DIR/index:标准索引,保留其通常的功能。
    [$GIT_DIR/index.lockfile.ext被编辑到的标准索引的副本。
  • [git add$GIT_DIR/indexsuffix -ed的HEAD提交
  • 2的副本。
  • 环境变量file.ext指向此第三索引。如果提交成功,Git会将git add文件重命名为GIT_INDEX_PATH,以使其成为the
  • 索引。如果提交失败,Git将删除index.lock文件,以便索引返回到开始之前的状态。 (无论哪种情况,Git都会删除已达到其目的的第三个索引。)

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

    dosn't

    会影响标准--includenor将[标准索引的--only考虑一个具体的例子,假设用户这样做:index使得标准索引与index.lock匹配,但git add file1 file2 HEAD除外。然后用户运行:

    file1

    以使建议的提交是添加了file2git commit --only file3
    的副本,

    ,如果此提交成功,Git将用其中HEADfile3file1全部添加(但由于file2将与新的file3提交匹配,因此在新索引中仅文件1和2将被[[modified
    )。
    现在假设您的提交挂钩运行file3,并且整个过程成功(成功完成了新提交)。 HEAD步骤会将git add file4的工作树版本复制到临时索引中,以便提交将同时更新git add 

    file4。然后,Git将重命名file3文件,以便file4与新的index.lock提交匹配。但是file3中的HEAD从未更新过,因此它[[不会与file4提交匹配。用户似乎会以某种方式恢复index.lockHEAD将显示对其的暂挂更改,已暂存以提交,而file4将显示git status与索引之间的差异是git diff --cached已更改回以匹配HEAD中的file4 ]。可以对此模式进行预提交挂钩测试,并在此模式下拒绝file4文件,以避免出现此问题。 (或者,您甚至可以使用第二个HEAD~1命令将git add偷偷添加到file4!)通常最好让钩子拒绝提交,并建议用户执行任何index.lock本身,这样您就不必一开始就知道所有这些实现秘密。

    1索引还包含一些额外的信息:缓存数据

    about

    工作树。这就是为什么有时将其称为缓存。我在这里描述的这些额外副本是通过复制原始索引制成的,因此这些额外副本也具有相同的缓存数据,除非它们是通过git add更新的。2未指定Git是否通过以下等效的内部副本进行复制:
    git add

    或其他某种方式(例如git commit的内部等效方式),但是由于总是在过程结束时才删除此特定副本,所以这无关紧要:工作树的任何缓存信息都变得无关紧要。

    是的,更改似乎已经被缓存。使用git add列出要提交的文件。

    © www.soinside.com 2019 - 2024. All rights reserved.