iter_changes, delta consistency and revert
Robert Collins
robertc at robertcollins.net
Tue Aug 4 02:38:55 BST 2009
So, I'm trying to land this iter_changes change. Theres one failure that
has me concerned. I've attached the diff for it below.
Now, its a bit hard to read like this, or even in context, so let me
make it more obvious:
bzr init
mkdir -p a/d/e
mkdir f
touch a/b a/c a/e f/g f/h f/i
bzr add
bzr commit -m 1
bzr mv a/b f/b
bzr mv a/d/e f/e
bzr mv f/g a/g
bzr mv f/h h
bzr mv f j
bzr st a
Now, the last command before my patch does this:
$ bzr st a
renamed:
a/b => j/b
a/d/e/ => j/e/
f/g => a/g
but after applying the patch:
$ bzr st a
renamed:
a/b => j/b
a/d/e/ => j/e/
f/ => j/
f/g => a/g
Now, you may be wondering why 'f->j' is in the status output. Its there
because without it the path of j/b, if applied to an inventory delta,
would be wrong. This matter for dirstate and other path based storage
systems. It also matters for humans, if we say we commit j/b, but
actually commit a/b, thats really confusing - at best.
The problem turns up in revert though. Revert uses iter_changes to
determine what to revert, and the inclusion of j in the output causes it
to revert the f->j rename when 'bzr revert a' is invoked. At a human
level, I would in fact expect 'revert a' to grab the things I'd renamed
out of a and put them back, and not to touch other things that look like
they are incidentally connected.
There is some friction here:
- revert wants 'enough changes to put specified things back the way
they were'
- commit and merge want 'enough changes so that the output tree looks
like the user expects and isn't corrupted'
- status wants to 'show what commit will do'
- I think revert is using iter_changes in a symmetrical way, but
inventory deltas built on iter_changes are not symmetric, and the
iter_changes work I've been doing is likewise not symmetric.
Specifically tree.iter_changes(basis, specific=foo) !=
basis.iter_changes(tree, specific=foo), where expansion for
consistency is concerned.
I have thought of of a few options:
- inspect the iter_changes output inside revert, and discard things
that are not needed.
- make consistent expansion an optional flag to iter_changes and have
revert use that.
However, we've had a number of bugs (going from memory) to do with
revert and dirstate; I'm not at all sure that this is a coincidence -
the very bug I'm fixing, to ensure consistent deltas, may well prevent
those bugs in revert.
I'd rather not have more flags to iter_changes, I think being
conservative and expanding as needed is the safest option. I think
revert is well placed as a special-case (it doesn't need consistency in
output, as its applying things in reverse) to manually filter the
transform it uses back down - by using a simple check that one of the
paths of each item it gets are inside the specified paths.
For now, I've made the failing test a KnownFailure, and would like to
land the changes. This is the bulk of the work, and can be tuned in
various directions quite easily.
=== modified file 'bzrlib/tests/blackbox/test_revert.py'
--- bzrlib/tests/blackbox/test_revert.py 2009-03-23 14:59:43
+0000
+++ bzrlib/tests/blackbox/test_revert.py 2009-08-04 00:59:44
+0000
@@ -96,7 +96,9 @@
self.failUnlessExists('a/b')
self.failUnlessExists('a/d')
self.failIfExists('a/g')
- self.failUnlessExists('j')
+ self.expectFailure(
+ "j is in the delta revert applies because j was renamed
too",
+ self.failUnlessExists, 'j')
self.failUnlessExists('h')
self.run_bzr('revert f')
self.failIfExists('j')
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 197 bytes
Desc: This is a digitally signed message part
Url : https://lists.ubuntu.com/archives/bazaar/attachments/20090804/873fde20/attachment.pgp
More information about the bazaar
mailing list