我有一个名为git
的有效/tmp/A
存储库。
当我cd
到/tmp/A
并从bash运行任何git
命令时,效果很好,但是当我从git
运行callCommand
命令时,在haskell程序中调用得到错误:
fatal: Not a git repository: '.'
如果我在callCommand
命令之前在pwd
ls -la
和git
中运行,例如:
callCommand $ "pwd; ls -la; git status"
它表明它在正确的路径/tmp/A
上,ls
表明该存储库存在并且具有.git
目录,但是git返回错误。
我怎么了?
更新。
ls
的输出是
drwxrwxr-x 11 xxx xxx 4096 Mar 22 11:44 .
drwxrwxr-x 3 xxx xxx 4096 Mar 22 11:44 ..
drwxrwxr-x 8 xxx xxx 4096 Mar 22 11:44 .git
-rw-rw-r-- 1 xxx xxx 270 Mar 22 11:44 .gitignore
drwxrwxr-x 7 xxx xxx 4096 Mar 22 11:44 dir2
drwxrwxr-x 8 xxx xxx 4096 Mar 22 11:44 dir1
drwxrwxr-x 9 xxx xxx 4096 Mar 22 11:44 test
已更新。更新。
从克隆的git存储库的钩子post-receive
中调用失败的程序。当不是从该存储库的钩子运行同一程序时,它可以正常工作。
为什么从钩子进行自我克隆存储库不起作用?
答案 0 :(得分:1)
TL; DR:您可能希望在脚本的开头使用unset GIT_DIR
(不过,Haskell拼写了此操作)。
这里的问题是,尽管/tmp/A
是一个明智的Git存储库,但实际的存储库本身却位于.git
子目录中。也就是说,/tmp/A/
是工作树,而/tmp/A/.git
是存储库专有。
在正常操作中,我们从工作树运行git subcommand arguments ...
,例如git status
或git commit -m message
。工作树包含一个.git
目录,或者在某些情况下包含 1 一个.git
文件。顶级git
命令检查.git
并找到它,然后说 aha,存储库是./.git
。或者,它找不到.git
,因此它看起来向上了一层,例如,它从/tmp/A
爬到了/tmp
本身的一层,并在那里检查了.git
。重复此操作直到出现某种停止点。 2
在所有情况下,该搜索过程必须都必须成功停止(通过找到适当的存储库),或者git subcommand
与fatal: Not a git repository ...
消息一起死亡。现在是关键的,并且是秘密的:这时,顶层git
命令设置了一个名为GIT_DIR
的环境变量,以包含实际存储库的路径名。 然后运行子命令,该命令使用$GIT_DIR
来定位存储库。在我们的常规用例中,我们在/tmp/A
中,并且/tmp/A
包含一个.git
目录,这会将$GIT_DIR
设置为/tmp/A/.git
,并且所有子命令都工作。
但是对于您而言,已经设置了 $GIT_DIR
。具体来说,它已设置为.
。因此,现在顶级git
命令停止搜索。它只是验证$GIT_DIR
是有效的并命名一个Git存储库,或者死于fatal
错误消息。由于/tmp/A
不是存储库(实际上是/tmp/A/.git
),因此会引起问题。
取消设置环境变量将重新打开搜索,从而解决了该问题。您也可以使用--git-dir
作为参数,或在$GIT_DIR
中设置正确的值。请注意,$GIT_WORK_TREE
适用相同的规则:--work-tree
参数设置$GIT_WORK_TREE
,如果您不使用它而$GIT_WORK_TREE
则不是集,前端git
命令使用其爬升文件系统树到.git
目录或文件代码中,以找到工作树的根目录。因此,如果在运行$GIT_DIR
时设置了$GIT_WORK_TREE
或git subcommand
,则Git会遵循它们,除非您用--git-dir
和/或{{1 }}。
挂钩始终设置为--work-tree
。他们可能也未设置$GIT_DIR
。其中大多数运行在工作树的顶层,但是,如the githooks documentation所述,$GIT_WORK_TREE
,pre-receive
,update
,post-receive
和{ {1}}全部在post-update
中运行。
1 在现代Git中,子模块和添加的工作树都使用push-to-checkout
即文件操作。 Git 1.7和1.8早期版本的子模块带有嵌入的$GIT_DIR
目录,并且不支持添加的工作树。
2 最明显的停止点是到达.git
时,无处可爬。但是,默认情况下,至少在Unix和类似Unix的系统上,Git会非常小心,以避免爬过挂载点。挂载点使您可以将不同的文件系统层和/或存储池移植到单个树结构层次结构中。例如,通常.git
本身可能是一个内存文件系统,而大型系统可能会将“系统存储”(/
等)与“用户存储”(/tmp
)隔离开。 Docker使用挂载点来重组Docker映像中的文件系统,等等。