移植物在汞中的应用效果

最近有几个关于在 Mercurial 中维护发布分支时跳过更改的问题。例如:

自从它在2.0中引入以来,我一直想知道如何使用 graft来避免这个问题。给定一个这样的修订树:

A---B---C---D---E---F---G---H---I---J

假设我们需要创建一个发布分支来跳过邪恶更改 E

hg update -r D
hg graft "F::J"

给我们:

A---B---C---D---E---F---G---H---I---J
\
--F'--G'--H'--I'--J'
  • 问题1: 这里刚刚发生了什么?我可以理解,transplant会从 F::J中生成补丁,然后将它们应用到 D上,但是 graft被认为是使用3路合并而不是补丁。那么..。这是怎么回事?为什么会更好?

假设我现在修复了 E,并将其合并到我的发布分支中。

                  --E2-----------------
/                     \
A---B---C---D---E---F---G---H---I---J---M1
\                            \
--F'--G'--H'--I'--J'---------M2--

M1是直线合并,没什么特别的。 M2正在合并具有“相同”(或至少等效)更改的分支。

  • 问题2: 这个合并只是一个正常的3路合并使用 DJ'M1
  • 汞是否储存或使用了关于移植手术的额外信息来帮助合并?

最后。

  • Q4: 这样的流有什么潜在的问题?
20621 次浏览

Q1: It helps when there are conflicts. You can use your usual merge tool then (for me it's inline conflict markers, which I edit with Emacs' smerge-mode).

Q2: It's a normal merge.

Q3: No.

Q4: I think it's ugly to have two almost identical branches.

When you update to D and graft F::J, Mercurial runs a number of merges. It will start with this merge:

M = three_way_merge(local=D, other=F, base=E)

If we write +d for the delta between the states C and D, then we start with:

        +d     +e     +f
---- C ---- D ---- E ---- F ----

Turn the graph 90 degrees clockwise and the above three-way merge looks like this:

    -e
.---- D
/
E
\
'---- F
+f

That is, we pretend that we started with E and applied the opposite of -e to get to D. I think of as the reverse patch of +e. Starting in E we also went to state F with the normal delta +f. There's nothing strange here — we have all the states (D, E, and F) in the repository already. So seen like this, it's clear that we can merge D and F.

Merging is a matter of "completing the diamond". So we find a new state M that is a mix of D and F and where the difference from D to M is similar to +f and the difference from F to M is similar to -e. It looks like this:

    -e     +f'
.---- D ----.
/             \
E               M
\             /
'---- F ----'
+f     -e'

The +f delta became +f' and the -e delta became -e'. This is just a normal three-way merge, but the effect is interesting: we've applied F onto D instead of E!

After the merge, the second parent of M to F is dropped:

    -e     +f'
.---- D ----.
/             \
E               M
\
'---- F
+f

To reiterate: We have copied the "effect" of F onto D, that is, we have found a delta (+f') that applied to D give the same effect as when +f was applied to E. We can straighten the graph a bit to get:

       +f'
--- D ---- M
\
'---- E ---- F
+e     +f

The result is that F is grafted onto D using the full three-way machinery.

  • Q1: What just happened here? So....... how does that work? Why is it better?

    A1: Using merges is better than patches since the merge machinery takes things like renames into account.

  • Q2: Is this merge just a normal 3-way merge using D, J' and M1?

    A2: Yes, grafting does not alter the topology of the graph.

  • Q3: Has mercurial stored/used extra information about the graft operation to help it with the merge?

    A3: No.

  • Q4: What are the potential problems with a flow like this?

    A4: From a merge perspective it should work okay. It will duplicate some history which might be confusing for people.