【问题标题】:Git help to understand merge-base conflictsGit 帮助理解基于合并的冲突
【发布时间】:2019-01-13 18:46:15
【问题描述】:

我在未修改的文件上遇到冲突。合并时更改一行的文件发生冲突。我开始了解可能发生的事情,但仍然无法解决问题。

这是分支结构。

  • 主人
    • current_iteration
      • mapr_autoinit

Master 已经很老了,并且在很长一段时间内都没有从 current_iteration 进行更改。然而,master 已经通过将其他基础直接重新设置到 master 上直接应用了更改。所以从技术上讲,master 和 current_iteration 出现了分歧。我们一直从 current_iteration 分支和标记。我看到的问题是,当我从 current_iteration 合并回我的分支时。基于对 current_iteration 的更改,我得到的冲突比应该发生的要多得多。我可以从 current_iteration 做一个 git diff / git apply 并且它应用得很干净。

当我在 mapr-autoinit 上运行 git show-branch --merge-base 时,我看到提交实际上是几个月前在 master 上的提交。但是,当我检查 git merge-base current_iteration mapr_autoninit 时,我发现版本是最新的,很可能不会有冲突。

从我最近几天看到的情况来看,如果我将 master 合并到 current_iteration 中,提交然后将 current_iteration 合并回 master 似乎是合乎逻辑的。这可能应该解决我的分支合并基础以指向更新的版本。

我也有可能停止跟踪大师。我尝试使用git config --unset branch.master.merge; git config --unset branch.master.remote 停止跟踪主服务器,但这并没有解决我的问题。

这是否是 master 和 current_iteration 出现分歧并且 merge 试图通过重放整个日志来协调合并的问题?

这里还有更多细节。我现在提出一个新问题,因为这个问题更加具体。我将使用有效答案更新两者或删除旧答案,具体取决于哪个是首选。

Git merge resulting in unreasonable conflicts

【问题讨论】:

    标签: git merge git-merge


    【解决方案1】:

    我自己从未发现git show-branch 输出非常有用,我不确定它的用途,也不知道其他人如何成功使用它。

    我也有可能停止跟踪主人......

    这无关紧要。重要的是实际的提交图。任何分支的上游都独立于提交图。

    这是否是 master 和 current_iteration 出现分歧而 merge 试图通过重放整个日志来协调合并的问题?

    没有。 合并基础查找之后重要的是——合并基础提交,即——加上两个分支提示提交。两者之间的一切都无关紧要。

    但是,当我检查 git merge-base current_iteration mapr_autoinit 时,我发现版本是最新的,很可能不会有冲突。

    这通常是开始的方式,因为git merge-base 检查提交图,并使用它来计算合并基础提交。请注意,git merge 默认运行相当于git merge-base --all。如果这会产生 多个 合并基(多个提交哈希 ID),那么您有一种特殊情况。假设您暂时不知道,但最好检查一下。

    找到合并基础提交后,您可以查看git log 输出(请参阅最后一节)并查看合并基础与两个分支提示的关系。 Git 不关心这个——好吧,这不太对:Git 找到合并基础之后(这取决于这个),Git 不再关心它——但你可能会发现它很有帮助。 p>

    找到current_iterationmapr_autoinit 的(单一)合并基础(假设您在这两个分支之一上),下面是Git 所做的:

    git diff --find-renames <merge-base-hash> current_iteration > /tmp/1
    git diff --find-renames <merge-base-hash> mapr_autoinit > /tmp/2
    

    我在此处将这些重定向到/tmp 文件,以便于多次查看和并排查看或其他任何内容,具体取决于您的文件查看器。因为我不知道你要合并的方向——从什么到什么——我只是给这两个文件编号,而不是称它们为“我们的”和“他们的”。请注意,合并更改 步骤在很大程度上是对称的。对于每个文件的每次更改,都有四种可能性:

    • 您触及了这些线条,但它们没有:Git 接受您的更改。
    • 他们触及了界限,而你却没有:Git 接受了他们的改变。
    • 您和他们接触了这些线,但您进行了相同的更改:Git 会复制一份更改。
    • 您和他们接触了这些行,但做了不同的更改:Git 声明了合并冲突,并将两组更改都放入工作树文件中。如果你将merge.conflictStyle 设置为diff3——我强烈推荐这个——Git 也包含合并基础版本,向你展示你和他们之前开始您和他们进行了相互矛盾的更改。

    查看结果,使用合并冲突标记并将通过merge.conflictStyle 包含的基本版本设置为diff3通常就足够了。 (特别是,它有时会显示 Git 有 mis-paired 更改并认为它们发生冲突的情况,而实际上这些更改是针对不冲突的其他区域。)如果不是,它可能有助于查看提交图。

    关于提交图的更多信息

    确实起作用的东西,但可能难以理解,1git log --graph 的输出。包含--decorate --oneline 选项很有帮助,对于这种特殊情况,您需要列出当前分支的名称2 和您打算合并的分支。例如,如果您已签出 mapr_autoinit 并打算运行 git merge master,您可以运行:

    git log --graph --decorate --oneline mapr_autoinit master
    

    Git 将尽最大努力以 ASCII 艺术形式绘制提交图,并添加可选的额外颜色以提供帮助。当然,结果很大程度上取决于图表中的内容。这是来自 Linux 内核的 Git 存储库的 sn-p:

    * 1ffaddd029c8 (HEAD -> master, tag: v4.18-rc8, origin/master, origin/HEAD) Linux 4.18-rc8
    *   a8c199208cd6 Merge branch 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
    |\  
    | * 1b3a62643660 x86/boot/compressed/64: Validate trampoline placement against E820
    * |   2f3672cbf9da Merge branch 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
    |\ \  
    | * | 0a0e0829f990 nohz: Fix missing tick reprogram when interrupting an inline softirq
    | * | 80d20d35af1e nohz: Fix local_timer_softirq_pending()
    * | |   0cdf6d4607df Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
    

    人们可以使用它来追踪自合并基础以来发生的事情。还有更多工具:

    git log --graph --decorate --oneline --boundary mapr_autoinit...master
    

    例如,将向您显示合并的内容(标记为*的提交),以及(由于--boundary)已合并的边界提交(标记为@ 987654344@) 但没有比这更深入的图表。

    对于非常简单的情况(内部分支和重新合并并不可怕的图形),在三点语法中添加 --left-right 有时也很有帮助。对于复杂情况,每条分支都有大量内部分支和合并操作,--first-parent 有时有用,--simplify-by-decoration 有时有用。


    1尽管如此,它仍然值得细读。如果您愿意,可以使用更漂亮地绘制图形的 GUI 或类似工具,但请注意,至少某些 Git GUI 似乎绘制不正确的图形(各种webservices咳嗽)。

    2您始终可以使用名称HEAD(全部大写)代替当前分支名称。例如,全小写适用于 Windows 和 MacOS 上不区分大小写的文件系统,但养成这种习惯并不好。但是,在任何现代 Git 中,单独的 @ 表示 HEAD,因此,如果您愿意,请使用它而不是拼写 HEAD。请注意,当使用两个或三个点语法(A..BA...B)时,完全省略一个名称 also 意味着 HEADHEAD..B@..B..B 是同一事物的三个拼写。

    【讨论】:

    • 我似乎对一个人的合并有疑问。似乎他的合并导致了我的问题,但我不明白它是如何发生的。分支 origin/feature/predict-proxy-plot-endpoints 似乎创造了一个疯狂的合并平台。我试图了解这是怎么回事。
    • 当一个人从某个来源重复合并相当不小心(至少在不关心图表方面)而不是小心(关于图表)rebase(即,复制)承诺使它们成为未来代码考古学家的线性和可理解的。有些人喜欢这种东西——例如,请参阅 Git 本身的 Git 存储库——但在过去 8 年多的时间里,我一直在努力让我工作过的地方的事情更易于管理......
    • 请注意,无论谁进行合并,都可以(尽可能多地)控制最终提交的树。有些人进行有时称为 evil merges 的操作,因为最终的合并提交中包含的内容不是来自两个输入的任一“侧”(与合并基础相比)。这可能是偶然发生的,也可能是故意发生的,有时尽管名称为“邪恶合并”,但这是一件好事。
    • 您还可以尝试重复合并,看看为什么会这样。由于合并取决于合并基础和两个特定提交,因此您可以签出(作为分离的 HEAD)两个提交之一(您好奇的现有合并的两个父级)并运行 git merge &lt;hash-of-other-commit&gt; 并查看Git如何合并这些。如果结果与您感兴趣的合并不匹配,那么进行合并的人一定是通过额外的选项或作为 Evil Merge 或其他方式完成的。
    猜你喜欢
    • 1970-01-01
    • 2012-03-18
    • 2015-10-15
    • 2017-07-24
    • 1970-01-01
    • 1970-01-01
    • 2020-08-23
    • 2018-08-04
    • 2012-05-09
    相关资源
    最近更新 更多