我正在编写一个 git post-receive Hook ,它将克隆一个单独的存储库作为部署的一部分。它将 repo 克隆到某个文件夹,并在后续 git 命令中使用 -C
选项将目录设置为 check out repo 的目录(如 man page 中所述)。
当从命令行手动运行时,钩子(Hook)按预期工作,但是当钩子(Hook)由 git 运行时(即当收到推送时)命令失败并显示 fatal: Not a git repository: '.'
。当我将 -C
换成 --git-dir
时,它起作用了。
这很容易重现,创建一个裸仓库 git init --bare
并用内容制作一个可执行钩子(Hook):
#!/bin/bash
set -xe
SOME_REPO_URL=???? # Some repo that is not this one
repopath=/tmp/somerepo
git clone $SOME_REPO_URL $repopath
# 1: This fails when run through the git hook
git -C $repopath checkout -b somebranch HEAD~1
# 2: This works every time
# git --git-dir $repopath/.git checkout -b somebranch HEAD~1
从命令行运行脚本将按预期工作,但当您推送到存储库时, Hook 将失败。注释 1
和取消注释 2
在这两种情况下都有效。
我找不到任何表明这是预期行为的文档 - 将不胜感激。
这是 Ubuntu 16.04 上的 git 2.7.4。
最佳答案
文字上的区别:
git -C <em>directory git-sub-command ...</em>
和:
git --git-dir <em>directory git-sub-command ...</em>
是前端设置程序git
首先使用操作系统级别的“将目录更改为”操作(来自 Python 的 os.chdir
,来自 C 的 chdir()
等),并设置环境变量 $GIT_DIR
第二个。在任何一种情况下,它都会找到子命令并运行它。 (请注意,您实际上可以两者。)This is documented , 包括多个 -C
的影响选项和 -C
之间的交互和 --git-dir
.
然而,这只是将问题推低了一个层次:现在您需要知道什么 git-checkout
(在 git --exec-path
目录中找到)与 $GIT_DIR
不同与当前工作目录相比。直接答案在the top level git
command documentation, under the ENVIRONMENT VARIABLES section :
GIT_DIR
If theGIT_DIR
environment variable is set then it specifies a path to use instead of the default.git
for the base of the repository. The--git-dir
command-line option also sets this value.
这是Jan Krüger's comment的地方进来。当你写一个Git hook时,你必须意识到Git可能会为你设置一些环境变量。如果$GIT_DIR
设置为相对路径名,并且您不覆盖它,并且您更改目录,您将更改所有各种 Git 子命令定位存储库的方式。因此,您必须取消设置它(以获得默认的 $GIT_DIR
-not-set 行为),或显式将其设置为绝对路径(以在目录更改时保留它),或显式设置它到其他存储库的路径(相对或绝对),具体取决于您想要的行为。
请注意 --work-tree
套$GIT_WORK_TREE
,还有其他类似的变量,但是——至少在迄今为止的所有 Git 版本中——$GIT_DIR
是 Git 钩子(Hook)中唯一一个“为你预先设置”(或“为了你的烦恼”:-))。
关于git - 在 git hook 中操作 repo 时 -C 和 --git-dir 的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42295050/