合并两个分支和Git历史 [英] Merging two branches and Git history

查看:258
本文介绍了合并两个分支和Git历史的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



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

 分支#1:----(分支)---- C1 ---------- C2 -------(合并)------ C5 
\ /
\ /
\ /
分支2:----------- C3 ---------- C4

一旦两个分支合并后,分支1的历史如何查看C5(提交#5)? Git将合并所有的历史记录给我以下内容:

 分支机构#1:------ ---------- C1 ---- C3 ---- C2 ---- C4 -------------- C5 

这是正确的理解吗?

如果是这样,万一发生紧急情况,我该如何撤销合并,因为所有来自分支#2的历史记录都将与分支#1的历史记录交织在一起。 解决方案

tl; dr



在两个分支之间有一个线性历史记录只能通过重新绑定一个分支在另一个分支之上<合并。如果你合并了两个分支的分支,Git将通过创建一个合并提交来加入两行历史记录。



合并提交



在Git中,提交通常包含对父项的引用。 合并提交 是一种特殊的提交方式,可引用两个或更多父母。



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


  1. 第一父母 C2 ,即分支上的提交
    ,其他分支合并为,即 branch1 第二个父是 C4 ,这是合并的分支上的提交,即 branch2

当您执行 git log on branch1 Git会按照以下两行历史记录向您显示:

  C1  -  C2  -  C5 < -  branch1 
/
C3 - C4 < - branch2

如果您在 branch2上执行 git log ,历史线将被交换:

  C3  -  C4 < -  branch2 
/
C1 - C2 - C5 <分支1



不合并提交合并



在这种情况下,两个分支之间的提交看起来在同一行历史记录中(不涉及合并提交)是一个 rebase 的结果。


$ b $在 branch1 之上重新分配 branch2 是一项操作,它是 'em>' 不同于合并两个分支。



合并完成时:

  git checkout branch1 
git merge branch2

兑换工作是通过以下方式完成的:



<$ p $基本的意思是指: git checkout branch2
git rebase branch1


查找所有co可以从 branch2 但不是 branch1 中获得的mmits,在这种情况下 C3 C4 - 并将它们应用于 branch1

所以最终的历史记录如下所示:



<$ p $ C1> C2-C3-C4 < - 分支2
^
分支1

注意 branch1 仍然指向 C2 - 与它相同的提交在rebase之前做过。由于两个分支之间的历史现在在同一行 ,因此将它们合并:

  git checkout branch1 
git merge branch2

不会创建合并提交。相反,Git只需将 branch1 向前移动,以便它指向与 branch2 相同的提交。此操作称为 fast-转发


要以另一种方式表达,当您尝试合并一个提交与
提交可以通过跟随第一个提交的历史记录到达,
Git通过向前移动指针来简化事情,因为有
没有发散的工作来合并 - 这被称为快进。




撤销合并



撤消合并的方式取决于是否合并是通过 merge commit 完成的。



如果有合并提交,可以通过简单地移动 branch1 指向合并提交的第一个父代:

  git checkout branch1#branch1在合并提交点C5 
git reset --hard branch1 ^#branch1现在指向C 2

如果合并是在重新绑定之后完成的,则事情有点棘手。你基本上需要恢复 branch1 来指向合并之前的提交。如果合并是您所做的最新操作,则可以使用特殊参考 ORIG_HEAD

  git reset --hard ORIG_HEAD 

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

  git checkout branch1 
git reflog# branch1在合并之前指向
git reset --hard HEAD @ {n}#移动分支1以指向reflog中的条目


Please can somebody inform me what Git does in terms of history when merging two branches.

If I have two branches which are both actively being developed on and both contain commits, which is similar to the following timeline:

Branch #1: ----(branch)----C1----------C2-------(merge)------C5
                  \                             /
                   \                           /
                    \                         /
Branch #2:           -----------C3----------C4

How does the history for Branch 1 look at C5 (commit #5) once both branches have been merged? I am under the impression Git will merge all history to give me the following:

Branch #1: ----------------C1----C3----C2----C4--------------C5

Is this the correct understanding?

If so, in the event of an emergency, how do I undo the merge, because surely all history from branch #2 will be entwined with branch #1's history.

解决方案

tl;dr

Having a linear history between two branches can only be done by rebasing one branch on top of the other before merging. If you just merge two branches that have diverged, Git will join the two lines of history by creating a merge commit.

Merging with merge commits

In Git, a commit normally holds a reference to one parent. A merge commit is a special kind of commit that references two or more parents.

In your example, the merge commit C5 has two parents:

  1. The first parent is C2, that is the commit on the branch where the other branch was merged to, i.e. branch1
  2. The second parent is C4, that is the commit on the branch that was merged, i.e. branch2.

When you do git log on branch1 Git will follow both lines of history showing you this:

C1--C2--C5 <- branch1
        /
  C3--C4 <- branch2

If you do git log on branch2, the lines of history will be swapped:

     C3--C4 <- branch2
         /
C1--C2--C5 <- branch1

Merging without merge commits

The scenario in which the commits between the two branches appear to be in the same line of history – with no merge commit involved – is the result of a rebase.

Rebasing branch2 on top of branch1 is an operation that's conceptually different from merging the two branches.

While merging is done with:

git checkout branch1
git merge branch2

Rebasing is done with:

git checkout branch2
git rebase branch1

which basically means:

Find all the commits that are reachable from branch2 but not from branch1 – in this case C3 and C4 – and apply them on top of the latest commit in branch1.

So the final history will look like this:

C1--C2--C3--C4 <- branch2
     ^
     branch1

Notice that branch1 still points to C2 – the same commit as it did before the rebase. Since the history between the two branches is now on the same line, merging them with:

git checkout branch1
git merge branch2

won't create a merge commit. Instead, Git will simply move the branch1 forward so that it points to the same commit as branch2. This operation is called a fast-forward:

To phrase that another way, when you try to merge one commit with a commit that can be reached by following the first commit’s history, Git simplifies things by moving the pointer forward because there is no divergent work to merge together – this is called a "fast-forward."

Undoing a merge

The way you undo a merge will vary depending on whether the merge was done through a merge commit or not.

If there's a merge commit, you can undo the merge by simply moving branch1 to point to the merge commit's first parent:

git checkout branch1       # branch1 points at the merge commit C5
git reset --hard branch1^  # branch1 now points at C2

If the merge was done after a rebase, things are a bit trickier. You basically need to restore branch1 to point to the commit it did before the merge. If merging was the latest operation you did, you can use the special reference ORIG_HEAD:

git reset --hard ORIG_HEAD

Otherwise you'll have to resort to the reflog:

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

这篇关于合并两个分支和Git历史的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆