git - 在 git hook 中操作 repo 时 -C 和 --git-dir 的区别

标签 git githooks

我正在编写一个 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 the GIT_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/

相关文章:

svn - Git 到 svn : Adding commit date to log messages

git - 如何使用 Jenkins 将源代码作为应用程序部署在 Azure 上的 Linux 虚拟机中?

git - 在 Git 预提交 Hook 中聚合和丑化 JavaScript

haskell - 部署使用 Snap 框架的 Haskell 代码

git - 哪个 git 钩子(Hook)用于验证推送的提交消息?

android - Maven 无法将 git-push 构建版本发布到存储库

linux - Etckeeper + git 和远程服务器

linux - 无法删除/找到 git hook

git post-receive hook 和一次推送多个提交

git - $GIT_DIR 不再设置在预提交 Hook 中