git 是否能够直接从源文件中获取提交消息?
Is git able to take the commit message directly from source file?
我正在寻找一种直接从提交的源文件中提取 git 提交信息的方法,而无需调用编辑器或类似工具。
我们的部门刚刚开始使用 git,由于遗留原因,所做的更改写在源文件的顶部:
#!/usr/local/bin/php
<?php
//
// @(#)insert_AX_serialno.php Arrow/ECS/EMEA/EA/nb 1.6 2018-03-14, 13:41:20 CET
//
// V 1.6: Now also check the Warehouse Code of an item before inserting the serial
// 2018-03-07 number. The Warehouse Code must not be equal to any of three values (see below).
//
// V 1.5: Now also check the Storage Dimensiaon of an item before inserting the serial
// 2018-03-07 number. The Storage Dimension must be equal to the constant "PHYSICAL".
//
// V 1.4: introduced an "Environment" variable which determines the target of the GetAXPO...
// 2018-02-21 functions (DEV, UAT or PROD). The variable can either be set explicitly or gets
// its value from the $_ENV array.
//
// V 1.3: stop processing if a line does not have the necessary Approval Status and
// 2018-02-20 PO Status
//
// V 1.2: Every insert requires now a RECID; either for the line or for the header.
// 2017-12-20 So we're selecting the RECID from the AX table if it's not provided as
现在我想直接从源代码中获取提交消息而不是再次输入,例如提交消息应该(在这个例子中)读作“V 1.6 - 2018-03-07
现在在插入序列号之前还要检查项目的仓库代码。仓库代码不得等于三个值中的任何一个(见下文)。"
我是 git 的新手,我能从 githooks 手册页中摘录的是我可以 准备 消息挂钩,但不替换它。
我的想法是,我可以使用 git commit <filename>
提交一个文件,然后 git 从源文件中获取相关消息 ...
问题是:
1) 钩子是否知道提交了哪个文件is/are?如果是,它是挂钩的参数还是环境变量?
2) 挂钩能否从源文件中准备一个消息文件并使 git 使用该文件而不是打开编辑器(当然不使用“-m”参数)?
all I could excerpt from the githooks man page was that I can prepare the message with a hook, but not replace it.
您可以准备 消息,包括完全替换。
1) Does a hook know which file(s) is/are being committed?
没有,但是你可以自己查询git。新提交的文件在索引中。使用命令 git diff --name-only
.
列出文件
2) Can a hook prepare a message file out of the source file
不,但是您可以为此编写自己的脚本。
and make git use that file instead of opening the editor (of course without using the "-m" parameter)?
没有。当 git
执行 prepare-commit-msg
挂钩时,下一步总是打开编辑器。
您可以使用显式选项 git commit --no-edit
来阻止打开编辑器。或者您可以在提交之前准备一个带有提交消息的文件,而不使用 prepare-commit-msg
挂钩,而是调用 git commit -F message.txt
.
我AFK的时候你也看看吧,不过我想看完这个,所以:
I'm new to git, and all I could excerpt from the githooks man page was that I can prepare the message with a hook, but not replace it.
事实并非如此——prepare-commit-msg 挂钩可以对消息文件做任何它喜欢的事情,包括完全替换它的内容。但是,您可能将通常只是 .git/COMMIT_EDITMSG
的 消息文件 与 git log
稍后显示的 而不是 .git/COMMIT_EDITMSG
.
要了解正在发生的事情(以及您需要做什么),您需要了解 Git 实际放入提交中的内容以及提交的工作方式。
首先,您所做的每个提交至少在逻辑上包含1一个完整、独立的快照,与其他所有提交分开。也就是说,通过从某个顶级目录开始并枚举其中的文件和目录,可以找到一些源代码 tree-of-files-and-directories。2 Git 提交所有文件, 包括 sub-directories.3
因此,如果您有一个 Git 存储库,您可以 运行:
git log
查看各种提交,然后 select 通过哈希 ID(例如用鼠标剪切和粘贴)和 运行:
git ls-tree -r <hash-id>
并且您会看到该特定提交包含每个文件,而不仅仅是与之前提交不同的文件。
尽管如此,git show <hash-id>
将向您显示该提交中 更改 的内容,就好像该提交只存储了 更改。提交不存储更改——它完整地存储所有内容——但 git show
显示 更改。 git show
实现这一点的方法是将提交与其前身提交进行比较。
提交的前身是提交的父。因此,提交是该父项的 child。对于每个文件,如果父提交中的文件与子提交中的文件匹配,则 git show
不说明该文件。如果文件不匹配,git show
会生成一组指令,用于更改父版本以使其成为子版本。 Git 在 git show
操作时产生此差异列表 *,这意味着您可以将各种标志传递给 git show
以更改 how 它计算并显示差异。
让我们看一下来自 Git 存储库的 Git 的实际原始提交对象,只是为了具体说明:
$ git rev-parse HEAD
e3a80781f5932f5fea12a49eb06f3ade4ed8945c
$ git cat-file -p e3a80781f5932f5fea12a49eb06f3ade4ed8945c | sed 's/@/ /'
tree 8e229ef2136e53a530ef74802f83d3b29a225439
parent 66023bbd78fe93c4704b3df754f9f7dc619ebaad
author Junio C Hamano <gitster pobox.com> 1519245935 -0800
committer Junio C Hamano <gitster pobox.com> 1519245935 -0800
Fourth batch for 2.17
这次提交的日志消息是最后一行。它位于 提交对象 中,哈希 ID 为 e3a80781f5932f5fea12a49eb06f3ade4ed8945c
。如果我 运行 git show
提交,Git 会告诉我 Documentation/RelNotes/2.17.0.txt
,但实际上,提交中的文件是 tree 8e229ef2136e53a530ef74802f83d3b29a225439
中的文件。如果我 运行 git ls-tree -r 8e229ef2136e53a530ef74802f83d3b29a225439
,它产生 3222 行输出:
$ git ls-tree -r 8e229ef2136e53a530ef74802f83d3b29a225439 | wc
3222 12900 259436
所以提交中有超过三千个文件。这些文件中有 3221 个与 父级 中的版本 100% 相同,即 66023bbd78fe93c4704b3df754f9f7dc619ebaad
,其中也有 3222 个文件。
无论如何,这里的关键位是:
- 提交是 Git 对象: 四种类型之一。完整集添加tree、blob(仅file-data:文件的name,如果有一个,而是在树对象中)和 annotated-tag。最后一个在这里无关紧要。
- 每个提交都有一些 parent 提交(通常只有一个)。
- 每次提交都会保存一棵树。该树列出了文件名及其 blob 哈希 ID。您可以试验
git ls-tree
(并阅读其文档)以了解它们的工作原理,但在这个级别上,细节无关紧要。
- 每个提交也有其关联但 user-supplied 元数据:作者和提交者(姓名、电子邮件和时间戳),以及从您的挂钩可以编辑的消息文件复制的日志消息。
因此,进行提交是一个过程,涉及构建树对象以用作快照,然后添加元数据以进行新的提交。新提交获得一个新的、唯一的哈希 ID。 (树 ID 不一定是唯一的:如果您进行的新提交与之前的提交具有 完全相同的 树,有时这样做是明智的,您最终 re-using老树。)
1最终,Git 确实开始做与其他版本控制系统相同的 delta-compression。但是这种情况发生在提交完成一个完整的独立快照之后很久。
2这是一个近似值。有关详细信息,请参阅下一节。
3Git 不保存任何目录:它只提交 文件。某个目录的存在是通过其中有一个文件来暗示的。如果需要,Git 稍后会 re-create 该目录,当检查提交并发现它必须这样做以便将文件放在那里时。
Git 如何进行提交,或者树对象中的内容
你特别提到你正在 运行ning git commit <em>filename</em>
:
My idea is that I can commit a file with git commit and git fetches the relevant message from the source file ...
Git 不会根据传递给 git commit
.
的参数构建树
相反,Git 有一个东西4,它称为 index,staging area 和 cache,这取决于调用者是谁以及他们希望强调索引的哪个方面。该索引是树对象的来源。
这意味着索引最初包含当前提交的所有文件。当你 运行 git 添加 <em>path</em>
时,Git 从 path
in the work-tree into the index, overwriting the one that was before.
要为提交创建树,Git 通常只调用 git write-tree
,它只是将索引内容打包为树。如果这棵树与某些现有树相同,则您 re-use 旧树;如果是新的,那就是新的;无论哪种方式,它都是 the 树,由索引中的任何内容组成。
一旦树被写入,Git 可以将它与当前提交的哈希 ID 结合起来以获得提交对象的 tree
和 parent
行。 Git 添加你的身份和当前时间作为作者和提交者,你的日志消息作为日志消息,并写出新的提交。最后,Git将新commit的ID写入当前b运行ch名称,这样新commit就是b运行ch的新提示。
当您使用 git 提交 <em>path</em>
时,这里的情况发生了变化。现在细节取决于你是 运行 git commit --only <em>path</em>
还是 git commit --include <em>path</em>
。 Git 仍然会从 一个 索引构建树。
4事实上,每个 work-tree 有一个索引。不过,默认情况下,只有一个 work-tree。但也有临时索引,我们稍后会看到。
git 提交 <em>path</em>
和临时索引
当你运行git提交<em>path</em>
时,Git必须构建一个临时索引,与普通索引分开。它从复制一些东西开始。它复制的内容取决于 --only
与 --include
.
对于--only
,Git通过读取当前提交的内容创建临时索引,即HEAD
提交,而不是通过读取普通索引的内容.使用--include
,Git通过读取普通索引的内容创建临时索引。
在临时索引中,Git 然后将给定 path
的任何条目替换为 work-tree。如果 path
不在临时索引中,Git 会将其添加为新文件。无论哪种方式,此路径现在都在临时索引中。
Git 现在使用临时索引而不是常规索引进行新提交。新提交像往常一样进入存储库,更新当前 b运行ch 名称,以便 b运行ch 的提示提交是新提交。新提交的父级像往常一样是旧的提示提交。但是既然已经提交了,Git就有点进退两难了。
索引—— 索引,正常的索引——通常应该与当前提交匹配,在“work-tree 工作”周期的开始.临时索引确实匹配新提交,因为新提交是使用临时索引进行的。但是临时索引几乎肯定在某些方面与 the 索引不同。因此,下一步行动再次取决于 --include
与 --only
:
如果您使用了--include
,临时索引从普通索引开始。临时索引与新提交匹配。所以临时索引变成了真正的索引。
此操作反映了正常提交:Git 使用名为 .git/index.lock
的临时锁定文件,以确保在执行所有提交工作时没有任何更改。对于不带路径参数的普通提交,临时锁文件和真正的索引除了某些时间戳外内容相同,所以Git只是将锁文件重命名为索引文件路径名,就搞定了。所以这处理了 no-path-arguments 案例和 --include
with path arguments 案例。
如果您使用了 --only
,Git 会用复制到临时索引中的条目更新普通索引,而保留普通索引的其余条目。这样,您专门提交的文件在当前(正常)索引中的形式与它们在当前提交中的形式相同。当前(正常)索引中的所有其他文件与您之前的一样 运行 git commit
:它们仍然匹配或不匹配 HEAD
提交(其 other 条目,对于未在命令行上给出的文件,都与父提交匹配),并且它们仍然匹配或不匹配 [=345= 中的文件], none 所有这些都改变了。
这对您的 prepare-commit-msg 挂钩意味着什么
与 Git 中的所有内容一样,您必须动态发现 发生了什么变化。
你根本不应该看work-tree。您可能已通过 git commit
调用(没有路径名参数),在这种情况下,使用的索引将是普通索引。您可能已通过 git commit --include
或 git commit --only
调用,在这种情况下,所使用的索引将是一个临时索引。
要找出索引(使用哪个索引)和 HEAD
提交之间的哪些文件不同,请使用 Git 提供的差异引擎之一。
一般来说,在您编写的任何代码中,除了您自己之外,您还应该使用 Git 调用的 管道命令。在这种情况下,所需的命令是 git diff-index
。另见
使用 git diff-index -r HEAD
会将当前提交与当前索引文件中的任何内容进行比较,由 $GIT_INDEX_FILE
和由于 [=62 而导致的任何替代 work-tree 情况确定=].方便的是,您无需在此进行任何调整。但是如果用户调用了 git commit --amend
,你真的应该与当前提交的父项进行比较。没有什么好的方法可以查明是否是这种情况。5
git diff-index
的输出默认为如下所示:
:100644 100644 f5debcd2b4f05c50d5e70efc95d10d95ca6372cd e736da45f71a37b46d5d46056b74070f0f3d488a M wt-status.c
您可以使用 --name-status
trim 关闭大部分 non-interesting 位,它会生成:
$ git diff-index -r --name-status HEAD
M wt-status.c
注意状态字母后面的分隔符是一个制表符,但是如果你写一个shell形式的循环:
git diff-index -r --name-status HEAD | while read status path; do ...
你可能总体上没问题。为了使其真正可靠,请使用有趣的路径名进行测试,包括白色 space 和 glob 字符。 bash 或其他智能语言的脚本可以使用 -z
标志来更理智地编码。有关详细信息,请参阅 the documentation。
请注意,文件可能会在此处 A
添加或 D
删除,而不仅仅是 M
修改。使用 git diff-index
将使您免于检查 R
enamed;使用 git diff
不会,因为那会读取用户的配置,这可能会设置 diff.renames
。您还应该准备好处理 T
ype-change,以防有人用文件替换符号 link,反之亦然。
一旦你有了一个修改过的文件列表,或者如果你愿意,可以与获取列表交错(但这更复杂——你需要保留和使用 :<mode>
的东西以获得强大的 line-by-line解码),你可以检查实际的差异。例如:
$ git diff-index --cached -p HEAD -- wt-status.c
diff --git a/wt-status.c b/wt-status.c
index f5debcd2b..e736da45f 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -1,3 +1,4 @@
+
#include "cache.h"
#include "wt-status.h"
#include "object.h"
说明我这里只是在文件顶部加了一个空行。 (你需要 --cached
让 Git 查看索引中的 blob 内容,而不是查看 work-tree 文件。你不需要 --cached
和初始 -r --name-status
变体,尽管包含它是无害的。这是 git diff-index
的一个烦人的特性。)
收集所有 git diff-index
输出并对其进行解析以发现您的日志消息文本后,您将准备好将新的提交日志消息写入日志消息文件。
5应该有吧。这是带有 Git 提交挂钩的主题:它们没有提供足够的信息。 Git 的更高版本可能会向挂钩添加更多参数,或设置特定的环境变量。例如,您可以在进程树中挖掘以尝试找到调用挂钩的 git commit
命令,然后查看它们的 /proc
条目或 ps
输出以找到它们的参数,但是这非常丑陋 error-prone,不太可能在 Windows.
上工作
我正在寻找一种直接从提交的源文件中提取 git 提交信息的方法,而无需调用编辑器或类似工具。
我们的部门刚刚开始使用 git,由于遗留原因,所做的更改写在源文件的顶部:
#!/usr/local/bin/php
<?php
//
// @(#)insert_AX_serialno.php Arrow/ECS/EMEA/EA/nb 1.6 2018-03-14, 13:41:20 CET
//
// V 1.6: Now also check the Warehouse Code of an item before inserting the serial
// 2018-03-07 number. The Warehouse Code must not be equal to any of three values (see below).
//
// V 1.5: Now also check the Storage Dimensiaon of an item before inserting the serial
// 2018-03-07 number. The Storage Dimension must be equal to the constant "PHYSICAL".
//
// V 1.4: introduced an "Environment" variable which determines the target of the GetAXPO...
// 2018-02-21 functions (DEV, UAT or PROD). The variable can either be set explicitly or gets
// its value from the $_ENV array.
//
// V 1.3: stop processing if a line does not have the necessary Approval Status and
// 2018-02-20 PO Status
//
// V 1.2: Every insert requires now a RECID; either for the line or for the header.
// 2017-12-20 So we're selecting the RECID from the AX table if it's not provided as
现在我想直接从源代码中获取提交消息而不是再次输入,例如提交消息应该(在这个例子中)读作“V 1.6 - 2018-03-07 现在在插入序列号之前还要检查项目的仓库代码。仓库代码不得等于三个值中的任何一个(见下文)。"
我是 git 的新手,我能从 githooks 手册页中摘录的是我可以 准备 消息挂钩,但不替换它。
我的想法是,我可以使用 git commit <filename>
提交一个文件,然后 git 从源文件中获取相关消息 ...
问题是:
1) 钩子是否知道提交了哪个文件is/are?如果是,它是挂钩的参数还是环境变量?
2) 挂钩能否从源文件中准备一个消息文件并使 git 使用该文件而不是打开编辑器(当然不使用“-m”参数)?
all I could excerpt from the githooks man page was that I can prepare the message with a hook, but not replace it.
您可以准备 消息,包括完全替换。
1) Does a hook know which file(s) is/are being committed?
没有,但是你可以自己查询git。新提交的文件在索引中。使用命令 git diff --name-only
.
2) Can a hook prepare a message file out of the source file
不,但是您可以为此编写自己的脚本。
and make git use that file instead of opening the editor (of course without using the "-m" parameter)?
没有。当 git
执行 prepare-commit-msg
挂钩时,下一步总是打开编辑器。
您可以使用显式选项 git commit --no-edit
来阻止打开编辑器。或者您可以在提交之前准备一个带有提交消息的文件,而不使用 prepare-commit-msg
挂钩,而是调用 git commit -F message.txt
.
I'm new to git, and all I could excerpt from the githooks man page was that I can prepare the message with a hook, but not replace it.
事实并非如此——prepare-commit-msg 挂钩可以对消息文件做任何它喜欢的事情,包括完全替换它的内容。但是,您可能将通常只是 .git/COMMIT_EDITMSG
的 消息文件 与 git log
稍后显示的 而不是 .git/COMMIT_EDITMSG
.
要了解正在发生的事情(以及您需要做什么),您需要了解 Git 实际放入提交中的内容以及提交的工作方式。
首先,您所做的每个提交至少在逻辑上包含1一个完整、独立的快照,与其他所有提交分开。也就是说,通过从某个顶级目录开始并枚举其中的文件和目录,可以找到一些源代码 tree-of-files-and-directories。2 Git 提交所有文件, 包括 sub-directories.3
因此,如果您有一个 Git 存储库,您可以 运行:
git log
查看各种提交,然后 select 通过哈希 ID(例如用鼠标剪切和粘贴)和 运行:
git ls-tree -r <hash-id>
并且您会看到该特定提交包含每个文件,而不仅仅是与之前提交不同的文件。
尽管如此,git show <hash-id>
将向您显示该提交中 更改 的内容,就好像该提交只存储了 更改。提交不存储更改——它完整地存储所有内容——但 git show
显示 更改。 git show
实现这一点的方法是将提交与其前身提交进行比较。
提交的前身是提交的父。因此,提交是该父项的 child。对于每个文件,如果父提交中的文件与子提交中的文件匹配,则 git show
不说明该文件。如果文件不匹配,git show
会生成一组指令,用于更改父版本以使其成为子版本。 Git 在 git show
操作时产生此差异列表 *,这意味着您可以将各种标志传递给 git show
以更改 how 它计算并显示差异。
让我们看一下来自 Git 存储库的 Git 的实际原始提交对象,只是为了具体说明:
$ git rev-parse HEAD
e3a80781f5932f5fea12a49eb06f3ade4ed8945c
$ git cat-file -p e3a80781f5932f5fea12a49eb06f3ade4ed8945c | sed 's/@/ /'
tree 8e229ef2136e53a530ef74802f83d3b29a225439
parent 66023bbd78fe93c4704b3df754f9f7dc619ebaad
author Junio C Hamano <gitster pobox.com> 1519245935 -0800
committer Junio C Hamano <gitster pobox.com> 1519245935 -0800
Fourth batch for 2.17
这次提交的日志消息是最后一行。它位于 提交对象 中,哈希 ID 为 e3a80781f5932f5fea12a49eb06f3ade4ed8945c
。如果我 运行 git show
提交,Git 会告诉我 Documentation/RelNotes/2.17.0.txt
,但实际上,提交中的文件是 tree 8e229ef2136e53a530ef74802f83d3b29a225439
中的文件。如果我 运行 git ls-tree -r 8e229ef2136e53a530ef74802f83d3b29a225439
,它产生 3222 行输出:
$ git ls-tree -r 8e229ef2136e53a530ef74802f83d3b29a225439 | wc
3222 12900 259436
所以提交中有超过三千个文件。这些文件中有 3221 个与 父级 中的版本 100% 相同,即 66023bbd78fe93c4704b3df754f9f7dc619ebaad
,其中也有 3222 个文件。
无论如何,这里的关键位是:
- 提交是 Git 对象: 四种类型之一。完整集添加tree、blob(仅file-data:文件的name,如果有一个,而是在树对象中)和 annotated-tag。最后一个在这里无关紧要。
- 每个提交都有一些 parent 提交(通常只有一个)。
- 每次提交都会保存一棵树。该树列出了文件名及其 blob 哈希 ID。您可以试验
git ls-tree
(并阅读其文档)以了解它们的工作原理,但在这个级别上,细节无关紧要。 - 每个提交也有其关联但 user-supplied 元数据:作者和提交者(姓名、电子邮件和时间戳),以及从您的挂钩可以编辑的消息文件复制的日志消息。
因此,进行提交是一个过程,涉及构建树对象以用作快照,然后添加元数据以进行新的提交。新提交获得一个新的、唯一的哈希 ID。 (树 ID 不一定是唯一的:如果您进行的新提交与之前的提交具有 完全相同的 树,有时这样做是明智的,您最终 re-using老树。)
1最终,Git 确实开始做与其他版本控制系统相同的 delta-compression。但是这种情况发生在提交完成一个完整的独立快照之后很久。
2这是一个近似值。有关详细信息,请参阅下一节。
3Git 不保存任何目录:它只提交 文件。某个目录的存在是通过其中有一个文件来暗示的。如果需要,Git 稍后会 re-create 该目录,当检查提交并发现它必须这样做以便将文件放在那里时。
Git 如何进行提交,或者树对象中的内容
你特别提到你正在 运行ning git commit <em>filename</em>
:
My idea is that I can commit a file with git commit and git fetches the relevant message from the source file ...
Git 不会根据传递给 git commit
.
相反,Git 有一个东西4,它称为 index,staging area 和 cache,这取决于调用者是谁以及他们希望强调索引的哪个方面。该索引是树对象的来源。
这意味着索引最初包含当前提交的所有文件。当你 运行 git 添加 <em>path</em>
时,Git 从 path
in the work-tree into the index, overwriting the one that was before.
要为提交创建树,Git 通常只调用 git write-tree
,它只是将索引内容打包为树。如果这棵树与某些现有树相同,则您 re-use 旧树;如果是新的,那就是新的;无论哪种方式,它都是 the 树,由索引中的任何内容组成。
一旦树被写入,Git 可以将它与当前提交的哈希 ID 结合起来以获得提交对象的 tree
和 parent
行。 Git 添加你的身份和当前时间作为作者和提交者,你的日志消息作为日志消息,并写出新的提交。最后,Git将新commit的ID写入当前b运行ch名称,这样新commit就是b运行ch的新提示。
当您使用 git 提交 <em>path</em>
时,这里的情况发生了变化。现在细节取决于你是 运行 git commit --only <em>path</em>
还是 git commit --include <em>path</em>
。 Git 仍然会从 一个 索引构建树。
4事实上,每个 work-tree 有一个索引。不过,默认情况下,只有一个 work-tree。但也有临时索引,我们稍后会看到。
git 提交 <em>path</em>
和临时索引
当你运行git提交<em>path</em>
时,Git必须构建一个临时索引,与普通索引分开。它从复制一些东西开始。它复制的内容取决于 --only
与 --include
.
对于--only
,Git通过读取当前提交的内容创建临时索引,即HEAD
提交,而不是通过读取普通索引的内容.使用--include
,Git通过读取普通索引的内容创建临时索引。
在临时索引中,Git 然后将给定 path
的任何条目替换为 work-tree。如果 path
不在临时索引中,Git 会将其添加为新文件。无论哪种方式,此路径现在都在临时索引中。
Git 现在使用临时索引而不是常规索引进行新提交。新提交像往常一样进入存储库,更新当前 b运行ch 名称,以便 b运行ch 的提示提交是新提交。新提交的父级像往常一样是旧的提示提交。但是既然已经提交了,Git就有点进退两难了。
索引—— 索引,正常的索引——通常应该与当前提交匹配,在“work-tree 工作”周期的开始.临时索引确实匹配新提交,因为新提交是使用临时索引进行的。但是临时索引几乎肯定在某些方面与 the 索引不同。因此,下一步行动再次取决于 --include
与 --only
:
如果您使用了
--include
,临时索引从普通索引开始。临时索引与新提交匹配。所以临时索引变成了真正的索引。此操作反映了正常提交:Git 使用名为
.git/index.lock
的临时锁定文件,以确保在执行所有提交工作时没有任何更改。对于不带路径参数的普通提交,临时锁文件和真正的索引除了某些时间戳外内容相同,所以Git只是将锁文件重命名为索引文件路径名,就搞定了。所以这处理了 no-path-arguments 案例和--include
with path arguments 案例。如果您使用了
--only
,Git 会用复制到临时索引中的条目更新普通索引,而保留普通索引的其余条目。这样,您专门提交的文件在当前(正常)索引中的形式与它们在当前提交中的形式相同。当前(正常)索引中的所有其他文件与您之前的一样 运行git commit
:它们仍然匹配或不匹配HEAD
提交(其 other 条目,对于未在命令行上给出的文件,都与父提交匹配),并且它们仍然匹配或不匹配 [=345= 中的文件], none 所有这些都改变了。
这对您的 prepare-commit-msg 挂钩意味着什么
与 Git 中的所有内容一样,您必须动态发现 发生了什么变化。
你根本不应该看work-tree。您可能已通过 git commit
调用(没有路径名参数),在这种情况下,使用的索引将是普通索引。您可能已通过 git commit --include
或 git commit --only
调用,在这种情况下,所使用的索引将是一个临时索引。
要找出索引(使用哪个索引)和 HEAD
提交之间的哪些文件不同,请使用 Git 提供的差异引擎之一。
一般来说,在您编写的任何代码中,除了您自己之外,您还应该使用 Git 调用的 管道命令。在这种情况下,所需的命令是 git diff-index
。另见
使用 git diff-index -r HEAD
会将当前提交与当前索引文件中的任何内容进行比较,由 $GIT_INDEX_FILE
和由于 [=62 而导致的任何替代 work-tree 情况确定=].方便的是,您无需在此进行任何调整。但是如果用户调用了 git commit --amend
,你真的应该与当前提交的父项进行比较。没有什么好的方法可以查明是否是这种情况。5
git diff-index
的输出默认为如下所示:
:100644 100644 f5debcd2b4f05c50d5e70efc95d10d95ca6372cd e736da45f71a37b46d5d46056b74070f0f3d488a M wt-status.c
您可以使用 --name-status
trim 关闭大部分 non-interesting 位,它会生成:
$ git diff-index -r --name-status HEAD
M wt-status.c
注意状态字母后面的分隔符是一个制表符,但是如果你写一个shell形式的循环:
git diff-index -r --name-status HEAD | while read status path; do ...
你可能总体上没问题。为了使其真正可靠,请使用有趣的路径名进行测试,包括白色 space 和 glob 字符。 bash 或其他智能语言的脚本可以使用 -z
标志来更理智地编码。有关详细信息,请参阅 the documentation。
请注意,文件可能会在此处 A
添加或 D
删除,而不仅仅是 M
修改。使用 git diff-index
将使您免于检查 R
enamed;使用 git diff
不会,因为那会读取用户的配置,这可能会设置 diff.renames
。您还应该准备好处理 T
ype-change,以防有人用文件替换符号 link,反之亦然。
一旦你有了一个修改过的文件列表,或者如果你愿意,可以与获取列表交错(但这更复杂——你需要保留和使用 :<mode>
的东西以获得强大的 line-by-line解码),你可以检查实际的差异。例如:
$ git diff-index --cached -p HEAD -- wt-status.c
diff --git a/wt-status.c b/wt-status.c
index f5debcd2b..e736da45f 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -1,3 +1,4 @@
+
#include "cache.h"
#include "wt-status.h"
#include "object.h"
说明我这里只是在文件顶部加了一个空行。 (你需要 --cached
让 Git 查看索引中的 blob 内容,而不是查看 work-tree 文件。你不需要 --cached
和初始 -r --name-status
变体,尽管包含它是无害的。这是 git diff-index
的一个烦人的特性。)
收集所有 git diff-index
输出并对其进行解析以发现您的日志消息文本后,您将准备好将新的提交日志消息写入日志消息文件。
5应该有吧。这是带有 Git 提交挂钩的主题:它们没有提供足够的信息。 Git 的更高版本可能会向挂钩添加更多参数,或设置特定的环境变量。例如,您可以在进程树中挖掘以尝试找到调用挂钩的 git commit
命令,然后查看它们的 /proc
条目或 ps
输出以找到它们的参数,但是这非常丑陋 error-prone,不太可能在 Windows.