Master 合并 master 到 branch 后包含来自 branch 的更改

Master contains changes from branch after merging master into branch

我最近在 master 的基础上创建了一个 b运行ch,branchA 来开发一个功能。在开发此功能时,其他提交被推送到 master。我想将这些更改带入 b运行ch,所以在 branchA 中,我 运行

git merge master 

然后我在此基础上进行了更改 (B)。然而,后来我意识到我将 master 合并到 b运行ch 中很糟糕,所以我使用

恢复了提交
git revert [hash of merge of master in branchA] -m 1

然后我重新应用了 B 的更改,并提交了它。最后我把master重新合并成branchA.

我对这次合并很满意,所以我想把 branchA 的变化带入 master。令我惊讶的是,更改已经在 master 中。当我查看 master 和 运行

git merge branchA

我看到了

Already up to date.

这里发生了什么?

我来自 SVN 背景,所以我预计需要将 branchA 合并回 master,但看起来这似乎是自动发生的?这种行为与快进有关吗?如果我不希望这种行为发生怎么办(即将更改从 master 拉入 b运行ch 而不让 b运行ch 的更改溢出回 master) .

提前致谢!

masterbranchA 开始,每个都有一些提交,并且 branchA 已签出(显示为 *):

m1 - m2 - m3     <--- master
 \ 
  a1 - a2       <--- branchA*

[编辑: 根据评论更新了合并结果,以表明 master 不会自动前进到合并提交]

然后将master合并到branchA,显示为merged commit a2m3:

m1 - m2 - m3        <-- master
 \          \ 
   a1 - a2 - a2m3   <-- branchA*

恢复合并只是应用 "undo" 的更改,它不会撤消实际合并 - 显示为 a2m3':

m1 - m2 - m3      <-- master
 \         \      
  a1 - a2 - a2m3 - a2m3' <-- branchA*

并且由于您在 branchA 仍然签出的情况下进行了此还原,因此 branchA 引用将指向新提交,而 master ref 仍指向 m3 提交.

然后您添加了另一个提交:

m1 - m2 - m3      <-- master
 \         \      
  a1 - a2 - a2m3 - a2m3' - a3 <-- branchA*

最后,当你检出master并合并到branchA时,如你所料,这只是一个快进,它转发master指向与相同的提交branchA。这是可能的,因为从 m3 到 a2m3 的合并 link 仍然存在(还原没有删除它),所以 master 被认为是 a3 的父提交(有一个完整的链到a3) 并且可以快进到它。

m1 - m2 - m3  
 \         \      
  a1 - a2 - a2m3 - a2m3' - a3 <-- branchA / master*

这是您尝试将 branchA 合并到 master 的位置,但得到的响应是 "Already up to date"。

现在,在第二次合并尝试之前,如果您已经签出 master 并在合并到 branchA 之前至少提交了一次,或者其他人已经提交 master遥控器,然后将其拉下,然后您的分支将再次发生分歧(想想 m3 右侧的新 m4 提交)。如果发生这种情况,从 branchAmaster 的合并将是完全合并,而不仅仅是快进。


如何考虑分支

我在思考分支方面的突破在于,分支实际上只是对提交的引用——从技术上讲,所有父提交都与之相关。当您合并两个分支时,您只是在创建一个具有两个父级而不是一个父级的提交,并且此时没有两个分支,只有一个 - 甚至过去分开的提交系列 masterbranchA,不再分开 - 它们已经真正合并,两个分支现在都引用它们。


你还能做什么?

根据我认为您想做的事情,您可以这样做:

警告:如果您在推送到其他人 (tm) 可以访问的遥控器后更改历史记录,则有 "Bad Things That Can Happen (tm)"...但至少在这种情况下,它只会正在重写 branchA 历史,而不是 master

  1. 而不是恢复 masterbranchA 的合并,只需将 branchA 重置为之前的提交 a2:

    git reset --hard <hash of a2>
    

    像这样重置会删除对 a2m3 的所有引用,因此它会有效地从您的存储库中删除。它仍将在您的存储库中保留一段时间,但除非您将哈希值保存在某处,否则将无法访问它。 Git 像这样跟踪提交一段时间,然后垃圾收集并删除它们,如果它们没有被重用足够长的时间。

  2. 此时你会:

    m1 - m2 - m3   <-- master
     \
      a1 - a2      <-- branchA
    

    和合并前一样。