>>>>> "jam" == John A Meinel <email address hidden> writes:
<snip/>
jam> If I understand correctly you now:
jam> 1) Status quo and don't record a path for the other root (didn't change
jam> merge_names)
Yes, funnily (?) I'm in the same position ("doesn't make sense") as you
but on different points.
_merge_names() switch the winners when this_name is None. While this is
"correct" since many tests break if you change that, I still consider it
a bug.
jam> 2) Update fix_root() to handle when other_root isn't present in this,
jam> but there may be children of it anyway.
jam> I still think I'd prefer to update _merge_names, but you've
jam> clearly fixed the immediate cases.
I reverted that because, while it was making the whole code more
coherent, it was adding cruft and blurry my understanding even more than
the let-switch-the-winners-just-because.
So, if I put back your patch to _merge_names, 6 tests are failing with
CantMoveRoot including:
^^^^[log from bzrlib.tests.per_workingtree.test_merge_from_branch.TestMergedBranch.test_file3_in_root_conflicted(WorkingTreeFormat5)]
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/vila/src/bzr/bugs/375898-new-root/bzrlib/tests/per_workingtree/test_merge_from_branch.py", line 204, in test_file3_in_root_conflicted
nb_conflicts = outer.merge_from_branch(inner, to_revision='3')
File "/home/vila/src/bzr/bugs/375898-new-root/bzrlib/decorators.py", line 192, in write_locked
result = unbound(self, *args, **kwargs)
File "/home/vila/src/bzr/bugs/375898-new-root/bzrlib/workingtree.py", line 942, in merge_from_branch
conflicts = merger.do_merge()
File "/home/vila/src/bzr/bugs/375898-new-root/bzrlib/merge.py", line 508, in do_merge
self._do_merge_to(merge)
File "/home/vila/src/bzr/bugs/375898-new-root/bzrlib/merge.py", line 480, in _do_merge_to
merge.do_merge()
File "/home/vila/src/bzr/bugs/375898-new-root/bzrlib/merge.py", line 620, in do_merge
self._compute_transform()
File "/home/vila/src/bzr/bugs/375898-new-root/bzrlib/merge.py", line 676, in _compute_transform
lambda t, c: conflict_pass(t, c, self.other_tree))
File "/home/vila/src/bzr/bugs/375898-new-root/bzrlib/transform.py", line 2742, in resolve_conflicts
new_conflicts.update(pass_func(tt, conflicts))
File "/home/vila/src/bzr/bugs/375898-new-root/bzrlib/merge.py", line 676, in <lambda>
lambda t, c: conflict_pass(t, c, self.other_tree))
File "/home/vila/src/bzr/bugs/375898-new-root/bzrlib/transform.py", line 2769, in conflict_pass
tt.adjust_path(new_name, final_parent, existing_file)
File "/home/vila/src/bzr/bugs/375898-new-root/bzrlib/transform.py", line 1135, in adjust_path
TreeTransformBase.adjust_path(self, name, parent, trans_id)
File "/home/vila/src/bzr/bugs/375898-new-root/bzrlib/transform.py", line 167, in adjust_path
raise CantMoveRoot
CantMoveRoot: Moving the root directory is not supported at this time
Note that the traceback above shows that we have already called
fix_root() at this point and doing so we have tried to move the root
which is wrong. The test doesn't attempt to move the root (nor adding
it), the *content* of the root has been dealt with during a *previous*
merge. We are only touching files that *were* in the other_root.
Hence, I concluded that this patch was not in the right direction and
removed it.
Now (as you hinted below and I agree with that) there is still a problem
somewhere and my gut feeling is that the switch-the-winners code is a
bug and that the existing code is working around this bug so that two
wrongs make a right (or several).
I even think that switch-the-winners is right as long as a single root
is involved... and I won't be surprised if fixing merge_names allow us
to also get rid of fix_root() and fixup_new_roots(). I suspect
adjust_name() should be fixed to special case the roots and that may be
enough but I don't want to dive into this without better tests.
<snip/>
jam> ^- The comment here is certainly wrong now. Perhaps something like:
jam> # other_root doesn't have a physical representation. We still need to
jam> # move any references to the actual root of the tree.
Fixed.
jam> + if not present:
jam> + try:
jam> + # If the other root is not in the current tree, we
jam> don't
jam> + # reparent file and dirs that are expected in the final
jam> + # tree. These paths where preventively introduced in
jam> + # _merge_names for possible conflicts. We may want
jam> to find
jam> + # a better way -- vila 20100401
jam> + self.tt.final_kind(trans_id)
jam> + self.tt.final_name(trans_id)
jam> + continue
jam> + except (errors.NoFinalPath, errors.NoSuchFile), e:
jam> + pass
jam> ^- This section is a bit ugly.
I went to fully inline reparent_children into fix_root(), I think this
version is now clearer:
if self.other_tree.inventory.root.file_id in self.this_tree.inventory:
# the other tree's root is a non-root in the current tree (as when
# a previously unrelated branch is merged into another)
return
try: self.tt.final_kind(other_root) other_root_is_present = True
except NoSuchFile:
# other_root doesn't have a physical representation. We still need
# to move any references to the actual root of the tree. other_root_is_present = False
# 'other_tree.inventory.root' is not present in this tree. We are
# calling adjust_path for children which *want* to be present with a
# correct place to go.
for thing, child in self.other_tree.inventory.root.children.iteritems(): trans_id = self.tt.trans_id_file_id(child.file_id)
if not other_root_is_present: try: self.tt.final_kind(trans_id) # The item exist in the final tree and has a defined place # to go already. continue except errors.NoSuchFile, e: pass
# Move the item into the root self.tt.adjust_path(self.tt.final_name(trans_id), self.tt.root, trans_id)
if other_root_is_present: self.tt.cancel_creation(other_root) self.tt.cancel_versioning(other_root)
jam> Certainly it seems to be necessary, but it certainly feels like
jam> 'accumulating cruft'.
Well, the 'try: final_kind() expect NoSuchFile: blah' idiom is used in
many places, and has puzzled me long enough, we may want to embed that
exception catching in final_kind and just let him return None.
From there we could just do:
if not other_root_is_present:
if self.tt.final_kind(trans_id) is None:
# The item exist in the final tree and has a defined place
# to go already. continue
# move it into the root self.tt.adjust_path(self.tt.final_name(trans_id), self.tt.root, trans_id)
Is that the cruft you were referring to ?
jam> The paragraph is a bit hard to read. How about:
Right.
jam> rename "present" to "parent_is_present"
jam> Change the block to:
Addressed by the inlining above.
jam> However, in working through this logic, I'm pretty sure it is
jam> wrong. Specifically, consider the case where "final_name"
jam> raises an exception.
Bah, nice catch. While restarting the branch from scratch I missed that,
thanks.
<snip/>
jam> I'm hesitant, but okay with landing the patch. You've pretty
jam> clearly demonstrated that it fixes the problem. The hesitancy
jam> is that it "doesn't make sense" to me. Which is fairly serious,
I share the feeling but for different reasons. That makes it even more
serious, but I think the correct way to fix that is to add more tests
for transform and push down fix_root() and fixup_new_roots() which
sounds even more like 'accumulating cruft' to me. Hopefully we'll be
able to also address the switch-the-winners in _merge_names doing so.
jam> but we've already spent far too long on this. I don't see it
jam> getting much better without some more serious surgery on the
jam> internals of merge and transform...
There we fully agree on both points.
I'll merge with the fixes mentioned above, yell if you disagree ;-)
>>>>> "jam" == John A Meinel <email address hidden> writes:
<snip/>
jam> If I understand correctly you now:
jam> 1) Status quo and don't record a path for the other root (didn't change
jam> merge_names)
Yes, funnily (?) I'm in the same position ("doesn't make sense") as you
but on different points.
_merge_names() switch the winners when this_name is None. While this is
"correct" since many tests break if you change that, I still consider it
a bug.
jam> 2) Update fix_root() to handle when other_root isn't present in this,
jam> but there may be children of it anyway.
jam> I still think I'd prefer to update _merge_names, but you've
jam> clearly fixed the immediate cases.
I reverted that because, while it was making the whole code more the-winners- just-because.
coherent, it was adding cruft and blurry my understanding even more than
the let-switch-
So, if I put back your patch to _merge_names, 6 tests are failing with
CantMoveRoot including:
^^^^[log from bzrlib. tests.per_ workingtree. test_merge_ from_branch. TestMergedBranc h.test_ file3_in_ root_conflicted (WorkingTreeFor mat5)] ------- ------- ------- ------- ------- ------- ------- ------- ------- vila/src/ bzr/bugs/ 375898- new-root/ bzrlib/ tests/per_ workingtree/ test_merge_ from_branch. py", line 204, in test_file3_ in_root_ conflicted from_branch( inner, to_revision='3') vila/src/ bzr/bugs/ 375898- new-root/ bzrlib/ decorators. py", line 192, in write_locked vila/src/ bzr/bugs/ 375898- new-root/ bzrlib/ workingtree. py", line 942, in merge_from_branch vila/src/ bzr/bugs/ 375898- new-root/ bzrlib/ merge.py" , line 508, in do_merge _do_merge_ to(merge) vila/src/ bzr/bugs/ 375898- new-root/ bzrlib/ merge.py" , line 480, in _do_merge_to do_merge( ) vila/src/ bzr/bugs/ 375898- new-root/ bzrlib/ merge.py" , line 620, in do_merge _compute_ transform( ) vila/src/ bzr/bugs/ 375898- new-root/ bzrlib/ merge.py" , line 676, in _compute_transform vila/src/ bzr/bugs/ 375898- new-root/ bzrlib/ transform. py", line 2742, in resolve_conflicts conflicts. update( pass_func( tt, conflicts)) vila/src/ bzr/bugs/ 375898- new-root/ bzrlib/ merge.py" , line 676, in <lambda> vila/src/ bzr/bugs/ 375898- new-root/ bzrlib/ transform. py", line 2769, in conflict_pass adjust_ path(new_ name, final_parent, existing_file) vila/src/ bzr/bugs/ 375898- new-root/ bzrlib/ transform. py", line 1135, in adjust_path rmBase. adjust_ path(self, name, parent, trans_id) vila/src/ bzr/bugs/ 375898- new-root/ bzrlib/ transform. py", line 167, in adjust_path
-------
Traceback (most recent call last):
File "/home/
nb_conflicts = outer.merge_
File "/home/
result = unbound(self, *args, **kwargs)
File "/home/
conflicts = merger.do_merge()
File "/home/
self.
File "/home/
merge.
File "/home/
self.
File "/home/
lambda t, c: conflict_pass(t, c, self.other_tree))
File "/home/
new_
File "/home/
lambda t, c: conflict_pass(t, c, self.other_tree))
File "/home/
tt.
File "/home/
TreeTransfo
File "/home/
raise CantMoveRoot
CantMoveRoot: Moving the root directory is not supported at this time
Note that the traceback above shows that we have already called
fix_root() at this point and doing so we have tried to move the root
which is wrong. The test doesn't attempt to move the root (nor adding
it), the *content* of the root has been dealt with during a *previous*
merge. We are only touching files that *were* in the other_root.
Hence, I concluded that this patch was not in the right direction and
removed it.
Now (as you hinted below and I agree with that) there is still a problem
somewhere and my gut feeling is that the switch-the-winners code is a
bug and that the existing code is working around this bug so that two
wrongs make a right (or several).
I even think that switch-the-winners is right as long as a single root
is involved... and I won't be surprised if fixing merge_names allow us
to also get rid of fix_root() and fixup_new_roots(). I suspect
adjust_name() should be fixed to special case the roots and that may be
enough but I don't want to dive into this without better tests.
<snip/>
jam> ^- The comment here is certainly wrong now. Perhaps something like:
jam> # other_root doesn't have a physical representation. We still need to
jam> # move any references to the actual root of the tree.
Fixed.
jam> + if not present: final_kind( trans_id) final_name( trans_id) NoFinalPath, errors.NoSuchFile), e:
jam> + try:
jam> + # If the other root is not in the current tree, we
jam> don't
jam> + # reparent file and dirs that are expected in the final
jam> + # tree. These paths where preventively introduced in
jam> + # _merge_names for possible conflicts. We may want
jam> to find
jam> + # a better way -- vila 20100401
jam> + self.tt.
jam> + self.tt.
jam> + continue
jam> + except (errors.
jam> + pass
jam> ^- This section is a bit ugly.
I went to fully inline reparent_children into fix_root(), I think this
version is now clearer:
if self.other_ tree.inventory. root.file_ id in self.this_ tree.inventory:
self. tt.final_ kind(other_ root)
other_ root_is_ present = True
other_ root_is_ present = False tree.inventory. root' is not present in this tree. We are tree.inventory. root.children. iteritems( ):
trans_ id = self.tt. trans_id_ file_id( child.file_ id) is_present:
try:
self. tt.final_ kind(trans_ id)
# The item exist in the final tree and has a defined place
# to go already.
continue
except errors.NoSuchFile, e:
pass
self. tt.adjust_ path(self. tt.final_ name(trans_ id),
self. tt.root, trans_id) is_present:
self. tt.cancel_ creation( other_root)
self. tt.cancel_ versioning( other_root)
# the other tree's root is a non-root in the current tree (as when
# a previously unrelated branch is merged into another)
return
try:
except NoSuchFile:
# other_root doesn't have a physical representation. We still need
# to move any references to the actual root of the tree.
# 'other_
# calling adjust_path for children which *want* to be present with a
# correct place to go.
for thing, child in self.other_
if not other_root_
# Move the item into the root
if other_root_
jam> Certainly it seems to be necessary, but it certainly feels like
jam> 'accumulating cruft'.
Well, the 'try: final_kind() expect NoSuchFile: blah' idiom is used in
many places, and has puzzled me long enough, we may want to embed that
exception catching in final_kind and just let him return None.
From there we could just do:
if not other_root_ is_present: final_kind( trans_id) is None:
continue
self. tt.adjust_ path(self. tt.final_ name(trans_ id),
self. tt.root, trans_id)
if self.tt.
# The item exist in the final tree and has a defined place
# to go already.
# move it into the root
Is that the cruft you were referring to ?
jam> The paragraph is a bit hard to read. How about:
Right.
jam> rename "present" to "parent_is_present"
jam> Change the block to:
Addressed by the inlining above.
jam> However, in working through this logic, I'm pretty sure it is
jam> wrong. Specifically, consider the case where "final_name"
jam> raises an exception.
Bah, nice catch. While restarting the branch from scratch I missed that,
thanks.
<snip/>
jam> I'm hesitant, but okay with landing the patch. You've pretty
jam> clearly demonstrated that it fixes the problem. The hesitancy
jam> is that it "doesn't make sense" to me. Which is fairly serious,
I share the feeling but for different reasons. That makes it even more
serious, but I think the correct way to fix that is to add more tests
for transform and push down fix_root() and fixup_new_roots() which
sounds even more like 'accumulating cruft' to me. Hopefully we'll be
able to also address the switch-the-winners in _merge_names doing so.
jam> but we've already spent far too long on this. I don't see it
jam> getting much better without some more serious surgery on the
jam> internals of merge and transform...
There we fully agree on both points.
I'll merge with the fixes mentioned above, yell if you disagree ;-)