0

我正在尝试从目录外部执行 git pull,并且正在运行以下命令:

git --git-dir=$WORKDIR/sources/.git pull

输出是“Alrady Up To Date”,或者它只是“拉”修改,但文件不是远程文件,即使 git pull 输出显示它应该是,并且 git status 显示文件是“修改”,好像他在 git pull 之后保留了本地版本并告诉我我修改了它。

我该如何解决这个问题?我已经了解了 --work-tree 选项,但我不知道它是否会以某种方式产生影响。

4

1 回答 1

2

我正在尝试从目录外部执行 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 的提交和其他内部对象组成。这些是通过它们的哈希 ID 编号和检索的。 特别是提交哈希 ID 始终是唯一的,为了检索提交,Git 需要知道它的编号。

  • 另一个数据库由名称组成,例如分支和标签名称,每个名称都映射到一个哈希 ID 号。这允许您使用分支或标签名称来检索提交。添加提交通常涉及更新分支名称或远程跟踪名称,以便能够找到新提交。

每个提交都包含每个文件的完整快照,作为一种只读存档。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行为不正确的原因。

于 2021-05-06T21:36:14.787 回答