[MERGE][BUG #151731] Alternative Cherrypicking merges
John Arbash Meinel
john at arbash-meinel.com
Tue Mar 11 22:26:45 GMT 2008
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
James Westby wrote:
| On Tue, 2008-03-04 at 14:30 +0000, John Arbash Meinel wrote:
|> -----BEGIN PGP SIGNED MESSAGE-----
|> Hash: SHA1
|>
|> I've been thinking about the cherrypicking bug:
|> https://bugs.launchpad.net/bzr/+bug/151731
|>
|> My notes on the bug are probably unclear, so I'll try to summarize, and
|> present an alternative to 3-way merge that might work very well for
|> cherrypicks.
|
| Hi John,
|
| Thanks for looking at this.
|
| I think that I agree with you on the examination of the problem,
| and I am trying to look at the code to review the patch, but I don't
| feel comfortable giving a full review. I do have some comments though.
|
|
|> @@ -453,13 +458,15 @@
|> supports_reprocess = True
|> supports_show_base = True
|> history_based = False
|> + supports_cherrypick = True
|> supports_reverse_cherrypick = True
|> winner_idx = {"this": 2, "other": 1, "conflict": 1}
|>
|> def __init__(self, working_tree, this_tree, base_tree,
|> other_tree,
|> interesting_ids=None, reprocess=False,
|> show_base=False,
|> pb=DummyProgress(), pp=None, change_reporter=None,
|> - interesting_files=None, do_merge=True):
|> + interesting_files=None, do_merge=True,
|> + cherrypick=False):
|
| Nitpick: the cherrypick parameter isn't added to the docstring. However
| do_merge isn't there as well. I only noticed this as you took the time
| to update one of the previous ones.
|
|
|> + def test_merge3_cherrypick_w_mixed(self):
|> + base_text = 'a\nb\nc\nd\ne\n'
|> + this_text = 'a\nb\nq\n'
|> + other_text = 'a\nb\nc\nd\nf\ne\ng\n'
|> + # When cherrypicking, lines in base are not part of the
|> conflict
|> + m3 = Merge3(base_text.splitlines(True),
|> this_text.splitlines(True),
|> + other_text.splitlines(True), is_cherrypick=True)
|> + m_lines = m3.merge_lines()
|> + self.assertEqualDiff('a\n'
|> + 'b\n'
|> + '<<<<<<<\n'
|> + 'q\n'
|> + '=======\n'
|> + 'f\n'
|> + '>>>>>>>\n'
|> + '<<<<<<<\n'
|> + '=======\n'
|> + 'g\n'
|> + '>>>>>>>\n',
|> + ''.join(m_lines))
|
| This is the only test that I don't fully understand, could you take
| a minute to explain the result to me please?
THIS BASE OTHER
a a a
b b b
q c c
d d
e f
e
g
Or if we re-write it to find matching sections:
THIS BASE OTHER
~ a a a
~ b b b
- --- --- ---
~ q c c
d d
~ --- ---
f
~ --- ---
e e
~ --- ---
g
Obviously ab is maintained without change.
Then we have an obvious conflict for:
BASE => THIS
cde q
versus
BASE => OTHER
cde => cdfeg
Standard 3-way merge would give us:
a
b
<<<<<<<
q
=======
c
d
f
e
g
|>>>>>>
However, we are explicitly cherrypicking. Which means we *don't* want lines that
are present in BASE to be present in the output. Which means we want to hide c d
e. There are 2 options
a
b
<<<<<<<
q
=======
f
g
|>>>>>>
or
a
b
<<<<<<<
q
=======
f
|>>>>>>
<<<<<<<
=======
g
|>>>>>>
Either could be seen as valid. My particular implementation does the latter,
partially because I think I prefer it.
Specifically, in the former case, you are throwing away the context lines, and
merging it together into one big region. In the later, the context lines
introduce a break to the conflicting region. (Which doesn't have anything to
match against in THIS.)
Oh, and I don't think we have a way of representing conflicts that span
non-contiguous ranges.
As the current output is:
('conflict', start_BASE, end_BASE, start_THIS, end_THIS, start_OTHER, end_OTHER)
I suppose some possibilities arise. For example, we could change it so that this
function only removes prefix and suffix matches, and keeps all the internal
context. So if you had:
THIS BASE OTHER
a a a
b b b
c d d
e f
g e
h
g
Then it would strip 'd' and 'g', but not 'e' from the conflict
a
b
<<<<<<<
c
=======
f
e
h
|>>>>>>
rather than the current
a
b
<<<<<<<
c
=======
f
|>>>>>>
<<<<<<<
=======
h
|>>>>>>
I can't say for sure what the "right" thing is. I can imagine someone doing
something like:
common context
def function_1_to_cherrpick():
~ bar
def function_written_to_not_cherrypick():
~ baz
def function_2_to_cherrpick():
~ bing
That is the case where I think we want to do what I've done, and have:
common context
<<<<<<
======
def function_1_to_cherrpick():
~ bar
|>>>>>
<<<<<<
======
def function_2_to_cherrpick():
~ bing
|>>>>>
|
| All of the changes seem reasonable to me. The only grey areas I have
| are the above test, and the _refine method.
|
The _refine... method is because we want to find "unmatched" regions, but all we
have is "get_matching_blocks()". So we track where we were last, and then when
we step to the next matching region, we check to see if any lines were skipped,
which thus must be unmatched.
| In my tests this seems to do the right thing though, and using the
| test case in the bug report it gives the expected result.
|
| I would guess this is a little intrusive for 1.3, but that is up to
| your second reviewer I guess.
|
| Thanks,
|
| James
Well, technically it is up to the release manager. Who I believe is still Martin.
John
=:->
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.5 (Cygwin)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org
iD8DBQFH1wclJdeBCYSNAAMRApIaAJ91a/SydIttr0phLwIX5MjfkcfZwwCfWq0A
qHaiwIulKDXrOyoAXaWlIyg=
=6xWS
-----END PGP SIGNATURE-----
More information about the bazaar
mailing list