在 Mac 上与 .DS_Store 合并冲突

Merge conflict with .DS_Store on Mac

我已经在一个存储库上工作了一年多,没有任何问题。其他人第一次提交,当我试图提取他们的更改时,我收到了这条消息:

error: The following untracked working tree files would be overwritten by merge:
    .DS_Store

我在我的存储库中找不到名为 .DS_Store 的文件。我将 .DS_Store 添加到我的 .gitignore 并提交了这些更改,但我仍然收到错误。然后我在 git pull 之前尝试了 运行 git stash 但这也没有帮助。我该如何解决?

在 Macbook Pro 上使用 RStudio。

.DS_Store是一个隐藏文件(因为.),你不能只看到它。在终端中,你可以看到它 ls -la.

然后,如果你已经将.DS_Store推送到你的仓库,你必须untrack这个文件,然后只untracked 文件将被 .gitignore.

忽略

要取消跟踪文件,请执行 git rm --cached .DS_Store。然后,当 .DS_Store.gitignore 中正确注册时,您将永远不会在远程存储库中看到此文件。

但是也没有问题,用合并覆盖.DS_Store-文件。这些文件包含有关系统配置的信息。对于每个从 Mac OS 推送到此存储库的人,都将创建自己的 .DS_Store。但是通过正确添加到 .gitignore,这个文件不再每次都被覆盖。

Someone else committed to it for the first time ...

"Well, there's your problem!"

说真的,这个其他人他们的.DS_Store文件放到了他们的 提交。您接受了他们的提交,因此您接受了 .DS_Store 应该存储在您的 Git 存储库中的想法,在该提交中。 (您可能会考虑从 控制的存储库的每个副本中弹出此提交,并让他们重新正确执行此操作,或者您可能只是在您控制的每个存储库中为他们修复它通过将他们的提交提取到安全的地方,删除文件,并进行新的额外提交。请注意,您必须小心避免检查他们在任何“不安全”的地方的提交。)

由于 .DS_Store 是一个隐藏文件,macOS Finder 创建并使用它来存储有关在何处以及如何显示目录中各种文件和子目录的各种图标的信息(或文件夹,如果您喜欢该术语)。 你的记录想要显示的内容和位置; 他们 记录他们 想要显示的内容和位置;你可能不想要他们的,他们也可能不想要你的。然而,这种东西在覆盖时是非常无害的:你可以删除它并让 Finder 从头开始​​创建一个。但是,您将失去任何仔细的重新组织,以便将图标放在 想要的位置。

这里的关键概念是提交保存所有文件的快照

每个 提交到每个 Git 存储库存储每个文件。有很多事情需要了解,具体取决于您想要的 Git 掌握程度。 使用 Git 你需要知道的最小集合是:

  • 存储库的核心是提交的集合。 Git 存储库与 文件 无关,尽管提交包含文件。存储库与 分支 无关,尽管提交安排在我们称为分支的事物中,以及我们 称为分支的不同事物——或者更准确地说, branch names——帮助我们(和Git)找到提交。但最终存储库是关于提交的。

  • 每个提交都有一个独特的,但看起来随机且不可能记住的“数字”,以 hexadecimal 表示。这个数字对于 那个特定的提交是唯一的: 没有其他 Git 存储库——任何地方,出于任何目的——可以使用 那个 数字,除非它是存储那个特定的提交。1 这就是两个不同的 Git 克隆如何在遇到彼此时决定一个提交的提交对方所缺乏的。

  • 每个提交存储两件事:

    • 提交存储所有文件的快照,如本节所述。不过,提交中的文件以一种特殊的方式存储:它们被压缩——有时非常压缩——并且 Git 化,并且 去重。如果同一个文件有数百万次提交,它只存储 一次。所以即使 Git 存储每个文件的每个版本,每个版本只有一个副本,有时那个副本会减少到只有几个字节。

      请注意,虽然这样说听起来很有趣,但提交仅存储它存储的文件。也就是说,提交 AA 代表一些哈希 ID)可能是您的第一次提交,其中您只有一个 README.md 文件或类似文件。所以提交 A 只有那个文件,或者那个文件加上一些其他的框架启动文件。 next 提交 B 可能有更多文件,但 A 只有初始文件。

    • 一个提交存储了一些元数据,或者关于提交本身的信息。这包括诸如谁、何时以及为什么(他们的日志消息)之类的内容。元数据字符串一起提交,以便 Git 可以从另一个提交中找到一个提交。

  • 每次提交后,都是完全只读的。 (这实际上适用于 Git 的所有内部对象,并且是由于基于哈希 ID 的存储技巧。)

因为提交 只读的,并且有 Git 化的文件,只有 Git 可以读取,实际上什么都没有——甚至 Git 本身—可以覆盖,您 必须 提取 一个提交,然后才能处理或使用它。提取的待处理副本不是提交本身:它是一个副本。这个副本进入你的工作树,你在那里工作。

当您提取提交的副本时,Git 通常会覆盖您的 先前的 工作树副本。也就是说,Git 必须从 先前选择的 提交中丢弃所有 old 文件,并将它们替换为 new 来自 newly selected 提交的副本。

对于某些文件——您的未跟踪 文件,无论它们是否被忽略——Git 都可以不理会这些文件。大多数时候这对你来说很好:这意味着你的 macOS Finder 可以在你的工作树上放置各种 .DS_Store 文件,只要你不 添加和提交 文件,以便它们永远不会进入您存储库中的任何 commit,Git 永远不会打扰这些工作树文件。

但是一些文件 提交中。在这里,如果某些文件 F1F2 在当前提交 C 中,并且您正在切换到新的目标提交 T 具有 F1 相同的副本,但与 F2 具有 不同的副本 、Git 将不得不从您的工作树中删除文件 F2 并放入 T 版本F2.

.DS_Store 文件也是如此:如果您的同事/同事/其他人提交了包含一些 .DS_Store 文件的提交,而您当前的提交 C没有有一个.DS_Store文件但是你的工作树有一个,你有一个untracked .DS_Store 文件。 注意这个文件是否被忽略并不重要;重要的是你在你的工作树中有它,并且在目标提交 T 中也有一个名为 .DS_Store 的文件的副本。 你已经告诉 Git从当前提交 C 切换到提交 T,因此 Git 必须 删除 你的 (未跟踪).DS_Store 并从 T.

中输入 他们的 .DS_Store

Git——没错!——抱怨说它会覆盖(即丢弃)你的 .DS_Store 文件。如果您签出提交 T,它会的。您的选择是:2

  • 签出提交 T,无论如何都会覆盖您的 .DS_Store 文件;
  • 先移动或保存您的 .DS_Store 以便覆盖不再是问题,然后 检查提交 T;或
  • 不检查提交 T

请注意,您无法修复提交 T,因为任何提交都无法更改。您可以通过签出 删除 .DS_Store 文件,然后制作 T新的和改进的版本一个新的提交 T2,但是当你这样做时,你现有的 .DS_Store 文件将被短暂地覆盖,直到你删除它。 (然后,您可以根据需要将未跟踪的 .DS_Store 文件从保存的位置放回原处。)

如果保存和恢复您的 .DS_Store 文件由于某种原因特别痛苦——它可能不是,但可能有其他文件可能是这种情况——考虑使用 git worktree add添加临时工作树和分支,您可以在其中进行修复提交以进行更正提交 T2,而无需触及现有的工作树。使用命令行执行此操作,而不使用任何花哨的 GUI(包括 macOS Finder),以便 Finder 不会使用 in 临时添加的工作树中的 .DS_Store 文件。这种添加工作树技术让您可以使用所有常用的日常 Git 工具,而无需学习很多更深入的 Git 命令。


1这种对唯一性的技术要求在技术上是不可能的——通过 pigeonhole principle 证明是不可能的——但是巨大的 size提交哈希 ID 有助于推迟不可避免的灾难;我们希望在宇宙终结之前它不会发生,或者至少我们都死了并且不在乎。如果确实发生,宇宙被摧毁呃不狂欢发生呃等等那不是对 我们都变成了青蛙? 啊是的:两个 Git 存储库中存在这种散列冲突,无法再相互通信。所以,并不是真正的灾难,只是很烦人。

2从技术上讲,还有更多的选择。例如,您可以使用:

  • 稀疏检出, 避免在删除文件并提交制作之前检出一个文件T2;或
  • git read-treegit rm --cachedgit write-treegit commit-tree 从字面上避免在提交 T2 时检出提交 T

这些解释起来非常棘手,对于大多数人来说最好只使用常规 Git 操作。