我正在尝试从目录外部执行 git pull ...
不要那样做。(你为什么这样做?)
git --git-dir=$WORKDIR/sources/.git pull
ElpieKay 在评论中建议:
添加--work-tree=$WORKDIR/sources
您回复的内容:
似乎现在正在工作
当你同时使用这两个选项时,Git 将:
- 将自己重新定位到您的工作树,
$WORKDIR/sources
;
- 用作适当
$WORKDIR/sources/.git
的存储库;和
- 在那里运行 Git 命令。
除了覆盖任何环境$GIT_WORK_TREE
和$GIT_DIR
变量之外,这对选项与执行以下操作相同:
git -C $WORKDIR/sources pull
where-C
导致 Git 首先更改目录,然后再运行git pull
. 这将是git pull
从该位置运行的一种更典型的方式:具有分离--git-dir
和--work-tree
选项的变体允许您将.git
与工作树分开,在相对罕见的情况下这是有用的,并覆盖任何早期的环境变量设置。1
1当您使用这些选项时,Git 本身会设置这些相同的环境变量。所以:
git --git-dir=A --work-tree=B whatever
与以下内容完全相同:
GIT_DIR=A GIT_WORK_TREE=B git whatever
除了后一种形式采用 POSIX 样式的 shell(命令行解释器)。
进一步阅读(可选)
您能否提供有关为什么需要此选项的任何见解?
Git存储库实际上只是.git
目录中的内容。存储库主要由两个数据库组成:
每个提交都包含每个文件的完整快照,作为一种只读存档。Git 会(以多种方式)压缩这些快照,并对快照中的其他重复文件进行重复数据删除,因此在许多情况下这会占用非常少的空间。这种压缩技术并不完美——它在存在许多大的、预压缩的二进制文件时往往会失败——但它对于人类可读的文件非常有用,例如软件的源代码。
提交本身还包含其前一个提交的提交编号(或复数形式,用于合并提交)。因此,只要 Git 可以找到最后的提交(通过分支或其他名称),Git 就可以通过向后查找的链一次一步地使用这些提交来找到每个较早的提交。这是存储库中的历史记录:History = commits,从最后开始并向后工作。
但是有一个问题!这些只读的、压缩的提交/文件只能由 Git 本身使用。你可以用这些做的主要事情是与其他 Git 交换它们。您还可以将它们与git diff
或类似使用,并对项目如何随时间变化进行一些分析,等等。但你无法取得任何进展。仅使用由两个数据库组成的存储库,您无法完成新工作。
要完成工作,您将需要一个工作树。在这里,您将让 Git提取一个提交。提取的提交将归档(压缩、只读、Git 化、无用)文件扩展为正常的日常(有用)形式。我们称之为签出分支或提交。(我们何时以及是否称其为“分支”与“提交”是很多混乱的根源,因为人类在这里不一致,有时也对细节一无所知。棘手的部分是,当我们有一个分支检出,我们也有一个提交检出。当我们只有签出的提交——通过 Git 所谓的“分离的 HEAD”——我们仍然有一个签出的提交,但不是一个分支。)
非裸存储库被定义为具有工作树的存储库。裸存储库是缺少工作树的存储库。基本上就是这样,但是缺少工作树意味着这个存储库可以无条件地接收新的提交。具有工作树的 Git 存储库无法安全地接收已签出分支的新提交。因此服务器(托管)站点通常存储裸存储库。
该git pull
命令的意思是:首先,运行git fetch
,然后运行第二个 Git 命令,对通过该git fetch
步骤获得的新提交执行一些操作。 fetch 步骤在裸存储库中运行良好,但第二个命令(无论您选择git pull
运行哪个命令)都需要一个工作树。
当你运行 Git 命令时,如果你有一个工作树,你应该在工作树中运行它们。如果有充分的理由git
要从该工作树之外运行,则可以使用,如上所示。您也可以使用or参数。git -C working tree path
$GIT_WORK_TREE
--work-tree
此外,当您确实有一个工作树并且没有使用所有这些复杂的方法将存储库与工作树分开时, Git 期望.git
目录(或文件)存在于顶层。事实上,在没有所有这些花哨的两部分分离技巧的情况下,Git就是这样找到工作树的顶层的。假设你在:
/path/to/some/working/dir/ectory
Git 将查看.git
此路径中是否存在。如果没有,Git 将取消该ectory
部分并重试:是否有/path/to/some/working/dir/.git
? 如果没有,Git 将取消该dir
部分并重试:是否有/path/to/some/working/.git
? 如果是这样,Git 已经找到了你的工作树的顶层,.git
这里——无论它是一个文件,包含目录的位置.git
,还是目录本身,因此是目录——决定了.git
存储库本身所在的位置。
但是,在您的情况下,您运行了:
git --git-dir=$WORKDIR/sources/.git ...
这告诉 Git:Git 目录是(无论$WORKDIR
扩展为什么——这个扩展是由 shell 完成的,而不是由 Git 完成的)/sources/.git
。所以Git不必搜索顶层。你没有告诉 Git 工作树的顶层在哪里,所以它只是假设你的当前目录是工作树的顶层。但实际上,您当前的目录是另一回事。因此,Git 可能已经损坏了各种文件,理论上它们来自您的工作树。
Git 还存储了一些被 Git 称为索引(或暂存区或缓存,具体取决于 Git 的哪个部分正在执行此“调用”)这一事实,您可能会部分获救。例如,这实际上只是存储库目录中的一个文件.git/index
。(文件的确切位置可能会有所不同,有时还有其他文件,所以不要在这一路径上计算太多。请记住.git/index
,如果有一个具体的模型来说明“索引”是什么。)在这个索引中, Git 存储有关它已签出的文件的信息。索引的存在,加上假设您已经在工作树的顶层,这就是为什么git --git-dir=<path> pull
行为不正确的原因。