在git钩子中操作repo时-C和--git-dir之间的区别 [英] Difference between -C and --git-dir when manipulating repo in git hook

查看:107
本文介绍了在git钩子中操作repo时-C和--git-dir之间的区别的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个git post-receive钩子,它将克隆一个单独的仓库作为部署的一部分.它会将存储库克隆到某个文件夹,并在后续git命令中使用 -C 选项将目录设置为已签出存储库的目录(如

I am writing a git post-receive hook that will clone a separate repo as part of a deployment. It clones the repo to a certain folder and uses the -C option in subsequent git commands to set the directory to that of the checked out repo (as documented in the man page).

从命令行手动运行时,钩子可以按预期工作,但是当钩子由git运行时(即,当接收到推送时),命令失败,并带有 fatal:不是git信息库:'.'.当我将 -C 换为-git-dir 时,它会起作用.

The hook works as expected when run manually from the command line, however when the hook is run by git (ie when a push is received) the command fails with fatal: Not a git repository: '.'. When I swap out the -C for a --git-dir it works.

这很容易复制,创建一个裸仓库 git init --bare 并创建一个包含以下内容的可执行钩子:

This is fairly simple to reproduce, create a bare repo git init --bare and make an executable hook with the contents:

#!/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

从命令行运行脚本将按预期运行,但是当您推送到存储库时,挂接将失败.在两种情况下都可以使用注释 1 和取消注释 2 .

Running the script from the command line will work as expected, but when you push to the repo the hook will fail. Commenting 1 and uncommenting 2 will work in both cases.

我找不到任何表明这是预期行为的文档-请多多解释.

I can't find any documentation that would indicate that this is intended behaviour - an explanation would be appreciated.

这是Ubuntu 16.04上的git 2.7.4.

This is git 2.7.4 on Ubuntu 16.04.

推荐答案

两者之间的字面差异:

git -C 目录git-sub-command ...

和:

git --git-dir 目录git-sub-command ...

是前端安装程序 git 使用操作系统级别的将目录更改为"操作(来自Python的 os.chdir chdir()从C等开始),并为第二个设置环境变量 $ GIT_DIR .在这两种情况下,它都将找到子命令并运行它.(请注意,您实际上可以同时执行 .)

is that the front end setup program git uses an OS-level "change directory to" operation (os.chdir from Python, chdir() from C, etc) for the first, and sets an environment variable $GIT_DIR for the second. In either case it then locates the sub-command and runs it. (Note that you can in fact do both.) This is documented, including the effects of multiple -C options and the interaction between -C and --git-dir.

但是,这只是将问题向下推了一层:现在您需要知道什么 git-checkout (位于 git --exec-path 目录中) $ GIT_DIR 的处理方式与当前工作目录的处理方式不同.直接答案在顶层 git 命令文档,位于环境变量"部分下:

That, however, just pushes the problem down one level: now you need to know what git-checkout (found in the git --exec-path directory) does differently with $GIT_DIR than it does with the current working directory. The direct answer is in the top level git command documentation, under the ENVIRONMENT VARIABLES section:

GIT_DIR
如果设置了 GIT_DIR 环境变量,则它将指定用于存储库基础的路径,而不是默认的 .git .-git-dir 命令行选项也会设置该值.

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.

这是扬·克鲁格(JanKrüger)的评论出现了.编写Git钩子时,您必须意识到Git可能会为您设置一些环境变量这一事实.如果将 $ GIT_DIR 设置为相对路径名,并且不覆盖它,而是更改目录,则将更改所有各种Git子命令查找存储库的方式.因此,您必须 un 设置它(以获得默认的 $ GIT_DIR -not-set行为),或显式将其设置为绝对路径(以在整个目录中保存它)更改),或将其显式设置为某些其他存储库的相对或绝对路径,具体取决于您想要的行为.

This is where Jan Krüger's comment comes in. When you write a Git hook, you must be aware of the fact that Git may set some environment variables for you. If $GIT_DIR is set to a relative path name, and you do not override it, and you do change directories, you will change the way all the various Git sub-commands locate the repository. Therefore you must either un-set it (to get the default $GIT_DIR-not-set behavior), or explicitly set it to an absolute path (to preserve it across directory changes), or explicitly set it to the path—relative or absolute—of some other repository, depending on what behavior you want.

请注意,-work-tree 设置了 $ GIT_WORK_TREE ,并且还有其他类似的变量,但是-至少在迄今为止的所有Git版本中,- $GIT_DIR 是Git挂钩中唯一的一个为您预设"(或为您烦恼" :-)).

Note that --work-tree sets $GIT_WORK_TREE, and there are other similar variables, but—at least in all Git versions to date—$GIT_DIR is the only one "pre-set for you" (or "for your annoyance" :-) ) in Git hooks.

这篇关于在git钩子中操作repo时-C和--git-dir之间的区别的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆