【问题标题】:One git repository, but one file is different on two different computers一个 git 存储库,但一个文件在两台不同的计算机上不同
【发布时间】:2021-01-03 19:18:31
【问题描述】:

我有一个远程(异地、托管)git 存储库,我正在从两台笔记本电脑访问它。由于我是唯一使用此存储库的人,因此我不必费心拥有单独的分支。通常当我提交并推送到存储库时,我会在我的另一台笔记本电脑上获取并合并。

我现在发现自己的情况是,我在两台计算机上都有一个文件的不同版本,而 git 告诉我不需要做任何事情,也不需要进行更新。

在两台笔记本电脑上,当我键入时

git remote -v

我收到了完全相同的东西——远程仓库的地址

origin  git@XYZ.com:myproj.git (fetch)
origin  git@XYZ.com:myproj.git (push)

在两台笔记本电脑上都会返回一个 git status 调用:

On branch master
Your branch is up-to-date with 'origin/master'

如果我执行

git remote update

我收到

Fetching origin

然后我打电话

git status -uno

我明白了

On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit

最后,如果我打电话

git fetch origin

没有输出。如果我再打电话

git merge

收到回复

Already up-to-date.

当我输入时

git rev-parse HEAD

在两台笔记本电脑上,我收到完全相同的哈希值:

d353340c1.....8503b

据我所知,两台笔记本电脑都认为远程存储库的所有内容都是最新的,但其中一个文件在两台笔记本电脑上明显不同。

这怎么可能,以及我如何才能说明所有内容真正同步的位置?

一台笔记本电脑正在从命令行运行带有 git 版本 2.7.4 的 Ubuntu 16.04。 另一个是 Windows 10,通过 Mintty 终端上的 git bash 2.19.0.windows.1 访问。

【问题讨论】:

  • 你试过git merge FETCH_HEAD吗?
  • 您能否编辑您的问题以在两个系统上包含git rev-parse HEAD 的输出?
  • @bk2204,我的帖子已被编辑添加。
  • 有什么不同?您是通过检查还是通过哈希确定的?该文件是实际在存储库中,还是被忽略(您可以使用git check-ignore 查找)?
  • 通过检查文件不同(其中一个版本中有 4 行)。这也清楚地反映在每个操作系统报告的字节大小差异(几百个)中。存储库中的任何地方都没有 .gitignore 文件,当我输入带有文件名的 git check-ignore 时,它​​什么也不返回。

标签: git command-line


【解决方案1】:

除了两个签出文件的差异似乎完全正常,在这里。鉴于这两个签出文件是(显然——见下文)跟踪文件,即在每台机器上的 Git 索引中,这种差异通常应该导致 git status 说有变化not staged for commit 至少在两个系统之一上。

在这一点上,可能会发生几件事:

  1. 该文件实际上可能不在索引中并且被忽略(但这似乎已在 cmets 中被排除)。
  2. 文件可能在缓存中被错误地标记为“干净”,因此git status 只是假设文件的工作树副本与文件的索引副本匹配。
  3. 该文件实际上可能是“干净的”。

在我详细介绍案例 2 和 3 之前,这里有一个特别的事实值得注意。当您使用 Git 时,您看到和使用的文件不在 Git 中。 在 Git 中的文件(存储在提交中)以特殊的、只读的、仅限 Git 的、压缩和去重的形式存储,只有 Git 才能真正使用。因此,为了使用提交,Git 必须复制该提交到某个地方,将文件转换为您可以实际使用的普通日常文件。这些文件在您的工作树 或工作树 中,而这个工作区实际上并不在 Git 存储库中。 (适当的存储库通常位于工作树顶层的 .git 子目录中。)

现在,案例 1 非常简单:

  • Git 的索引本身是一个复杂的小动物,但它相当于一个列表,列出了所有要提交的文件,包括它们应该具有的已经 Git 化的 内容 下一步提交。
  • Git 索引中不的文件不会出现在下一次提交中(当然您可以更改它,例如使用git add)。
  • 存在于工作树中但不在 Git 索引中的文件根据定义是未跟踪文件。

这就是不被跟踪的全部内容:它只需要存在于您的工作树中,但不存在于 Git 的索引中。未跟踪的文件通常会导致 Git 抱怨,但如果在 .gitignore 中列出,Git 就会停止抱怨。这当然需要存在.gitignore 或.git/info/exclude 文件。 (您可以在主目录配置中使用全局 .gitignore,但 git check-ignore -v 会指出它,如果它导致文件被忽略。)

如果为该存储库定义了 clean 和 smudge 过滤器(通过存储库中的 .gitattributes 以及某些 Git 配置文件中的过滤器定义),则可能发生第 3 种情况( s)):

  • 涂抹过滤器(如果有的话)负责更改从 Git 出来的文件。当 Git 提取提交时,它首先将提交的所有文件复制到其索引中(以便它们准备好进入下一次提交)。1 然后,Git 提取这些文件 - 解压缩并将它们反Git-化为您可以实际使用的版本,然后进入您的工作树。如果有污点过滤器,数据会在到达工作树副本的途中通过污点过滤器,因此工作树副本不需要匹配(扩展的)索引副本。 p>

  • clean 过滤器(如果有的话)负责在文件进入 Git 时更改文件。当您git add 一个文件时,Git 会压缩、Git 化和去重文件的数据。如果有一个干净的过滤器,Git 会在开始压缩和 Git 化过程之前通过干净的过滤器运行数据。所以清洁过滤器可以带走污迹过滤器放入的东西。这样,您可以提交与您实际使用的文件不同的文件。2

根据使用的清洁和涂抹过滤器,可以想象一些工作树文件的大部分内容在两台不同的机器上会完全不同。这当然需要文件定义干净和涂抹过滤器,而这又需要.gitattributes 或.git/info/attributes 文件。

这留下了最后一种可能性:案例 2,Git 认为文件是干净的(因为它是这样标记的),即使它不是。解决这个问题的最简单方法是 touch 文件(使用 Unix/Linux touch 命令,如果有的话)。这会将文件上的修改时间戳设置为“现在”,这可能比保存在 Git 索引中的任何已保存的修改时间戳(从“那么”,几秒钟或更长时间之前)晚。

如果这些都无法找到或纠正问题,那么其他事情——非常神秘的事情,可能是 Git 错误——正在发生。


1这过于简单了:在某些情况下,Git 的索引中已经存在某些内容,可以将其保留在原处。我们将在这里忽略这些极端情况。

2至少在理论上,这是一种获得人们不断要求的东西的方法:拥有一个配置文件,其中包含未提交的“本地配置”部分。但是,这样做会遇到一些困难的实施问题。

【讨论】:

    猜你喜欢
    • 2019-03-03
    • 1970-01-01
    • 2018-08-12
    • 2021-12-02
    • 1970-01-01
    • 2021-11-03
    • 1970-01-01
    • 2015-12-26
    • 2018-03-03
    相关资源
    最近更新 更多