代码之家  ›  专栏  ›  技术社区  ›  Robin

合并后分支的Git历史记录

  •  5
  • Robin  · 技术社区  · 7 年前

    我对git在合并后如何存储历史有点困惑。

    我已合并分支 A 至分支机构 B 成功地现在,当我转到一个文件时,在分支中 B ,这是合并的一部分,我看到了分支的文件的所有历史记录 A. 但我没有看到branch的任何历史记录 B . 分支的文件的历史记录在哪里 B 去了?

    我合并的方式是通过 git merge <branch> 所以在这种情况下,我在branch B 并已使用 git merge A .


    例如,在分支中 A. 我有以下承诺: a , aa , aaa 对应不同的文件。

    在分支中 B ,我有以下承诺: b , bb , bbb 对应不同的文件。

    现在当我合并分支时 A. 进入分支机构 B ,我在树枝上看到的一切 B git log , aa公司 , aaa级 历史我看不到我的 b 历史

    本质上,当我合并时,我希望我的合并是线性的 A. B 那么我想让历史有所有的分支 B 历史,在历史之上,它将是刚刚发生的合并,类似于SVN的做法。

    我当前的git日志历史非常混乱。

    2 回复  |  直到 7 年前
        1
  •  11
  •   torek    4 年前

    TL;博士

    历史不是 跑了 ,Git不是 显示

    在Git中,历史 提交集。没有文件历史记录!

    当您运行以下命令时 git log dir/sub/file.ext ,或就此而言, git log dir/sub git log . 在中时 dir/sub ,Git将 合成 (临时)文件历史记录,从真实历史记录(提交集)中提取一些子历史记录。这个合成过程故意放弃一些提交。例如,它会下降 全部的 不影响您询问的任何文件的提交。但默认情况下,它的下降幅度远不止这些,通过一些 git log 电话 历史简化 .

    比较长的

    每个提交都有一个唯一的哈希ID git日志 例如,输出。哈希ID实际上只是提交内容的加密校验和。

    每次提交都存储文件的快照(哈希ID)–Git将其称为 . 合并提交也是如此:合并提交与任何其他提交一样,都有一个树。

    每次提交还存储您的姓名(作者和提交人)、电子邮件地址和时间戳,以便Git可以向您显示这些信息。它存储一条日志消息——无论您给它什么——以便Git也可以显示它。

    Git存储在Committ中的最后一件事第二件事,真的,就在 tree 是的列表 父母亲 通过其唯一哈希ID提交。

    线性历史很容易

    在处理普通的非合并提交时,查看历史记录非常简单。我们只是从 最近的 提交,由以下分支名称标识 master ,并向后工作。分支名称包含最后一个提交的哈希ID 提示 分支机构的名称 指向 承诺:

    ... <--1234567...   <--master
    

    如果提交 1234567 主人 , git日志 可以显示您的承诺 1234567 ... 并提交 1234567 其中包含正确提交的哈希ID 之前 1234567 .

    如果我们将真正的散列ID替换为单个字母,为了让事情更简单,我们会得到如下结果:

    A <-B <-C <-D <-E <-F <-G   <--master
    

    犯罪 G 返回点以提交 F ,它指向 E ,依此类推,直到我们到达第一个提交,提交 A . 此提交不指向任何地方–it 不能 ,这是第一次承诺;它不能有父对象,所以这就是历史结束(开始)的地方,在时间的开始。Git调用 A. 提交:没有父级的提交。

    很容易显示线性历史,从时间的终点开始,从起点结束。Git只是一次选择一个提交并显示它。这就是:

    git log master
    

    does:它从一个commit开始,由 主人 ,并显示它,然后显示一个提交的一个父级,然后显示之前的一个,依此类推。

    当您让Git显示提交时,您可以–实际上,您几乎总是–让Git将其显示为 色斑 ,而不是作为快照。例如, git log --patch 这样做。为了将提交显示为补丁,Git只需查看提交的 父母亲 首先是的树,然后是提交树,并将两者进行比较。因为两者都是快照,所以从父快照到子快照的任何更改都必须是使子提交的人实际执行的操作。

    非线性历史更难

    既然我们知道Git是反向工作的,那么让我们看看更复杂的历史,包括包含实际合并提交的历史。(我们不要因为 git merge 不总是合并!)

    A. 合并提交 就是至少有两个父母的承诺。在大多数情况下,您不会看到包含三个或更多父项的提交它调用这些 八达通合并 ,它们不会做任何普通合并无法完成的事情,所以八达通合并主要是为了炫耀你的Git fu.:-)

    我们通常通过以下方式进行合并 git checkout somebranch; git merge otherbranch ,我们可以这样绘制结果提交链:

    ...--E--F--G------M   <-- master
             \       /
              H--I--J   <-- feature
    

    现在,假设你跑 git log master (注:否 --patch 选项)。Git当然应该显示您的提交 M 第一但Git接下来会显示哪个提交? J G ? 如果它显示其中一个,那么之后应该显示哪一个?

    Git对这个问题有一个通用的答案:当它向您显示合并提交时,它可以添加 二者都 提交到“提交尚未显示”队列的父级。当它显示普通的非合并提交时,它会将(单个)父级添加到同一队列。然后它可以在队列中循环,显示您一次提交一个,并将其父级添加到队列中。

    当历史是线性的时,队列中一次有一个提交:一个提交被删除并显示,现在队列中有一个父级,您可以看到父级。

    当历史记录有一个合并时,队列以一个提交开始,Git从队列中弹出提交并显示它,然后将双亲放入队列中。然后Git从两个父母中挑选一个给你看 G J ,并放置 F I 进入队列。队列中仍有两个提交。Git弹出一个并显示提交,然后打开另一个。

    最终Git试图 F 在队列上,当 F 已在队列中。Git避免了添加两次,因此最终队列深度会减少到再次提交一次,在本例中显示 F , E , D 等等(这里的细节有点复杂:队列特别是 priority queue 优先权由其他 git日志 排序参数,因此有不同的方法可以实现。)

    您可以使用查看连接 git log --graph

    如果您添加 --graph 到您的 git日志 命令时,Git将绘制一个有点粗糙的ASCII艺术图,其中的线将子提交连接回其父级。这非常有助于告诉您,您查看的提交历史毕竟不是线性的,即使 git日志 一次显示一个提交(因为它必须)。

    显示合并提交

    我在上面提到过 -p --修补程序 , git日志 将显示什么 改变 在提交中,将父快照/树与子快照/树进行比较。但对于合并提交,有 (甚至更多)父母:没有办法让你看到 这个 父母对孩子,因为至少有 父母

    什么 git日志 默认情况下,就是完全放弃。它根本没有显示补丁。其他命令执行更复杂的操作,您可以 git日志 也可以这样做,但请注意,默认值是 git日志 放弃这里。

    History Simplification (这是一个可单击的链接 git日志 文件)

    当你跑步时 git log file.ext ,Git将故意跳过任何差异(通过比较父级和子级获得)未触及的非合并提交 file.ext . 这很自然:如果你有这样一条链条:

    A--B--C--D--E   <-- master
    

    而您更改了(或首次创建) 文件提取 当您进行提交时 A. E ,您只希望看到这两个提交。Git可以通过为 D -vs公司- E 看到这些 文件提取 已更改(因此应该 显示 E ),然后继续 D . 这个 C -vs公司- D 比较显示没有变化 文件提取 ,所以Git 不会 显示 D ,但它会 C 在优先队列中,继续访问 C . 这也没有改变文件,所以Git最终会继续 B ,没有更改,Git移动到 A. . 为了进行比较,中的所有文件 A. 总是新的-这是任何根提交的规则;所有文件都已添加,所以Git会显示 A.

    不过,我们刚刚看到,默认情况下 git日志 不喜欢为合并计算修补程序。这太难了!所以 git日志 通常不会在此处显示合并。然而,它确实试图简化提交图的任何部分。正如文档所述,默认模式:

    如果最终结果相同,则修剪一些分支。。。

    如果提交是一个合并,并且[文件与中的文件相同]是一个父级,则只遵循该父级。。。否则,请跟随所有家长。

    所以在合并提交时 M 在我们的图中,Git将进行快速检查:is 文件提取 在中相同 M 如中所示 G ? 如果是,添加 G 到队列。如果不是,在 M 如中所示 J ? 如果是,添加 J 到队列。否则,即:。, 文件提取 不同于 M 比在 二者都 G J 添加两者 G J 到队列。

    历史简化还有其他模式,您可以使用各种标志选择这些模式。这个答案已经太长了,所以我将把它们留给文档(参见上面的链接)。

    结论

    你不能从什么中得出太多的推论 git log -- path 显示了Git执行的历史简化。如果你想看 每件事 ,考虑运行 git log --full-history -m -p -- path 相反这个 -m 选项拆分的每个合并 git diff 目的(这与 -p 选项),以及 --full-history 强制Git始终跟踪所有父级。

        2
  •  2
  •   Alejandro C.    7 年前

    一切都应该还在那里。尝试使用查看 git log --graph .