【问题标题】:git pull and resolve conflict issuegit pull 并解决冲突问题
【发布时间】:2018-06-27 11:06:11
【问题描述】:

我在一个已修复的文件中遇到了正常的合并冲突(在拉取之后)。我更改了文件,使用 git add 添加并提交以便推送。 然后我发现当我推送时,其他 5 个文件与我更改的文件一起推送。 发生了什么?如果我用 gitk 检查我的提交只有那个文件, 如果我改为在 github Web 界面中查看,我会看到 6 个文件而不是 1 个(所以我在拉取时也下载了其他 5 个文件,但我没有触摸任何添加)。 如果我在本地做git show --stat commitID,我会看到类似网页。 拜托,谁能告诉我为什么合并添加了文件并且没有静默合并?我认为 pull 命令合并了它们,然后只有我修改过的快照(1 个文件)会被推送。为什么 gitk 给一件事而 git show stat 另一件事? (也许是一些 gitk 参数?)

【问题讨论】:

  • 您的初始合并会带来 5 个新文件吗?我在这里没有看到任何特别令人担忧的东西。当然,除非这 5 个文件不属于您团队中的任何人。那我可能会担心。
  • 您是否同时处理了这五个其他文件?另外,最后一个共同祖先是什么时候?可能同时在您的合并和分离这些文件的最近共同祖先之间还有其他提交,因此当然合并必须引入这些更改。
  • 我担心的是......当我提交某些东西时,我会在舞台上提交文件。要在阶段添加文件,我需要“git add”它们。当我拉(即提取 + 合并)时,是否有合并的某些部分将文件添加到阶段?我可以这样解释。我的错是我在添加修复之前没有做“git status”,但我认为舞台是空的。顺便说一句,我从来没有碰过那些文件。
  • @TimBiegeleisen:文件已经存在。它们只是被修改了,我把它们拉了出来。我担心的是,由于我没有像修复时那样通过“git add”将它们添加到舞台上,它们是如何完成提交的?合并操作是否自动为我添加了它们?为什么在 gitk 我的提交中只显示我的修复,而在 github 页面中我看到它们?

标签: git merge conflict pull


【解决方案1】:

解决您在评论中添加的内容:

我担心的是......当我提交某些东西时,我会在舞台上提交文件。

没错。但是:

要在阶段添加文件,我需要“git add”它们。

这不太对。我们稍后再讨论这个问题。

当我拉取(即提取 + 合并)时,是否有合并的某些部分将文件添加到阶段?

是的,有。

我可以这样解释。我的错是我在添加修复之前没有做“git status”,但我认为舞台是空的。

现在让我们仔细看看这个。这个暂存区究竟是什么?请注意,它有三个不同的名称:暂存区,这是您一直使用的名称; 索引;有时是 cache(所以你会看到,例如,git rm --cached 和 git diff --no-index 或 git diff --cached 来控制是否涉及索引/缓存/暂存区域)。我将在这里使用 index 这个词,以避免过多地暗示它:staging area 这个名称(在许多方面更好)暗示了关于索引的一些内容用于暂存文件,而名称 cache 暗示了如何使用索引来加速各种操作。

我喜欢定义索引的方式是,您可以使用它来构建您将进行的下一次提交。这是指它在暂存文件中的作用,但提醒您为什么您也在暂存文件:因为您打算进行新的提交。如果它们与旧的完全一样,那么制造新的就没有意义了。所以在某种程度上,我们知道我们正在更改存储在索引中的数据,然后我们将使用git commit 将其转换为新的快照。

关于索引的第一个奇怪的事情是它永远不会1为空。相反,索引通常匹配当前提交。此时您必须运行git commit --allow-empty 来创建新的提交。这不是因为索引本身是空的;相反,这是因为索引与当前提交之间的差异为空。

不过,稍后,您将 git checkout 提交一些提交(可能通过分支名称),或者运行 git commit 来创建一个新提交。在 this 点,索引和当前提交将相互匹配。索引中的内容也是已提交的内容。

当您运行git add 时,您所做的是将工作树文件复制到索引中。如果那是一个 new 文件,那么它现在在索引中,而以前它不存在。如果是 changed 文件,您刚才所做的就是将存储在索引中的数据替换为新数据。无论哪种方式,索引版本现在都与工作树版本匹配。 (练习:索引版本现在是否匹配提交版本?如果工作树版本匹配提交版本会发生什么?)

关于索引的第二个奇怪的事情是在git merge 期间发生了什么。 git merge 处理的情况有多种,其中一些很容易,不要这样做;但其中之一是真正的合并。在真正的合并中,Git 有两个特定的提交——我喜欢称它们为 L 和 R,分别代表左右,或者本地和远程,或者 --ours 和 @ 987654333@——共享一个共同的合并库提交B。 Git 通过实际上运行来查找自公共基础以来发生的事情:

git diff --find-renames B L   # what did we change in --ours?
git diff --find-renames B R   # what did they change in --theirs?

然后,Git 将 组合 更改,实际上是用每个文件的 三个 版本填充索引:一个来自 B ,一个来自 L,一个来自 R。这三个进入每个文件的索引条目中的“槽”。通常,在非合并中间的情况下,只占用槽零。当我们合并时,slot 0 被引导出来,三个版本进入 slot 1-3。

然后,Git 可以轻松比较这三个版本,并决定采用哪一个(如果 --ours 与 --theirs 中只有一个更改了文件与基础)或如何组合更改(如果 --ours 和--theirs 改变了它)。 如果Git 可以组合更改——好吧,如果它认为可以——它会这样做,并完全丢弃这些编号较高的插槽条目:组合版本进入插槽零像往常一样,该文件已解决。如果 Git 认为它不能组合更改,它会将其最佳猜测和冲突标记写入工作树,然后将编号较高的插槽留在索引中。2 然后你必须自己解决(使用工作树文件,或者三个索引槽条目,或者你喜欢的任何东西)和git add 正确的结果,不管是什么。然后git add 步骤将清除槽 1-3 条目并写入槽零条目。

在这一切结束后,我们回到了更正常的情况。索引现在在每个文件的正常插槽零(无冲突)条目中包含每个文件的副本,因为它应该出现在新的合并提交中。所以现在我们或 Git 可以运行 git commit 来提交最终结果。

如果我们进行真正的合并,并且 R 中的文件既不在 L 也不在合并基础 B 中,该文件的合并结果是“获取新文件”。所以这种情况很简单,git merge 将文件添加到插槽 0 中,而没有真正提及它。


1好吧,有一种明显的情况是索引完全为空,即根本没有文件。例如,这是一个新的、新鲜的、完全空的存储库中的初始状态。请注意,在这种情况下,您也没有任何分支。这是一个特殊的状态:你在分支 master 但分支 master 还不存在!索引确实是空的,根本没有提交。

2这个一般性的描述并不完全是它在内部发生的方式,它都经过优化以使简单的案例快速进行。但这是合乎逻辑的过程。优化流程见the git read-tree documentation。

【讨论】:

    猜你喜欢
    • 2018-08-04
    • 2010-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-15
    • 2023-03-21
    • 2021-04-02
    • 1970-01-01
    相关资源
    最近更新 更多