git 令人困惑的图表。 `master` 分支好像有两行?

git confusing graph. `master` branch seems to have two lines?

在 运行 git log 我看到了 st运行ge 图。我会进一步解释。 以下是 git 带图表的日志的输出。

$ git log --graph  --oneline
*   df1834d (HEAD -> master, tag: r-0.1, origin/master) Merge branch 'master' of https://github.com/samshers/graphql-hibernate
|\
| * d56a675 fixed country null issue
* | ee9bb70 fixed country null issue
|/
* 2617f2a hibernate cascade error issue. country field in state table set to null

如您所见,大师本身有两个独立的 b运行ches。为了进一步证实这一点,我 运行

$ git branch --contains ee9bb706c8fcc329fac4acf69ad6b684f1069170
  joincolumn_issue
  ls
  mappedBy
* master

然后

$ git branch --contains d56a6751771b1f62d9ceb0bcce9a2391c004ee44
  joincolumn_issue
  ls
  mappedBy
* master

很明显这两个提交存在于 master 上 - 那么为什么会有两个图表。 我怎么知道 changes 两个提交都存在于 master 上。或者如果其中之一的 changes 实际上存在于 master 上,那么两者中的哪一个?

编辑 - 根据 RY 和 Mark 的回复 (如果颜色代码有更多含义,请同时提示。)
因此,我进一步试图理解为什么提交 (Y) 不是基于先前的提交 (X)(如果 X 在 Y 之前提交)。 git 日志显示 d56a675ee9bb70 同时提交。

commit ee9bb706c8fcc329fac4acf69ad6b684f1069170
Author: itsvamshers <itsvamshers@gmail.com>
Date:   Mon Sep 9 17:24:01 2019 +0530

    fixed country null issue

commit d56a6751771b1f62d9ceb0bcce9a2391c004ee44
Author: itsvamshers <itsvamshers@gmail.com>
Date:   Mon Sep 9 17:24:01 2019 +0530

    fixed country null issue

但是,进一步挖掘可以看出细微差别..

$ git show -s --format="%ct" d56a6751771b1f62d9ceb0bcce9a2391c004ee44
1568030041

$  git show -s --format="%ct"  ee9bb706c8fcc329fac4acf69ad6b684f1069170
1568031643

并且此信息应该足以让 git 将提交按正确的顺序排列。但如果不是,那我想更聪明的做法是有理有据,只是想了解原因和原因。

d56a675 不存在于 ee9bb70 的历史记录中,ee9bb70 不存在于 d56a675 的历史记录中。两者都存在于 master 的历史记录中,因为它们在 df1834d 中重新合并在一起。所有这些就是为什么图中有一个叉子。

他们的两个更改 存在于 master 的历史记录中 ,但这并不意味着合并提交以您可能想要的方式保留了这些更改。你得看看现在的状态再比较。

git show d56a675
git show ee9bb70
git diff 2617f2a..df1834d

此外,如果两个提交相同,或者如果一个是另一个的更新版本(他们的摘要表明),则合并它们可能是一个错误。

听起来混淆是关于分支是什么,以及分支对 "contain" 在 git 中的提交意味着什么。

分支只是指向提交的指针。分支 不是 git 中提交的集合,就像它可能在某些工具中一样。 git 最接近分支 "containing or not containing" 的提交是,该分支的提交是或不是 "reachable"。分支指向的提交是可访问的,就像通过遵循可访问提交的父指针(递归)找到的任何提交一样。

合并是具有两个(或更多)父指针的提交。因此,当您将分支合并到 master 时,该分支的所有提交都可以从 master 访问(通过合并提交的第二个父指针)。所以分支提交是 "contained in" master (即可以从 master 访问)因为你将它们合并到 master 中;这是正常的 git 行为。

如果您只想知道提交时 "on master" 的提交...好吧,git 不会 真正地 跟踪事情就像那样,但你可以做到

git log --graph --one-line --first-parent

现在,如果您做了一些不寻常的事情(例如将 master 合并到一个分支中,然后将 master 快速转发到生成的合并中,这只是一个示例),那么这仍然可能无法完全按照您的意图进行;但如果您遵循相当正常的 branch/merge 策略(并坚持使用 "porcelain" 命令 - 那些旨在供最终用户使用的命令),它应该看起来更像您所期望的。

默认情况下,log 的这种行为跟随进入合并的两个分支是 --graph 选项在 IMO 中有用的主要原因。

无论如何,示例图中显示的所有提交的更改都存在于 master 中,因为它们都显示为可从 master 访问。有一个陷阱 - 这假设合并提交是两个分支的合理合并。如果您使用 ours 合并策略合并,则分支不存在。如果您在解决冲突时做了一些非常奇怪的事情,从分支中撤消了一些更改,那么您有时会遇到所谓的 "evil merge" 并且它撤消的更改不存在。如果你知道你的团队中没有人做过这样的事情,那么你就不必担心了。

您可以依靠 git log 的历史简化来告诉您分支是否在合并中被完全破坏(除非您提供像 --full-history 这样的选项,否则不应显示这样的分支,因为log 将决定它可以在不提及分支的情况下完全解释当前状态),但这可能不是 100% 可靠的,并且在任何情况下 log 的逻辑都无法告诉您是否有邪恶合并 - 所以在某些时候,你必须依赖于你和你的团队遵循合理流程的想法。

或者良好的工具和测试覆盖率;你也可以依靠它。