重新绑定树(提交/分支及其所有子项) [英] Rebasing a tree (a commit/branch and all its children)

查看:151
本文介绍了重新绑定树(提交/分支及其所有子项)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  A  -  H(master)
|
\ - B - C - D - E(功能)
|
\- F(新)
|
\- G(其他)

我想重新分行支行所以它取决于 H 而不是 A

  A  -  H(主)
|
\ - B'-C'-D'E'(feature)
|
\- F'(新)
|
\- G'(其他)

简单的概念很难自动完成看来。这已被问及此处此处,但建议的解决方案不适合我。

首先,如前所述, git分支当前分支存在时,输出不是无关紧要的(前缀 * )。但这不是一个障碍,在我的情况下,我可以很容易地提供名称功能 other ,或者确保当前分支是 master



然后我尝试了这些命令:

  git rebase --committer-date-is-author-date --preserve-merges  - 到主要功能^功能
git rebase --committer-date-is-author-date --preserve-merges --onto主要功能^ new
git rebase --committer-date-is-author-日期 - 保留合并 - 主要功能^其他

我最后:

  A  -  H(主)
|
\ -E'(feature)
|
\ - B' - C' - D' - F'(新)
|
\ -B - C - D - G'(other)

绝对不是我想要的!或者,如果我使用 B ^ 而不是特性^ ,那么我也可以得到 B - C - D 功能分支中记录。

所以,有关如何自动完成此操作的进一步建议?

编辑:它适用于此:

  git结账功能
git合并其他
git合并新
git rebase -p主要功能

现在至少树看起来是正确的,我只需在合并之前将分支头移动到它们的右侧提交......这可能是完成:

  git checkout master 
git分支-f新特性^ 2
git分支-f功能特性^ 1
git分支-f其他功能^ 2
git分支-f功能特性^ 1


解决方案

在这些情况下,一个很好的窍门是mer ge(加入)所有分支都是
移入最终的提交节点。之后,使用rebase和
- preserve-merges 选项移动生成的附属子树
(分支集)。



创建一个包含所有分支的封闭子树,公开
2个节点(开始和结束),这些节点被用作分配
命令的输入参数。



封闭子树的末尾是一个人造节点,在移动树之后可以删除
,以及
可能已经存在的其他节点创建用于合并其他分支。



让我们来看看下面的案例。



开发人员想插入一个新的提交( master )转换为
其他3个开发分支( b11 b2 b3 )。其中一个( b11 )是
,它是基于 b1 的功能分支 b12 的合并。其他2
分行( b2 b3 )有分歧。 - 将这个新提交到这些分支中的每一个的
中,但是开发人员可能不希望
在3个不同的分支中具有相同的提交,但是在分支分歧之前只有1个提交
。 / p>

  * baa687d(HEAD  - > master)new common commit 
| * b507c23(b11)b11
| * 41849d9将分支'b12'合并到b11
|中| \
| | * 20459a3(b12)b12
| * | 1f74dd9 b11
| * | 554afac b11
| * | 67d80ab b11
| | /
| * b1cbb4e b11
| * 18c8802(b1)b1
| /
| * 7b4e404(b2)b2
| | * 6ec272b(b3)b3
| | * c363c43 b2 h
| | /
| * eabe01f头文件
| /
* 9b4a890(镜像/主文件)初始
* 887d11b初始化

为此,第一步是创建一个公共合并提交,
包含3个分支。为此,使用了名为 pack
的临时分支。


$ b 合并到 pack 可能会产生冲突,但这不是重要的
,因为这些合并稍后将被丢弃。只需指示git到
自动解决它们,添加选项 -s递归-Xours

  $ git checkout -b pack b11#在'b11'创建新分支以避免丢失原始参考
$ git merge -s递归-Xours b2#将b2合并到包
$ git merge -s递归-Xours b3#将b3合并为包

合并后的所有树到 pack 分支:

  * b35a4a7(HEAD  - > pack)合并分支'b3'装入包
| \
| * 6ec272b(b3)b3
| * c363c43 b2 h
* | 60c9b7c将分支'b2'合并到包
| \\
|中* | 7b4e404(b2)b2
| | /
| * eabe01f头
* | b507c23(b11)b11
* | 41849d9将分支'b12'合并到b11
| \\
|中* | 20459a3(b12)b12
* | | 1f74dd9 b11
* | | 554afac b11
* | | 67d80ab b11
| / /
* | b1cbb4e b11
* | 18c8802(b1)b1
| /
| * baa687d(master)new common commit
| /
* 9b4a890 initial
* 887d11b init

现在是时候移动已创建的子树。对于
,使用以下命令:

  $ git rebase --preserve-merges --onto master master ^ pack 

引用 master ^ 表示在 master master
父级),在这种情况下为9b4a890。这个提交不是重新发布的,它是3个重新设计的分支的起源
。当然,pack是
整个子树的最终参考。



在rebase期间可能会有一些合并冲突。如果在合并之前有
已经发生冲突,这些将再次出现。是
确定以同样的方式解决它们。对于为合并到临时节点 pack 而创建的
虚假提交,请勿打扰,并且
会自动解决它们。



  * 95c8d3d(HEAD  - > pack)合并分支' b3'装入包
| \
| * d304281 b3
| * ed66668 b2 h
* | b8756ee将分支'b2'合并到包
| \\
|中* | 8d82257 b2
| | /
| * e133de9 header
* | f2176e2 b11
* | 321356e将分支'b12'合并到b11
| \\
|中* | c919951 b12
* | | 8b3055f b11
* | | 743fac2 b11
* | | a14be49 b11
| / /
* | 3fad600 b11
* | c7d72d6 b1
| /
* baa687d(master)new common commit
|
* 9b4a890 initial
* 887d11b init

有时旧分支引用可能不会重新定位(即使没有它们的情况下
树也会重新定位)。在这种情况下,您可以恢复
或手动更改某些参考。



现在是时候撤消预先加标的合并,这可能会导致
rebasing整棵树。在

$ b

  * f2176e2(HEAD  - > b11)之后, b11 
* 321356e将分支'b12'合并到b11
| \
| * c919951(b12)b12
* | 8b3055f b11
* | 743fac2 b11
* | a14be49 b11
| /
* 3fad600 b11
* c7d72d6(b1)b1
| * d304281(b3)b3
| * ed66668 b2 h
| | * 8d82257(b2)b2
| | /
| * e133de9 header
| /
* baa687d(mirror / master,mirror / HEAD,master)new common commit
* 9b4a890 initial
* 887d11b init

开发人员想要实现的是:提交
由3个分支共享。


This is my current git tree:

A - H (master)
|
\- B - C - D - E (feature)
           |
           \- F (new)
           |
           \- G (other)

And I'd like to rebase the side branch so that it depends on H rather than A:

A - H (master)
    |
    \- B'- C'- D'- E'(feature)
               |
               \- F'(new)
               |
               \- G'(other)

Easy concept, hard to do automatically, it seems. This has already been asked here and here, but the proposed solutions are not working for me.

First, as pointed out in the former, the git branch output is not trivial to parse when the current branch is there (there is a * prepended). But that's not a stopper, in my case I can easily provide the names feature, new and other by hand, or make sure the current branch is master.

Then I tried with these commands:

git rebase --committer-date-is-author-date --preserve-merges --onto master feature^ feature
git rebase --committer-date-is-author-date --preserve-merges --onto master feature^ new
git rebase --committer-date-is-author-date --preserve-merges --onto master feature^ other

and I end up with:

A - H (master)
    |
    \- E'(feature)
    |
    \- B' - C' - D' - F'(new)
    |
    \- B" - C" - D" - G'(other)

Definitely not what I want! Or, if I use B^ instead of feature^, then I also get the B - C - D history in the feature branch.

So, any further suggestion on how to get this done more or less automatically?

EDIT: It sort of works with this:

git checkout feature
git merge other
git merge new
git rebase -p master feature

Now at least the tree looks correct, I just have to move the branch heads to their right commits before the merges... which could be done with:

git checkout master
git branch -f new feature^2
git branch -f feature feature^1
git branch -f other feature^2
git branch -f feature feature^1

解决方案

In these cases, a nice trick is to merge (join) all the branches to be moved into a final commit node. After that, use rebase with the --preserve-merges option for moving the resulting enclosed subtree (set of branches).

Creating a closed subtree that contains all the branches, exposes 2 nodes (start and end) that are used as input parameters for the rebase command.

The end of the closed subtree is an artificial node that may be deleted after moving the tree, as well as the other nodes that may have been created for merging other branches.

Let's see the following case.

The developer wants to insert a new commit (master) into other 3 development branches (b11, b2, b3). One of these (b11) is a merge of a feature branch b12, both based on b1. The other 2 branches (b2, b3) diverge.

Of course the developer could cherry-pick that new commit into each one of these branches, but the developer may prefer not to have the same commit in 3 different branches, but just 1 commit before the branches diverge.

* baa687d (HEAD -> master) new common commit
| * b507c23 (b11) b11
| *   41849d9 Merge branch 'b12' into b11
| |\
| | * 20459a3 (b12) b12
| * | 1f74dd9 b11
| * | 554afac b11
| * | 67d80ab b11
| |/
| * b1cbb4e b11
| * 18c8802 (b1) b1
|/
| * 7b4e404 (b2) b2
| | * 6ec272b (b3) b3
| | * c363c43 b2 h
| |/
| * eabe01f header
|/
* 9b4a890 (mirror/master) initial
* 887d11b init

For that, the first step is to create a common merge commit that includes the 3 branches. For that a temporary branch called pack is used.

Merging into pack may create conflicts, but that is not important since these merges will later be discarded. Just instruct git to automatically solve them, adding options -s recursive -Xours.

$ git checkout -b pack b11 # create new branch at 'b11' to avoid losing original refs
$ git merge -s recursive -Xours b2 # merges b2 into pack
$ git merge -s recursive -Xours b3 # merges b3 into pack

This is the whole tree after merging everything into the pack branch:

*   b35a4a7 (HEAD -> pack) Merge branch 'b3' into pack
|\
| * 6ec272b (b3) b3
| * c363c43 b2 h
* |   60c9b7c Merge branch 'b2' into pack
|\ \
| * | 7b4e404 (b2) b2
| |/
| * eabe01f header
* | b507c23 (b11) b11
* |   41849d9 Merge branch 'b12' into b11
|\ \
| * | 20459a3 (b12) b12
* | | 1f74dd9 b11
* | | 554afac b11
* | | 67d80ab b11
|/ /
* | b1cbb4e b11
* | 18c8802 (b1) b1
|/
| * baa687d (master) new common commit
|/
* 9b4a890 initial
* 887d11b init

Now it's time to move the subtree that has been created. For that the following command is used:

$ git rebase --preserve-merges --onto master master^ pack

The reference master^ means the commit before master (master's parent), 9b4a890 in this case. This commit is NOT rebased, it is the origin of the 3 rebased branches. And of course, pack is the final reference of the whole subtree.

There may be some merge conflicts during the rebase. In case there had already been conflicts before doing the merge these will arise again. Be sure to solve them the same way. For the the artificial commits created for merging into the temporary node pack, don't bother and solve them automatically.

After the rebase, that would be the resulting tree:

*   95c8d3d (HEAD -> pack) Merge branch 'b3' into pack
|\
| * d304281 b3
| * ed66668 b2 h
* |   b8756ee Merge branch 'b2' into pack
|\ \
| * | 8d82257 b2
| |/
| * e133de9 header
* | f2176e2 b11
* |   321356e Merge branch 'b12' into b11
|\ \
| * | c919951 b12
* | | 8b3055f b11
* | | 743fac2 b11
* | | a14be49 b11
|/ /
* | 3fad600 b11
* | c7d72d6 b1
|/
* baa687d (master) new common commit
|
* 9b4a890 initial
* 887d11b init

Sometimes the old branch references may not be relocated (even if the tree relocates without them). In that case you can recover or change some reference by hand.

It's also time to undo the pre-rebase merges that made possible rebasing the whole tree. After some delete, reset/checkout, this is the tree:

* f2176e2 (HEAD -> b11) b11
*   321356e Merge branch 'b12' into b11
|\
| * c919951 (b12) b12
* | 8b3055f b11
* | 743fac2 b11
* | a14be49 b11
|/
* 3fad600 b11
* c7d72d6 (b1) b1
| * d304281 (b3) b3
| * ed66668 b2 h
| | * 8d82257 (b2) b2
| |/
| * e133de9 header
|/
* baa687d (mirror/master, mirror/HEAD, master) new common commit
* 9b4a890 initial
* 887d11b init

Which is exactly what the developer wanted to achieve: the commit is shared by the 3 branches.

这篇关于重新绑定树(提交/分支及其所有子项)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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