正确地将一个特性合并到 master 中
Correctly merging a feature into master
问题:
我总是 运行 在涉及多个相关功能分支时遇到同样的问题。
master ---A---B---C
\
feature1 D---E---F
\
feature2 G---H
我有这样的东西。假设这两个分支都被审查过,我将把 feature1
合并到 master
。然后结帐并拉取 master
,然后结帐并将 feature2
变基为 master
。这样做,我总是一遍又一遍地看到相同的冲突,尤其是在多个分支上。
良好的变基:
我在网上看到上面的例子,首先我应该做这样的事情来确保我正确地变基:
将 feature1
变基为 master
master ---A---B---C
\ \
feature1 \ D'--E'--F'
\
feature2 D---E---F---G---H
Rebase feature2
到新的 feature1
提交
master ---A---B---C
\
feature1 D'--E'--F'
\
feature2 G'--H'
我会使用 git rebase --onto feature1 feature1@{1} feature2
来做到这一点。
困惑:
据我了解,最好像这样变基,因为当你变基时,你的分支实际上将包含全新的提交(即上面的 F
和 F'
),这可能会导致不必要的冲突.
考虑到所有这些,正确的方法是什么:
- 将
feature1
合并到 master
- 合并
feature2
到 master`
我想尝试学习推荐的方法,我可以确信我不会每次都遇到多个依赖分支的痛苦冲突。
注意,这个答案分为两部分。第一个是关于变基的机制,第二个是变基与合并。
复杂变基的机制
I would do this using git rebase --onto feature1 feature1@{1} feature2
是的:这通过将参数拆分为 rebase 来实现:现在不再是 feature1
,而是 --onto feature1 feature1@{1}
.
通常,我们运行 git rebase <em>name</em>
,例如git rebase feature1
。我们要先git checkout feature2
。添加 feature2
到命令的末尾(如上引用)只是为我们做了这个 git checkout
步骤。因此,如果我在这里调用“正常”,git rebase
只有一个参数,通常是另一个分支名称,如 feature1
.
但是git rebase
所做的是复制一些提交,为此,它需要知道两个事情:
- 要复制的内容(提交列表),以及
- 在哪里放置 新副本。
那个参数 feature1
为其中的 做了繁重的工作。这很好当它工作时,但是为了将 feature2
变基到已经变基的 feature1
,它并不总是有效。
它不起作用的原因(当它不起作用时)与您绘制的图表有关。你以一种奇怪的方式画了它们,左边有分支名称。这种绘图具有误导性:它暗示每个提交都在 one 分支上,这是不正确的。
又是第一张图:
master ---A---B---C
\
feature1 D---E---F
\
feature2 G---H
问:A
提交到哪个分支? (技巧问题!)
答:在所有个分支上。
绘制这些图表时应在左侧显示提交,在右侧上显示标签,标签指向一个特定的提交——因为这就是这些东西在Git中的实际工作方式。这是相同的图表,重新绘制:
--A--B--C <-- master
\
D--E--F <-- feature1
\
G--H <-- feature2
通过从右边开始并跟随(内部的并且总是向后指向的)父链接从提交到提交,我们可以看到 C
、B
和 A
在主人身上; F
、E
、D
和 A
在 feature1
上;例如 H
、G
、F
、E
、D
和 A
在 feature2
上。
现在我们可以在第一个git rebase
之后绘制第二个图,像这样:
D'-E'-F' <-- feature1
/
--A--B--C <-- master
\
D--E--F [reflog: feature1@{1}]
\
G--H <-- feature2
这就是 git rebase
的拆分参数的用武之地。
通常,Git 找到 git rebase
将使用以下方式复制的提交集:
git rev-list <argument>..<current-branch>
这里是 feature1..feature2
。这意味着 可从 feature2
到达的所有提交,但可从 feature1
到达的所有提交除外。现在,在 我们移动 feature1
之前,那是正确的提交集:它是 H
和 G
。但是我们移动了 feature1
,现在它是 错误的 组提交,因为它也包括 F
到 D
。
一旦我们说 feature1@{1}..feature2
,但是,我们再次得到 正确的 一组提交。但是现在我们已经失去了复制的地方,这就是我们需要 --onto
的原因:那就是 放置副本的地方。
当第二次rebase完成后,我们应该绘制最终结果如下:
G'-H' <-- feature2
/
D'-E'-F' <-- feature1
/
--A--B--C <-- master
\
D--E--F [reflog: feature1@{1}]
\
G--H [reflog: feature2@{1}]
并且由于引用日志通常是不可见的,我们可以完全删除图表的下半部分。
变基与合并
As I understand it, it's better to rebase like this because ...
更好 是一个非常狡猾的术语。
变基有两个问题:
它复制 提交,然后放弃原件以支持新副本。其他人有原件吗?如果是这样,你也让他们为难了:他们也必须放弃原件,转而使用新的副本。
它复制 提交。新副本至少与原件有些不同(否则它们实际上 是 原件)。确切地说,副本有什么不同?那很重要么?你在这个过程中有没有破坏某些东西,即引入错误?
使用git merge
可以避免这些问题。相反,它插入了它自己的问题:
历史现在很纠结。如果有必要弄清楚发生了什么,无论是谁在探索历史,都可能不得不俯视合并的两条“腿”。一些人认为这是积极的,而不是消极的,因为这是真实的历史,而不是后来经过清理的人造历史。
(我倾向于赞成清理历史,但这个论点的双方都有其优点。)
合并本身可能会引入错误。
如果您有一组非常好的测试,这有助于解决“引入错误”这两个问题。
如果它有足够的帮助,它只留下 一个 变基问题(假设你足够聪明,或者有一个很好的工具,像这种情况一样做你自己的复杂变基) : 别人有原件吗?平衡你对该问题的回答与你对纠结的历史是否糟糕的回答,以便决定合并还是变基。
如果你没有有很好的测试,那么... :-)
问题:
我总是 运行 在涉及多个相关功能分支时遇到同样的问题。
master ---A---B---C
\
feature1 D---E---F
\
feature2 G---H
我有这样的东西。假设这两个分支都被审查过,我将把 feature1
合并到 master
。然后结帐并拉取 master
,然后结帐并将 feature2
变基为 master
。这样做,我总是一遍又一遍地看到相同的冲突,尤其是在多个分支上。
良好的变基:
我在网上看到上面的例子,首先我应该做这样的事情来确保我正确地变基:
将 feature1
变基为 master
master ---A---B---C
\ \
feature1 \ D'--E'--F'
\
feature2 D---E---F---G---H
Rebase feature2
到新的 feature1
提交
master ---A---B---C
\
feature1 D'--E'--F'
\
feature2 G'--H'
我会使用 git rebase --onto feature1 feature1@{1} feature2
来做到这一点。
困惑:
据我了解,最好像这样变基,因为当你变基时,你的分支实际上将包含全新的提交(即上面的 F
和 F'
),这可能会导致不必要的冲突.
考虑到所有这些,正确的方法是什么:
- 将
feature1
合并到master
- 合并
feature2
到 master`
我想尝试学习推荐的方法,我可以确信我不会每次都遇到多个依赖分支的痛苦冲突。
注意,这个答案分为两部分。第一个是关于变基的机制,第二个是变基与合并。
复杂变基的机制
I would do this using
git rebase --onto feature1 feature1@{1} feature2
是的:这通过将参数拆分为 rebase 来实现:现在不再是 feature1
,而是 --onto feature1 feature1@{1}
.
通常,我们运行 git rebase <em>name</em>
,例如git rebase feature1
。我们要先git checkout feature2
。添加 feature2
到命令的末尾(如上引用)只是为我们做了这个 git checkout
步骤。因此,如果我在这里调用“正常”,git rebase
只有一个参数,通常是另一个分支名称,如 feature1
.
但是git rebase
所做的是复制一些提交,为此,它需要知道两个事情:
- 要复制的内容(提交列表),以及
- 在哪里放置 新副本。
那个参数 feature1
为其中的 做了繁重的工作。这很好当它工作时,但是为了将 feature2
变基到已经变基的 feature1
,它并不总是有效。
它不起作用的原因(当它不起作用时)与您绘制的图表有关。你以一种奇怪的方式画了它们,左边有分支名称。这种绘图具有误导性:它暗示每个提交都在 one 分支上,这是不正确的。
又是第一张图:
master ---A---B---C
\
feature1 D---E---F
\
feature2 G---H
问:A
提交到哪个分支? (技巧问题!)
答:在所有个分支上。
绘制这些图表时应在左侧显示提交,在右侧上显示标签,标签指向一个特定的提交——因为这就是这些东西在Git中的实际工作方式。这是相同的图表,重新绘制:
--A--B--C <-- master
\
D--E--F <-- feature1
\
G--H <-- feature2
通过从右边开始并跟随(内部的并且总是向后指向的)父链接从提交到提交,我们可以看到 C
、B
和 A
在主人身上; F
、E
、D
和 A
在 feature1
上;例如 H
、G
、F
、E
、D
和 A
在 feature2
上。
现在我们可以在第一个git rebase
之后绘制第二个图,像这样:
D'-E'-F' <-- feature1
/
--A--B--C <-- master
\
D--E--F [reflog: feature1@{1}]
\
G--H <-- feature2
这就是 git rebase
的拆分参数的用武之地。
通常,Git 找到 git rebase
将使用以下方式复制的提交集:
git rev-list <argument>..<current-branch>
这里是 feature1..feature2
。这意味着 可从 feature2
到达的所有提交,但可从 feature1
到达的所有提交除外。现在,在 我们移动 feature1
之前,那是正确的提交集:它是 H
和 G
。但是我们移动了 feature1
,现在它是 错误的 组提交,因为它也包括 F
到 D
。
一旦我们说 feature1@{1}..feature2
,但是,我们再次得到 正确的 一组提交。但是现在我们已经失去了复制的地方,这就是我们需要 --onto
的原因:那就是 放置副本的地方。
当第二次rebase完成后,我们应该绘制最终结果如下:
G'-H' <-- feature2
/
D'-E'-F' <-- feature1
/
--A--B--C <-- master
\
D--E--F [reflog: feature1@{1}]
\
G--H [reflog: feature2@{1}]
并且由于引用日志通常是不可见的,我们可以完全删除图表的下半部分。
变基与合并
As I understand it, it's better to rebase like this because ...
更好 是一个非常狡猾的术语。
变基有两个问题:
它复制 提交,然后放弃原件以支持新副本。其他人有原件吗?如果是这样,你也让他们为难了:他们也必须放弃原件,转而使用新的副本。
它复制 提交。新副本至少与原件有些不同(否则它们实际上 是 原件)。确切地说,副本有什么不同?那很重要么?你在这个过程中有没有破坏某些东西,即引入错误?
使用git merge
可以避免这些问题。相反,它插入了它自己的问题:
历史现在很纠结。如果有必要弄清楚发生了什么,无论是谁在探索历史,都可能不得不俯视合并的两条“腿”。一些人认为这是积极的,而不是消极的,因为这是真实的历史,而不是后来经过清理的人造历史。
(我倾向于赞成清理历史,但这个论点的双方都有其优点。)
合并本身可能会引入错误。
如果您有一组非常好的测试,这有助于解决“引入错误”这两个问题。
如果它有足够的帮助,它只留下 一个 变基问题(假设你足够聪明,或者有一个很好的工具,像这种情况一样做你自己的复杂变基) : 别人有原件吗?平衡你对该问题的回答与你对纠结的历史是否糟糕的回答,以便决定合并还是变基。
如果你没有有很好的测试,那么... :-)