monotone-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Monotone-devel] considering no merge-into-dir


From: graydon hoare
Subject: [Monotone-devel] considering no merge-into-dir
Date: 08 Oct 2003 18:22:31 -0400
User-agent: Gnus/5.09 (Gnus v5.9.0) Emacs/21.2

hi,

I've been considering the suggestion (from IRC) of "merge-into-dir". 

the idea of this command (or change to the way "merge" works) is to
write the result of a 3-way merge into a directory -- maybe even your
working copy -- and let you "inspect" it to make sure it's ok, before
committing. then when you're ready, you "commit" and commit is smart
enough to realize this is the result of a merge and not a normal bit
of work, and commit multiple ancestry edges and all that. this fits
with the old CVS intuition that "commit is the only thing that commits
stuff".

I'll admit some of this sounds appealing, but something about it
seemed not quite right. and it's been bugging me. it bugged me during
a recent, extremely *long* errand (in which I was pursuing pie
containers for thanksgiving pumpkin pie) until it finally occurred
why. I've now, I think, realized why it's not quite right. I will
outline a scenario which illustrates:


graydon and tromey both work on a file pie.h, which contains a list of
pie codes, plus a count of how many there are:

#define APPLE_PIE 0xf00d1234
#define PEACH_PIE 0xf00d2234
#define TOTAL_PIES 2

this parent version we will call PARENTPIE. now tromey adds a new pie
on his copy and updates the total number of pies

  #define APPLE_PIE 0xf00d1234
+ #define RHUBARB_PIE 0xf00d4452
  #define PEACH_PIE 0xf00d2234
- #define TOTAL_PIES 2
+ #define TOTAL_PIES 3

we will call this version TROMEYPIE. graydon also adds a new pie, but
absent-mindedly forgets to update the total number of pies, because he
is lazy and stupid. graydon's version is called GRAYDONPIE:

  #define APPLE_PIE 0xf00d1234
  #define PEACH_PIE 0xf00d2234
+ #define BLUEBERRY_PIE 0xf00d1199
  #define TOTAL_PIES 2

now they both exchange packets and merge, using a merge-into-tree
strategy. tromey pays attention to pie numbers, so examines the merge
and *fixes* the number of pies before committing his merge. so he
commits this (relative to TROMEYPIE):

  #define APPLE_PIE 0xf00d1234
  #define RHUBARB_PIE 0xf00d4452
  #define PEACH_PIE 0xf00d2234
+ #define BLUEBERRY_PIE 0xf00d1199
- #define TOTAL_PIES 3
+ #define TOTAL_PIES 4

we'll call this TROMEYMERGE. graydon is lazy so just commits what the
automerger produces (relative to GRAYDONPIE):

  #define APPLE_PIE 0xf00d1234
+ #define RHUBARB_PIE 0xf00d4452
  #define PEACH_PIE 0xf00d2234
  #define BLUEBERRY_PIE 0xf00d1199
- #define TOTAL_PIES 2
+ #define TOTAL_PIES 3

we'll call this GRAYDONMERGE. so far so good. our graph now has 2
heads: TROMEYMERGE and GRAYDONMERGE, and each of these heads has an
"in edge" from *each* of TROMEYPIE and GRAYDONPIE.  but now comes the
problem: njs is working on some unrelated oven-control system, and
doesn't care much about what's going on in the pie enumeration
department. when njs fetches these versions and does a merge, here's
what (might) happen:

  - monotone looks at heads and sees TROMEYMERGE and GRAYDONMERGE
  - seeking a least common ancestor, it chooses (why not?) GRAYDONPIE
  - it sees the following two edits:

     (on the edge GRAYDONPIE -> TROMEYMERGE)

     - #define TOTAL_PIES 2
     + #define TOTAL_PIES 4

     (on the edge GRAYDONPIE -> GRAYDONMERGE)

     - #define TOTAL_PIES 2
     + #define TOTAL_PIES 3

    oops, those *conflict*. njs is dropped into emacs to fix the
    problem. what a pain in the ass!

compare with a different scenario: suppose tromey committed the
results of his automerge as TROMEYMERGE. it would be identical to
GRAYDONMERGE -- wrong, but identical -- so no news there. TOTAL_PIES
would be equal to 3, clearly wrong. then suppose tromey updated,
looked over the results, fixed the wrongness, and committed an extra
version after that called TROMEYFIX, with TOTAL_PIES set to 4. then
when njs runs merge:

  - monotone looks at heads and sees TROMEYFIX
  - heads are merged, so nothing to do

why is this different? because the versions graydon and tromey
synthesized by their automerge are identical, once they are committed
they form the new *merged* head of the tree. further work by either of
them has that merged head as a least common ancestor, as far as
monotone's concerned.

whereas, by doing a "smart" merge-into-tree (TROMEYMERGE) which
produces a *different* head, tromey inadvertantly pushes the least
common ancestor of subsequent versions back to a choice between the
merge *inputs*. and, as my carefully crafted put fully plausible
example demonstrates, if monotone chooses wrong amongst the merge
inputs, it may pick an ancestor for which the outgoing edges actually
conflict.

of course, tromey might also get graydon's bad merge first and merge
with it, fixing the conflict before njs sees it. but then tromey has
just fixed graydon's stupid problem *twice*, and the extra node
TROMEYMERGE was pointless. so either way, I don't see it as a good
idea. I think I'm going to leave it the way it is.

-graydon





reply via email to

[Prev in Thread] Current Thread [Next in Thread]