首页 > 解决方案 > 关于 git merge 的一些问题

问题描述

git fetchand之后git merge,我注意到会有一个特殊的条目要求Mergegit log.

例如,

commit COMMITID (HEAD -> localBranchName)
Merge: XXXXXXXXXX YYYYYYYYYYY
Author: XXX
Date:   XXXXXXX
Merge remote tracking branch into .... 

我应该如何Merge在上面的提交日志中解释?

随之而来的另一个问题git merge是,在这次 git 合并之后,我看到了以下历史记录git log

The merge commit to bring remote changes

The new feature commit in the local branch

The commit since the first checkout

如果我发出问题git push,git 是否足够聪明,知道它只需要推The new feature commit in the local branch送到远程?如果不是,那么实现这一目标的正确方法是什么?(我的新功能提交与 带来的远程更改没有任何冲突git merge,我只是担心带来的提交git merge也会出现在远程的历史中)。

标签: git

解决方案


这不是真正的条目;这是一个描述

当您运行时git merge,Git 可以1做出与大多数普通提交以一种特定方式不同的提交。大多数普通提交存储单个提交的原始哈希 ID。这个父级是这个提交的直接前身。合并提交的特别之处在于它存储了至少两个(通常正好是两个)父提交的哈希 ID。

请记住,Git 与文件无关,也与分支无关,真的。Git 的真正意义在于提交提交存储,作为他们的主要数据,快照——每个文件的冻结副本,当你做出一个特定的提交时它的状态——加上一些元数据,包括谁做出了提交(姓名和电子邮件地址),什么时候(日期和时间戳),以及原因(日志消息)。每次提交中还有一个关键项,即提交的parent 或 parents,元数据格式灵活,可以容纳额外的信息,例如日志消息的文本编码(如果你不指定,Git 假定为 UTF-8它)。

每个提交都有自己唯一的哈希 ID。没有其他提交可以具有哈希 ID:一旦将其分配给提交,就意味着提交 - 永远,或者至少只要该提交继续存在。此外,此哈希 ID 是通用的:每个Git 都同意提交具有哈希 ID。

Git 中的分支名称仅包含一个提交的原始哈希 ID。根据定义,这一次提交是分支的尖端。但是这一次提交保存了其父提交的哈希 ID,即,之前某个时间点作为分支尖端的提交。该父级持有其父级的哈希 ID 是之前提交的提示,依此类推。

当你运行时git log,它从当前提交开始——这通常是一个分支的尖端,因为你git status会说你“在”一个分支上——并向你显示那个提交。然后它向后退一步到该提交的父提交,并显示父提交。然后它向后移动一步,依此类推:

... <-F <-G <-H   <-- master (HEAD)

在这里,我们在分支上master。该名称master包含 commit 的真实哈希 ID(无论它是什么——一些大而难看的字母和数字字符串)H,它是分支中的最后一个提交。CommitH保存其 parent 的哈希 ID G。我们说那个master 指向 HH指向GG当然拥有另一个父哈希,所以G指向F,它指向另一个更早的提交,依此类推。

运行git log将显示 commit H、then G、thenF等。

合并提交有两个父级:

          I--J
         /    \
...--G--H      M--N   <-- master (HEAD)
         \    /
          K--L

在这里,git log将显示N,然后M,然后——好吧,现在它有问题了。它会注意到这M是一个合并提交,并且有两个父级,并为您提供 和 的哈希 ID 的缩短 J版本L。然后它将继续向您显示J或之一L。然后它将继续向您显示它尚未向您显示的两者中的一个或另一个IK然后它会再次继续前进——最终它会向你展示历史的所有分支——以及表演I-J、和、等等。K-LHG

当遇到这样的合并提交时,使用 访问提交的确切顺序git log是您可以控制的,在某种程度上,使用--date-order,--author-date-order--topo-order. 但是查看这些内容的最佳方式是使用git log --graph图形查看器,它不仅显示提交,还显示它们的连接。

请注意,这些提交您存储库中的历史记录。在 Git 中,提交是历史;历史只不过是提交(或其中一些选定的子集)。

如果我发出问题git push,git 是否足够聪明,知道它只需要将本地分支中的新功能提交推送到远程?

您需要知道的主要事情是git push发送提交,然后必须要求其他 Git 设置一些名称,人们可以通过该名称找到提交。所以当你运行时git push,你选择了两件事:

  • 您身边的特定提交,例如由您当前分支命名的提交,以及
  • 另一个Git(您要向其发送提交的那个)应该设置的名称。

您可以只运行git push origin master,或者git push根本不使用任何参数,让 Git 使用您的默认分支(无论它是什么)来指定这两者。Git 会找到分支的提示提交(哈希 ID 在您这边的分支名称中的那个),并将该提交发送到另一个 Git。

你的 Git 刚刚发送的提交有一个父哈希 ID,或者在这种情况下,因为它是一个合并提交,所以有两个父哈希 ID。另一个 Git 可以立即判断它是否有父提交。如果没有,它也会向你的 Git 询问这些。如果是这样,它就完成了。如果它需要另一个或两个提交,它会获取它们并检查它们的父 ID,并在需要时获取这些提交,依此类推。

结果是,在您的 之后git push,您的 Git 不仅发送了您指定的一个特定提交,而且还发送了导致该提交所需的所有历史记录。然后他们的 Git 会检查请求,在这种情况下,就是将他们的分支名称设置为与您的匹配。如果他们认为没问题,他们会接受你的推动。如果不是,他们会拒绝它。

通过分支名称(<code>git push origin master 或类似名称)成功推送的最终结果是它们master现在与您的匹配master:它存储相同的原始提交哈希 ID,并且从该哈希 ID 中,两个 Git 将找到相同的集合的提交。两个 Git 现在都包含相同的历史记录。


1我们必须在这里使用can而不是does 一词,因为虽然git merge有一项工作被描述为“合并”,但有很多方法可以完全失败,或者在没有实际合并任何内容的情况下完成工作。你做了一个需要做实际工作的合并,所以它做了,结果做了一个合并提交。


推荐阅读