合并两个分支和Git历史

合并两个分支和Git历史,git,merge,git-merge,Git,Merge,Git Merge,有人能告诉我Git在合并两个分支时在历史方面做了什么吗 如果我有两个分支,它们都在积极开发中,并且都包含提交,这与以下时间线类似: Branch #1: ----(branch)----C1----------C2-------(merge)------C5 \ / \ / \

有人能告诉我Git在合并两个分支时在历史方面做了什么吗

如果我有两个分支,它们都在积极开发中,并且都包含提交,这与以下时间线类似:

Branch #1: ----(branch)----C1----------C2-------(merge)------C5
                  \                             /
                   \                           /
                    \                         /
Branch #2:           -----------C3----------C4
合并两个分支后,分支1的历史如何看待C5(提交5)?我的印象是Git将合并所有历史,以提供以下信息:

Branch #1: ----------------C1----C3----C2----C4--------------C5
这是正确的理解吗


如果是这样,在紧急情况下,如何撤消合并,因为分支2的所有历史记录肯定会与分支1的历史记录纠缠在一起。

要撤消合并,可以使用:
git checkout banrch\1;git reset——硬c2哈希

合并实际上不会创建您描述的内容,合并将创建一个包含两个父提交的提交。在提交中,分支2的更改将在主分支上重播。这解释了发生的情况:

您描述的是当您将分支#2重设为分支#1:(某种程度上)时发生的情况。你会得到C1,C2,C3,C4,C5和一个重基。重定基时,提交不按时间排序。当您将分支#2重设为分支#1时#2中的每个提交将在该点应用于#1

撤销重基或合并非常简单,只要在提交的情况下将头部重置为合并提交之前,并重置为开始重基之前#1分支中的最后一次提交

最后,我当然不知道您的具体设置,但如果两个分支都有很多积极的开发,我会经常将#2合并到#1中,因为这样做只是偶尔会导致很多冲突

tl;博士 两个分支之间的线性历史记录只能通过在合并之前将一个分支重定为另一个分支的顶部来实现。如果您只是合并两个分叉的分支,Git将通过创建合并提交来连接两行历史记录

使用合并提交进行合并 在Git中,提交通常包含对一个父级的引用。是一种特殊类型的提交,它引用两个或多个父级

在您的示例中,合并提交
C5
有两个父级:

  • 第一个父级是
    C2
    ,即分支上的提交 其他分支合并到的位置,即
    branch1
  • 第二个父级是
    C4
    ,即合并的分支上的提交,即
    branch2
  • 当您在
    branch1
    git日志中执行
    git日志时,git将遵循两行历史记录,向您显示以下内容:

    C1--C2--C5 <- branch1
            /
      C3--C4 <- branch2
    
    无合并提交的合并 在这种情况下,两个分支之间的提交似乎处于同一历史行中,而不涉及合并提交,这是重新基础的结果

    branch1
    之上对
    branch2
    重新定基是通过合并两个分支实现的操作

    合并完成时,请执行以下操作:

    git checkout branch1
    git merge branch2
    
    git checkout branch2
    git rebase branch1
    
    重新定基通过以下方式完成:

    git checkout branch1
    git merge branch2
    
    git checkout branch2
    git rebase branch1
    
    这基本上意味着:

    查找所有可从
    branch2
    访问但不能从
    branch1
    访问的提交—在本例中为
    C3
    C4
    —并将它们应用于
    branch1
    中的最新提交之上

    因此,最终的历史将如下所示:

    C1--C2--C3--C4 <- branch2
         ^
         branch1
    
    。相反,Git只需向前移动
    branch1
    ,使其指向与
    branch2
    相同的提交。此操作称为:

    换句话说,当您尝试将一个提交与一个 通过遵循第一次提交的历史记录可以达到的提交, Git通过向前移动指针来简化事情,因为 没有分歧的工作可以合并在一起——这被称为“快进”

    撤消合并 撤消合并的方式将因合并是否通过合并提交而有所不同

    如果存在合并提交,只需移动
    branch1
    指向合并提交的第一个父级,即可撤消合并:

    git checkout branch1       # branch1 points at the merge commit C5
    git reset --hard branch1^  # branch1 now points at C2
    
    如果合并是在重新基址之后完成的,事情就有点棘手了。您基本上需要恢复
    branch1
    ,以指向合并之前的提交。如果合并是您最近执行的操作,则可以使用:

    否则,您将不得不求助于:


    首先,您需要了解git中的分支只是一个标记。在您的示例中,分支#1将设置为C1,然后是C2,然后是C5(合并后),而分支#2将设置为C3,然后是C4

    然后,如果我理解正确的话,当git说“提交属于分支X”时,这意味着该提交是由该分支或该提交的祖先(直接或间接)标记的当前提交。所以是的,在合并之后,所有提交到C1到C的都属于分支#1

    最后,对于撤消合并,有两种可能:

    • 如果您的合并没有被其他开发人员拉入,则始终可以重置分支#1。重置实际上只是将分支的标记移动到另一个提交。在您的情况下,在分支1上完成签出后,将使用
      git reset C2
      。如果您想摆脱本地修改,可以执行
      git reset--hardc2
      。您必须小心,因为reset是git中极少数能够丢失工作的命令之一

    • 如果合并已被共享,则仍有可能执行还原。还原是一种ew提交,修改会删除对合并的修改。这不是一个完美的解决方案,因为历史将被保留

    有关这些操作的更多信息,请参见:

    我还建议阅读这本电子书,至少是前三章,这本书对git中使用的概念有很好的理解

    这是正确的理解吗

    合并后,branch#1的历史将与您在问题中发布的历史相同,尽管其基础并不是那么简单

    将分支2合并到分支1将“混乱”(不确定这是否
    git reset --hard ORIG_HEAD
    
    git checkout branch1
    git reflog                 # Find the commit that branch1 pointed to before the merge
    git reset --hard HEAD@{n}  # Move branch1 to point to that entry in the reflog