【问题标题】:Git Merge Conflict: Add Changes to be committed when resolved?Git合并冲突:解决时添加要提交的更改?
【发布时间】:2017-01-05 15:56:16
【问题描述】:

我经常遇到以下合并冲突问题并解决它,但我想问一下我的解决方案是否正确。就我个人而言,鉴于功能测试正在通过,我没有看到任何问题,但如果能对此有所了解会很好。

所以,假设我们有两个分支:

  1. develop
  2. feature

我正在更改 feature 分支中的代码,然后创建一个 PR 以合并到 develop。但是,GithubBitbucket 的 diff 工具表明我们遇到了合并冲突;编码中很常见的情况。

然后我采取以下步骤:

  1. git checkout developgit pull origin develop

  2. git checkout feature 然后git pull origin feature

  3. git merge develop,所以要更新我当前的分支。这些步骤帮助我找出发生冲突的文件。
  4. 然后我手动修复冲突,我看到:

`您有未合并的路径。 (修复冲突并运行“git commit”)

要提交的更改:

modified:   app/BlablaFile.php
    modified:   app/Blabla2File.php
    renamed:    app/OldName.php -> app/NewName.php

然后:

Unmerged paths:
  (use "git add <file>..." to mark resolution)
    both modified:   app/UnmergedFile.php

这基本上是我为解决合并冲突而编辑的文件列表。

问题是我应该只git add app/UnmergedFile.php 然后git commit -m "Updated app/UnmergedFile.php" 吗?或者我应该git add 也包含在Changes to be committed: 部分中的文件?

我通常会做第一个,但如果有另一个想法会很好。

【问题讨论】:

    标签: php git github git-merge


    【解决方案1】:

    TL;DR:您不需要重新添加“要提交的更改”中的文件。

    Git 的“索引”

    Git 有一个叫做 indexstaging area 的东西,有时甚至是 cache(如 git diff --cached )。解释得不是很好,部分原因是它很复杂。幸运的是,索引的使用非常简单,除了(唉)在合并期间。 :-)

    索引中的内容最好描述为您将进行的下一次提交。这也有助于记住 Git 总是有一个 当前提交,名为 HEAD,和(--bare 存储库除外),work-treeworking tree,您可以在其中准备好文件以供查看、编译、编辑和进行其他任何操作是你处理你的文件。

    最初,您的工作树、索引和HEAD 提交都匹配(当您第一次克隆存储库时)。您不能直接在索引中接触文件,因此您可以在工作树中进行任何更改,甚至创建新文件,您可以在其中完成所有工作。然后,要将修改后的文件放回索引中,请在路径上运行 git add,以便 Git 将修改后的文件复制到索引中。要将新文件放入索引中,您还需要在路径上运行 git add

    如果你出于某种原因兴奋不已并立即运行git commit,Git 会读取你当前的索引并将其打包为一个新的提交。新提交将拥有索引中的每个文件,作为它的工作树快照,现在处于它现在的状态,在索引中。

    如果该状态匹配HEAD 提交,git commit 只会说:“呵呵?为什么你现在尝试进行新的提交?”因此,您可能已经更改了索引中的某些内容。 git status 将向您展示索引中与HEAD 提交不同的内容:这些是“要提交的更改”。

    合并

    运行git merge 有时会揭示有关索引的秘密。 in 索引中的每个条目实际上有四个 slots,它们被编号。通常,您只会看到插槽 0,它是为“正常”文件保留的,准备提交。

    合并旨在合并两组(或有时更多,但让我们坚持两组)更改。例如,也许您和 Bob 从相同的文件开始。然后您对一些文件进行了一些更改,git add-ed 并提交了源的新快照。与此同时,Bob 对一些文件进行了一些更改——甚至可能是相同的文件——以及 git add-ed 并提交,现在是时候将你的更改和 Bob 的更改结合起来了。

    要执行合并——将某些文件合并为动词——Git 首先找到 合并基础,即您和 Bob 同步的点。然后 Git 运行两个 git diffs:一个从该合并库到 your 的最新提交,一个从同一合并库到 Bob 的最新提交。这显示了“你改变了什么”和“Bob 改变了什么”。

    Git 然后尽最大努力合并这些更改(包括,在本例中,找出并遵循文件重命名,并找出如果只有 一个 时该怎么做你们中的一些人重命名了一些文件——但大多数合并冲突不包括文件重命名,除非你编写了大量的 Java 代码......)。但有时,Git 自己无法做到这一点。在这种特殊情况下,Git 会将合并工作交还给您,此时您会看到索引中的所有 slots

    索引槽 1 是 Git 存储文件的 base 版本的位置。这是你们俩开始的通用版本。

    索引槽 2 是文件的 HEAD--ours 版本。 (有时也称为“本地”版本。)

    索引槽 3 是文件的另一个或 --theirs(或有时是“远程”)版本。

    这几乎就是它的全部内容:三个插槽包含三个版本,您最终会得到“未合并的路径”。工作树中的文件包含 Git 最初的合并工作,以及冲突标记和 --ours--theirs 版本的一些混搭。如果您将 merge.conflictstyle 设置为 diff3,Git 还将包含 base 版本文件中的部分,存储在索引槽 1 中。现在由您来解决合并问题。 p>

    确定正确的分辨率并更新文件的工作树版本后,您必须git add 路径。这会将工作树版本存储到索引槽 0 中,清除槽 1-3 中的三个条目。由于 slot 0 保存了正常的、待提交的版本,因此文件现在可以提交了。

    对于根本没有更改的文件,只是你们中的一个人更改了某些内容, Git 认为它正确地结合了您的更改和 Bob 的更改,那些文件已经在工作树和(零槽)索引中更新。如果结果与当前的HEAD 提交不同,git status 会将文件显示为“要提交的更改”。

    最后几位

    我在上面说过,这就是几乎的全部。关于索引槽,最后要记住的几件事是:

    • 有些插槽可能是空的。假设您 Bob 都添加了一个文件。在这种情况下,您会遇到“添加/添加冲突”。什么版本的文件是通用基础版本?当然没有:你们都添加了一个 new 文件。所以在这种情况下,基本插槽(插槽 1)是空的。

      如果您删除一个文件而 Bob 更改了它,也会发生同样的情况。在这种情况下,--ours 插槽(插槽 2)是空的,而插槽 1 和 3 保存基本版本和 Bob 的版本。由您决定是保留 Bob 的版本、删除文件还是使用第三种变体,但同样只有三个插槽中的两个被填充。

    • 如果你们中的一个或两个重命名一个文件,则三个槽中的文件版本可能来自早期提交中具有不同名称的文件。例如,您的输出显示:

          renamed:    app/OldName.php -> app/NewName.php
      

      这里没有冲突,但如果有冲突,至少有一个app/NewName.php 的插槽将由其他提交版本的app/OldName.php 填充。

      这主要在您查看旧版本时很重要。如果在单独的克隆或工作树中签出其中一个文件尚未重命名的提交,或者如果您使用git show &lt;commit&gt;:app/OldName.php 查看文件而不签出,则必须使用 old 名称,只要它有旧名称。但是,如果您使用git checkout --oursgit checkout --theirs 将这两个版本中的一个提取到工作树中,则必须使用 new 名称,因为索引现在将文件存储在 new名字。

    • 如果您这样做使用git checkout --oursgit checkout --theirs 分别获取您或 Bob 的文件版本,这不会解析文件,但会破坏 Git 的尝试将它们合并到工作树中。如果要恢复 Git 合并它们的尝试,请使用 git checkout -m。请注意,所有这些都会覆盖文件的工作树版本,同时保留三个未解析的索引槽。

    • 不过,奇怪的是,如果您 git checkout &lt;commit-id&gt; -- &lt;path&gt; 从某个特定提交中获取文件的旧版本,那么 覆盖 索引:它将提交的文件版本复制到索引槽零,破坏槽 1-3 条目。该文件现在似乎已解决!同样,您可以使用git checkout -m 恢复未解决的状态。 (当然这会覆盖工作树版本。)

    • 同样,如果您在文件还没有完全完成的情况下错误地使用git add 解析文件,您可以git checkout -m 取消解析它 - 当然,这会覆盖工作 -树版本。如果您已经完成了大部分解析,那么您不妨完成解析并重新git add 结果。这将使用从工作树中新复制的版本替换零槽索引条目:文件保持解析,但准备下一次提交的版本更改为最新的git add-ed 版本。

    【讨论】:

    • 好的,这个答案显然深入地涵盖了我的问题。非常感谢你,@torek!
    【解决方案2】:

    我通常会做后一个,并且没有遇到过它。

    我认为这取决于您要实现的目标。

    如果您想明确提及您已准确解决冲突的文件是什么,您可以执行第一个。否则你可以做另一个。

    【讨论】:

      【解决方案3】:

      “要提交的更改”列表中命名的文件已经在暂存区(也称为索引)中。
      Git add 是您用来将工作放入索引的工具,它告诉 git 您希望它们包含在提交中。 因此,已经暂存的文件的 git add 将是多余的。

      仅当文件在两个列表中都列出时才需要在“待提交”列表中额外添加文件(如果您暂存文件然后对其进行更多修改,有时会发生这种情况)。

      【讨论】:

        猜你喜欢
        • 2012-04-07
        • 1970-01-01
        • 2021-01-20
        • 1970-01-01
        • 2015-10-15
        • 2014-11-24
        • 2021-05-07
        • 2017-05-10
        • 2021-07-28
        相关资源
        最近更新 更多