我制作了一个powershell脚本,为我项目中的某些文件添加标题。我希望每当代码处于推送到GitHub的过程中运行它,以便GitHub存储库中的所有此类文件都附加了标头,从而无需手动运行脚本。
问题在于,当我在预提交git hook中修改文件时,这些更改不会被重新进行,所以我基本上必须暂存,提交然后再次提交以提交标头。
有没有一种好方法可以解决这个问题,或者将powershell脚本的执行与git流分开是更好的做法吗?
答案 0 :(得分:2)
主题中问题的答案是"是的,但是。" :-)我在这里稍微改写一下,以便我们可以讨论所有的技术细节。 "但是"如果你使用git commit --only
,那将是一个很大的惊喜。我似乎记得有一段时间它也严重影响git commit -a
,但现在情况好一点。 (我不确定哪个Git版本与-a
表现不好。)
在大多数情况下,Git从an或 进行每次新提交。索引或任何索引本质上是一个提议的提交:它由一种扁平树组成,带有blob哈希值和文件名。它的形式使git mktree
特别方便,它将索引转换为一系列 tree 对象,并返回顶级树对象的哈希ID,然后进入提交对象。
然后,问题涉及这三个部分:
这里, 索引是与工作树一起使用的特殊的,可分辨的索引。每个工作树都有一个这样的索引:如果你使用git worktree add
,你会获得更多的工作树,每个工作树都有自己的私有索引,但你只能 in 一次只有一个工作树,所以"这个工作树的索引"是 索引。
但是,当您运行git commit
时,您可以指示它(使用--only
和/或其他命令行参数)来构建自己的私有索引,与<分开< em> 索引。如果您已经这样做了,它将使用环境变量GIT_INDEX_FILE
运行各个钩子,并将其设置为临时索引的路径名。 (如果没有,GIT_INDEX_FILE
将包含.git/index
,这是 索引文件的路径。)
所以Q1的答案是:$GIT_INDEX_FILE
。
现在,您可以实际修改Git用于构建提交的索引,因为Git会在运行挂钩后重新读取此索引。因此Q2的答案是:是的,这使得下一次提交在任何使用的索引中都使用了任何内容。
第三季度是最难的。如果您使用git commit --only <paths>
,Git必须创建一个临时索引:
HEAD
<paths>
根本没有打扰 索引。但是,如果提交继续并且成功,Git现在必须修改 索引,以解释这些<paths>
在新HEAD
提交中有新blob的事实。
实际上,Git需要创建两个临时索引(索引?),一个用于提议的提交及其--only
文件,一个用于提议的提交结果。建议的提交结果变为index.lock
,作为新索引。
如果您在运行时git add
个文件,它们将进入临时索引。但是 指数怎么样?让我们来看看:
$ cat .git/hooks/pre-commit
#! /bin/sh
echo pre-commit hook, GIT_INDEX_FILE = $GIT_INDEX_FILE
git add sneaky
$ echo this is the base version of sneaky > sneaky
$ echo this is the base version of other > other
$ git add other sneaky
$ git commit -m 'create two files'
pre-commit hook, GIT_INDEX_FILE = .git/index
[master 5131b63] create two files
2 files changed, 2 insertions(+)
create mode 100644 other
create mode 100644 sneaky
如您所见,预先提交挂钩在此处触发,并添加了sneaky
。这没什么大不了的,因为复制到此提交的索引 - 索引 - 已经是相同的基本版本。
但是,现在让我们修改sneaky
,git add
的当前内容,并修改other
和git add
的当前内容,以便我们在 索引中为这两个文件添加新内容......
$ echo version 2 of other > other
$ echo version 2 of sneaky > sneaky
$ git add other sneaky
此时,索引和工作树都有&#34;版本2&#34;。现在让我们将工作树文件更新为&#34;版本3&#34; 没有 git add
他们:
$ echo version 3 of other > other
$ echo version 3 of sneaky > sneaky
$ git status --short
MM other
MM sneaky
这告诉我们HEAD
,索引和工作树版本都不同:每个版本的HEAD
版本是基础,索引版本是版本2,工作树版本版本3。
现在我们运行git commit --only other
:
$ git commit --only other -m 'jump other straight to v3'
pre-commit hook, GIT_INDEX_FILE = [path]/.git/next-index-72393.lock
[master 91ec03b] jump other straight to v3
2 files changed, 2 insertions(+), 2 deletions(-)
现在让我们看看我们在提交,索引和工作树中有什么:
$ git status --short
MM sneaky
好的,other
的工作树版本与other
的索引版本匹配HEAD
版other
,所以:
$ cat other
version 3 of other
它们都是版本3.但sneaky
怎么样? HEAD
和索引不同,索引和工作树不同。让我们先看看HEAD
中的内容:
$ git show HEAD:sneaky
version 3 of sneaky
现在让我们看看工作树中的内容:
$ cat sneaky
version 3 of sneaky
啊哈,这些比赛!棘手的部分是查看索引版本,但我们也可以使用git show
:
$ git show :0:sneaky
version 2 of sneaky
哇,看那个! 索引版本是旧版本!
这就是Q3的答案:预提交钩子中的git add
更新用于构建下一个提交的索引,但是如果那个是临时的 index,它不更新将成为真正的索引。这可以说是一个错误:预提交钩子中的git add
也应该添加到将成为 索引的索引中。实现这一点有点棘手(git commit
可以在挂钩之前和之后读取临时索引,并且可能将任何更新复制到index.lock文件。
请注意,如果您在没有--only
的情况下提交,我会跳过详细信息。幸运的是,在这种情况下,您添加的索引是 索引,因此一切都按预期工作:
$ git reset --hard 5131b63
HEAD is now at 5131b63 create two files
$ echo v2 > other && echo v2 > sneaky && git add other
$ git commit -m 'regular commit'
pre-commit hook, GIT_INDEX_FILE = .git/index
[master 10a8b20] regular commit
2 files changed, 2 insertions(+), 2 deletions(-)
$ git status --short
$
预提交git add
替换了sneaky
的索引版本,并且它仍然被替换了......即使提交失败也会如此。
另请注意,使用git commit -a
时,我们会获得不同的临时索引:
$ git commit -a -m test
pre-commit hook, GIT_INDEX_FILE = [path]/.git/index.lock
在这里,Git为git commit -a
所做的是将建议的新索引创建为 index.lock
文件。 git add
正常进行,以通常方式添加文件,然后当提交成功时,Git 将 index.lock
重命名为index
。这将解锁索引文件,同时将修改后的索引放在适当位置,以便git commit -a
到Q3的答案是临时索引成为索引。这与git commit --only
的不同。
答案 1 :(得分:0)