当来自 git 预提交挂钩的 运行 时,`git diff` 不起作用
`git diff` does not work when run from a git pre-commit hook
我有一个 git 预提交挂钩,可以在提交之前对任何修改后的文件进行一些样式检查。
实现无关紧要,但它从调用 git diff
开始。这是我在 (repo)/.git/hooks/pre-commit
中的内容。
#!/bin/sh
echo "=== Running script..."
git diff
echo "=== Done running script..."
# Other stuf
# ....
# Always exit with 1 so pre-commit hook always fails.
# Useful for testing
exit 1
当我实际尝试提交某些内容时,pre-commit
挂钩正确触发,但 git diff
命令不输出任何内容(肯定有修改过的文件)
> git commit --all -m "foo"
=== Running script...
=== Done running script...
然而,如果我 运行 pre-commit
钩子脚本 directly/manually,它 确实 工作
> ./.git/hooks/pre-commit
=== Running script...
(... outputs git diff ...)
=== Done running script...
git 调用 hook 与我手动调用它有什么不同?无论哪种方式,它 运行 都是同一个用户(我的用户名)
我也试过 this thread 的建议,但是 unset GIT_DIR
、--git-dir=
和 work-tree=
没有解决任何问题。
谢谢!
您需要使用 git diff --cached
,因为更改已经开始。
作为,您在这里需要git diff --cached
,但这不一定是全部。
这里有两个陷阱需要警惕。第一个是 git diff
所做的:它比较两个 树 (或类似树的东西)。第二个与短语 the index.
有关
索引,并为 git diff
选择树
通常,您比较的两棵树是与两个特定提交关联的树:
git diff <hash1> <hash2>
(或与 <hash1>..<hash2>
相同,与大多数 Git 命令不同, 不会 像双点..
操作在 the SPECIFYING RANGES section of the gitrevisions documentation) 中描述。
将两棵树中的一棵作为您的 work-tree 也很常见,当您 运行:
时就会发生这种情况
git diff HEAD
例如:这会将由 HEAD
命名的提交(即当前分支尖端提交)与当前工作树进行比较。
使用:
git diff --cached
告诉 Git 将 HEAD
提交与您的 index 代表的树进行比较。 Git 的索引,也称为 暂存区 或 缓存 ,是 Git 构建 下一步 承诺制作。这就是为什么在提交之前必须 运行 git add
:git add
命令将文件从工作树复制到索引。
使用:
git diff
完全没有参数选择索引作为第一棵树,工作树作为第二棵树。一旦所有内容都从工作树复制到索引中,这个特定的差异将是空的,这就是您在这里看到的。
指数 vs 指数
第二个陷阱在于您正在使用 git commit --all
.
虽然 Git 谈论 索引,但实际上每个工作树都有一个特定的、有区别的索引,Git 实际上允许多个索引,一次只使用一个。
当您使用 git commit --all
或将文件名传递给 git commit
时,Git 会创建一个 临时 索引,它会在承诺过程。为了表明有一个临时索引在起作用,Git 设置了环境变量 GIT_INDEX_FILE
。使用此临时索引而不是普通索引,直到允许并提交提交,或者直到拒绝提交。
如果提交被拒绝,Git只是删除临时索引,一切都恢复到原来的样子。如果事情不是 git add
-ed,它们仍然不是 git add
-ed。
如果提交被接受,临时索引变成"real"或"main"索引,更多或更少。这里事情会变得复杂,因为你可以在真正的索引中暂存一些项目,运行 git commit --all
或 git commit --include <paths>
或 git commit --only <paths>
,如果提交成功,两者之间的区别初始(主要或实际)索引和临时索引很重要。
如果您打算对工作树中的文件 and/or 它们在索引中的副本进行特殊处理,您可能希望简单地拒绝任何使用临时索引的尝试,以避免这些并发症。但是,这将排除 --all
.
的使用
我有一个 git 预提交挂钩,可以在提交之前对任何修改后的文件进行一些样式检查。
实现无关紧要,但它从调用 git diff
开始。这是我在 (repo)/.git/hooks/pre-commit
中的内容。
#!/bin/sh
echo "=== Running script..."
git diff
echo "=== Done running script..."
# Other stuf
# ....
# Always exit with 1 so pre-commit hook always fails.
# Useful for testing
exit 1
当我实际尝试提交某些内容时,pre-commit
挂钩正确触发,但 git diff
命令不输出任何内容(肯定有修改过的文件)
> git commit --all -m "foo"
=== Running script...
=== Done running script...
然而,如果我 运行 pre-commit
钩子脚本 directly/manually,它 确实 工作
> ./.git/hooks/pre-commit
=== Running script...
(... outputs git diff ...)
=== Done running script...
git 调用 hook 与我手动调用它有什么不同?无论哪种方式,它 运行 都是同一个用户(我的用户名)
我也试过 this thread 的建议,但是 unset GIT_DIR
、--git-dir=
和 work-tree=
没有解决任何问题。
谢谢!
您需要使用 git diff --cached
,因为更改已经开始。
作为git diff --cached
,但这不一定是全部。
这里有两个陷阱需要警惕。第一个是 git diff
所做的:它比较两个 树 (或类似树的东西)。第二个与短语 the index.
索引,并为 git diff
选择树
通常,您比较的两棵树是与两个特定提交关联的树:
git diff <hash1> <hash2>
(或与 <hash1>..<hash2>
相同,与大多数 Git 命令不同, 不会 像双点..
操作在 the SPECIFYING RANGES section of the gitrevisions documentation) 中描述。
将两棵树中的一棵作为您的 work-tree 也很常见,当您 运行:
时就会发生这种情况git diff HEAD
例如:这会将由 HEAD
命名的提交(即当前分支尖端提交)与当前工作树进行比较。
使用:
git diff --cached
告诉 Git 将 HEAD
提交与您的 index 代表的树进行比较。 Git 的索引,也称为 暂存区 或 缓存 ,是 Git 构建 下一步 承诺制作。这就是为什么在提交之前必须 运行 git add
:git add
命令将文件从工作树复制到索引。
使用:
git diff
完全没有参数选择索引作为第一棵树,工作树作为第二棵树。一旦所有内容都从工作树复制到索引中,这个特定的差异将是空的,这就是您在这里看到的。
指数 vs 指数
第二个陷阱在于您正在使用 git commit --all
.
虽然 Git 谈论 索引,但实际上每个工作树都有一个特定的、有区别的索引,Git 实际上允许多个索引,一次只使用一个。
当您使用 git commit --all
或将文件名传递给 git commit
时,Git 会创建一个 临时 索引,它会在承诺过程。为了表明有一个临时索引在起作用,Git 设置了环境变量 GIT_INDEX_FILE
。使用此临时索引而不是普通索引,直到允许并提交提交,或者直到拒绝提交。
如果提交被拒绝,Git只是删除临时索引,一切都恢复到原来的样子。如果事情不是 git add
-ed,它们仍然不是 git add
-ed。
如果提交被接受,临时索引变成"real"或"main"索引,更多或更少。这里事情会变得复杂,因为你可以在真正的索引中暂存一些项目,运行 git commit --all
或 git commit --include <paths>
或 git commit --only <paths>
,如果提交成功,两者之间的区别初始(主要或实际)索引和临时索引很重要。
如果您打算对工作树中的文件 and/or 它们在索引中的副本进行特殊处理,您可能希望简单地拒绝任何使用临时索引的尝试,以避免这些并发症。但是,这将排除 --all
.