Git pull 不起作用,显示本地文件已修改但未修改

Git pull doesn't work and shows local files as modified with no modifications

我正在尝试从目录外执行 git 拉取,我是 运行 这个命令:

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

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

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

I am trying to perform a git pull from outside the directory ...

不要那样做。 (你为什么要这么做?)

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

Add --work-tree=$WORKDIR/sources

您回复的内容:

Seems to be working now

当您同时使用这两个选项时,Git 将:

  • 将自身重新定位到您的工作树,$WORKDIR/sources
  • 使用 $WORKDIR/sources/.git 作为 存储库;
  • 运行 Git 命令在那里。

除了覆盖任何环境 $GIT_WORK_TREE$GIT_DIR 变量之外,这对选项与以下操作相同:

git -C $WORKDIR/sources pull

其中 -C 导致 Git 在 运行 宁 git pull 之前先更改目录。这将是从该位置 运行 到 git pull 的一种更典型的方法:具有单独 --git-dir--work-tree 选项的变体可以让您将 .git 与工作树,在相对罕见的情况下有用,并覆盖任何早期的环境变量设置。1


当您使用这些选项时,

1Git 本身会设置这些相同的环境变量。所以:

git --git-dir=A --work-tree=B whatever

与以下内容完全相同:

GIT_DIR=A GIT_WORK_TREE=B git whatever

除了后一种形式采用 POSIX 风格 shell(命令行解释器)。


进一步阅读(可选)

can you provide any insight on why this option is needed?

A Git repository 实际上只是 .git 目录中的东西。存储库主要由两个数据库组成:

  • 一个——通常更大——由Git的提交和其他内部对象组成。这些通过它们的散列 ID 进行编号和检索。 提交 哈希 ID 尤其总是唯一的,要检索提交,Git 需要知道它的编号。

  • 另一个数据库由names,如b运行ch和tag names组成,每一个都映射到一个hash ID号。这允许您使用 b运行ch 或标记名称来检索提交。添加 new 提交通常涉及更新 b运行ch 名称或远程跟踪名称,以便能够找到新的提交。

每个提交都包含每个文件的完整快照,作为一种只读存档。 Git 压缩这些快照(以多种方式)并在 快照中删除重复的文件 ,因此在许多情况下这需要非常少的 space。这种压缩技术并不完美——它在存在许多大的、预压缩的二进制文件时往往会失败——但它非常适合 人类可读的 文件,例如软件的源代码.

提交本身包含提交编号——或者数字,复数,用于合并提交——它们的前身提交.因此,只要 Git 可以找到 last 提交(通过 b运行ch 或其他名称),Git 就可以使用这些来找到 每个较早的提交,一次一步,通过向后看的链。这是存储库中的历史记录:History = commits,从最后开始并向后工作。

但是有一个问题。这些只读、压缩的 commits/files 只能由 Git 本身使用 。你可以用这些做的主要事情是与其他一些 Git 交换它们。您还可以将它们与 git diff 或类似的方法一起使用,并对项目随时间发生的变化进行一些分析,等等。但是你无法取得任何进展。您无法完成 new 工作,只有由两个数据库组成的存储库。

要完成工作,您需要一个工作树。在这里,您将 Git 提取 提交。提取的提交将归档(压缩的、只读的、Git-化的、无用的)文件扩展到他们正常的日常(有用的)形式。我们称之为 checked out b运行ch 或提交。 (我们何时以及是否将其称为“b运行ch”与“提交”是很多混乱的根源,因为人类在这里不一致,有时会忽略运行t的细节棘手的部分是,当我们检出 b运行ch 时,我们也会检出 commit。当我们 只有 检出一个提交时——通过 Git 所谓的“分离的 HEAD”——我们仍然有一个检出的提交,但不是 b运行ch .)

非裸存储库被定义为具有工作树的存储库。裸存储库是缺少工作树的存储库。这基本上就是全部内容,但是缺少工作树意味着这个存储库可以 接收 新提交 无条件地 。具有工作树的 Git 存储库无法安全地接收已签出的 b运行ch 的新提交。所以 server (hosting) 站点通常存储裸存储库。

git pull命令意味着:首先,运行git fetch,然后运行第二个Git命令用通过 git fetch 步骤获得 的新提交。 提取步骤在裸存储库中工作正常,但第二个命令 - 无论您为 git pull 到 运行— 需要 工作树。

当您 运行 Git 命令时,如果您有一个工作树,您应该 运行 它们 工作树中.如果有充分的理由你想从 外部 那个工作树 运行 git ,你可以使用 git - C<em>工作树路径</em>,如上图。您还可以使用 $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 调用它的 index(或 暂存区cache,取决于 Git 的哪一部分正在执行此“调用”)。这实际上只是存储库目录中的一个文件,例如 .git/index。 (文件的确切位置可能会有所不同,有时还会有其他文件,所以不要在这条路径上计算太多。记住 .git/index 尽管如果它有助于为“索引”是什么建立一个具体的模型.) 在此索引中,Git 存储关于 已检出哪些文件的信息。索引的存在,加上您已经在工作树的顶层的假设,是 git --git-dir=<path> pull 行为不正确的原因。