Handle vertex merges more carefully.

When autofilling the vertex of a block, it is possible to do the merge
three ways:

1. Using the commits directly above and to the left as parents

2. Using the commits at [i1,0] and [i1-1,i2] as parents (i.e., as a
   continuation of the bottom edge)

3. Using the commits at [i1,i2-1] and [0,i2] as parents (i.e., as a
   continuation of the right edge)

We want the final history to be *as if* the parents were as in (1).

Formerly we were doing (1) and simply using the result.  This is
incorrect because the neighboring commits do not have correct
histories.  Therefore, the merge base for this merge is [0,0], and the
merge can have unnecessary conflicts.

Change to trying both (2) and (3).  If both of those commits succeed
*and* if they give identical trees, then create a synthetic commit
with the parents as in (1) and use that; otherwise, fail.
This commit is contained in:
Michael Haggerty 2013-05-14 10:07:01 +02:00
parent 43c96036be
commit 8d283e9658

View File

@ -1241,19 +1241,18 @@ class Block(object):
# of them permanently.
merges = []
def do_merge(i1, commit1, i2, commit2):
def do_merge(i1, commit1, i2, commit2, msg='Autofilling %d-%d...', record=True):
if (i1, i2) in self:
return self[i1,i2].sha1
try:
sys.stderr.write(
'Autofilling %d-%d...' % self.get_original_indexes(i1, i2)
)
sys.stderr.write(msg % self.get_original_indexes(i1, i2))
merge = automerge(commit1, commit2)
sys.stderr.write('success.\n')
except AutomaticMergeFailed, e:
sys.stderr.write('unexpected conflict. Backtracking...\n')
raise UnexpectedMergeFailure(str(e), i1, i2)
merges.append((i1, i2, merge))
if record:
merges.append((i1, i2, merge))
return merge
i2 = self.len2 - 1
@ -1266,10 +1265,39 @@ class Block(object):
for i2 in range(1, self.len2 - 1):
above = do_merge(i1, above, i2, self[0,i2].sha1)
# We will compare two ways of doing the final "vertex" merge:
# as a continuation of the bottom edge, or as a continuation
# of the right edge. We only accept it if both approaches
# succeed and give identical trees.
i1, i2 = self.len1 - 1, self.len2 - 1
do_merge(i1, above, i2, left)
vertex_v1 = do_merge(
i1, self[i1,0].sha1, i2, left,
msg='Autofilling %d-%d (first way)...',
record=False,
)
vertex_v2 = do_merge(
i1, above, i2, self[0,i2].sha1,
msg='Autofilling %d-%d (second way)...',
record=False,
)
if get_tree(vertex_v1) == get_tree(vertex_v2):
sys.stderr.write(
'The two ways of autofilling %d-%d agree.\n'
% self.get_original_indexes(i1, i2)
)
else:
sys.stderr.write(
'The two ways of autofilling %d-%d do not agree. Backtracking...\n'
% self.get_original_indexes(i1, i2)
)
raise UnexpectedMergeFailure('Inconsistent vertex merges', i1, i2)
# Success! Now we can record the results:
# Everything is OK. Now reparent the actual vertex merge to
# have above and left as its parents:
merges.append((i1, i2, reparent(vertex_v1, [above, left])))
# Done! Now we can record the results:
sys.stderr.write('Recording autofilled block %s.\n' % (self,))
for (i1, i2, merge) in merges:
self[i1, i2].record_merge(merge, MergeRecord.NEW_AUTO)