nod*_*bqs 2 git merge logging commit
我有两个生成日志的 git 分支,如下所示:
Branch A
commit xyz @ 11:00 am
commit yut @ 11:10 am
commit mot @ 11:30 am
Branch B
commit xyz @ 11::00 am
commit shu @ 11: 20 am
commit yam @ 11: 40 am
Merge Branch B to Branch A
Run Code Online (Sandbox Code Playgroud)
现在,当我检查分支A的日志时,显示如下:
Branch A
commit xyz @ 11:00 am
commit yut @ 11:10 am
commit shu @ 11: 20 am
commit mot @ 11:30 am
commit yam @ 11: 40 am
commit merge Branch B 11:50 am
Run Code Online (Sandbox Code Playgroud)
但是当我检查 shu 的提交对象时,它的父哈希是 xyz 而不是 yut (尽管 yut 在日志中位于它前面)。
git log 功能是否只是读取两个分支的提交历史记录(通过合并提交),然后按提交的“时间”顺序显示它们?
世界各地每台计算机上当地时间的差异不会扰乱这个顺序吗?
除了LeGEC 的答案之外,值得考虑的是如何git log 显示提交。这很重要,因为git log实际上确实实现了其中许多选项。
请记住,每个提交本身都使用唯一的哈希 ID 进行编号,并且每个提交都存储其父(前驱)提交的哈希 ID\xe2\x80\x94 的数字\xe2\x80\x94 。大多数提交都有一个父提交,它会产生一个漂亮、简单的线性(但向后看)提交链:
\n... <-F <-G <-H\nRun Code Online (Sandbox Code Playgroud)\n链中的最后一次H提交在哪里。这里的大写字母代表提交的实际哈希 ID(无论是什么)。commit 的内容分为两部分:HH
H存储了早期提交的实际哈希 ID G。那么,我们说该提交H 指向较早的提交G。Git 使用哈希 ID 在其存储库中所有 Git 对象的大数据库中查找实际提交,因此只要我们给出 Git 哈希 ID H,它就可以使用它来读出内容,包括哈希 ID G。然后它有一个 hash ID G,它可以用它来读出G\ 的内容,其中包括 hash ID F,它可以用它来读取F\ 的内容,等等。
HGit 获取hash ID 的地方是从分支名称:
... <-F <-G <-H <--master\nRun Code Online (Sandbox Code Playgroud)\n例如。我们说分支名称指向链中的最后一次提交。
\n合并提交的特殊之处在于它有两个父项,而不是单个父项。也就是说,合并提交(一如既往地向后)指向两次提交,而不是一次:
\n...--I--J <-- branch1\n \\\n M <-- merged\n /\n...--K--L <-- branch2\nRun Code Online (Sandbox Code Playgroud)\n在这里,我们创建了一个merged指向 commit 的分支名称M。当我们一次处理一个提交时,我们可以从M向后退到或 J 之一(正如 Git 倾向于做的那样)。 L
但是,如果我们想同时git log查看提交和呢?如果我们被迫一次处理一个提交\xe2\x80\x94,就像我们经常做的那样\xe2\x80\x94,我们将如何管理呢?J L
Git 使用的方法是将提交哈希 ID 放入队列,或者更具体地说,优先队列]( https://en.wikipedia.org/wiki/Priority_queue )。也就是说,如果我们在分支上merged运行git logGit:
使用名称merged查找M提交哈希 ID,并将其放入M队列中。队列现在只有一个条目。
从队列中取出第一个提交(使队列为空)并检查它。这个提交是一个合并提交,所以git log不会打印太多关于它的信息,至少默认情况下是这样的,也就是说,如果你要求补丁,git log -p你不会得到一个\xe2\x80\x94,但它确实如此将父母双方放入队列中。
由于队列具有排序属性\xe2\x80\x94,因此优先级较高的提交会先于较低优先级的提交\xe2\x80\x94,因此优先级决定接下来将显示哪个J或。L
从队列中取出第一个提交(在队列中留下一个提交)并检查它。此提交,无论是J或L,都是具有单父项的普通提交,因此 Git 会打印它并包含一个补丁(如果您需要的话)。1 然后 Git 将此提交的父级(无论是哪个父级)放入队列中(以便队列中再次有两个条目)。
重复上面的“从队列中获取第一个提交并使用它”直到队列最终为空\xe2\x80\x94这可能需要很长时间! \xe2\x80\x94或者你告诉Git退出。
\n因此,您看到提交的顺序取决于您设置的优先级。
\n不过,除了各种排序选项之外,还有一个非常重要的选项 ,--first-parent它会影响 Git 处理合并提交的方式。特别是,我们在上面的步骤 2 中看到,Git 将合并提交的双亲放入M队列中。如果我们使用--first-parent,Git不会将父项都放入队列中。相反,Git 仅将的第一个父级M放入队列中。
因此,合并的第一个父级非常重要。但哪位父母是第一位呢?答案取决于谁进行合并,如何进行合并。
\n当你跑步时:
\ngit checkout somebranch\ngit merge otherbranch\nRun Code Online (Sandbox Code Playgroud)\nGit 实际上会进行合并提交,例如M,新合并提交的第一个父级是您在步骤中签出的提交:进行合并之前git checkout的最后一次提交。somebranch第二个父分支\xe2\x80\x94git log --first-parent将忽略\xe2\x80\x94,这是另一个分支的最后一次提交(即在您运行时git merge)。所以如果你有:
...--G--H--I <-- somebranch (HEAD)\n\n ...--J--K--L <-- otherbranch\nRun Code Online (Sandbox Code Playgroud)\n\xe2\x80\x94(HEAD)这里表示您执行了git checkout somebranch并获得了提交I\xe2\x80\x94 并运行git merge otherbranch,新的合并提交将把提交I作为其第一个父级,并L作为其第二个父级:
...--G--H--I--M <-- somebranch (HEAD)\n /\n ...--J--K--L <-- otherbranch\nRun Code Online (Sandbox Code Playgroud)\n请注意,M现在是最后一次提交somebranch,并且提交J-K-L现在在两个分支上。因此,除非您使用,否则该git log命令将显示提交,这会明确排除这些提交,因为它们来自侧分支。J-K-L --first-parent
请注意,使用git pull可能会导致某些人所说的“狐步合并”,其中显示您不想git log --first-parent看到的提交,而不是您所做的提交。这是因为将您的(本地)分支视为主线,而不是将其他 Git 分支视为主线,并将您的工作视为功能分支。另一方面,这可能是您更喜欢的顺序。作为控制者\xe2\x80\x94,即进行合并的人\xe2\x80\x94,您可以决定是否有偏好,如果有,该偏好是什么。git merge
如果你想查看哪个提交是哪个提交的父提交,如果添加 --graph 选项,事情应该会更清楚:
git log --graph
Run Code Online (Sandbox Code Playgroud)
关于提交的显示顺序,请参阅以下内容中的提交顺序部分git help log:
默认顺序是:
--日期顺序
在显示所有子项之前不显示父项,但否则按提交时间戳顺序显示提交。