I've tracked this down to a simple logic bug in _discard_merge_parents. It iterates through, and for blocks with all removed children, it removes the whole thing in one pass, rather than removing the children one by one. But the check for 'all removed children' was incorrect.
The actual fix is almost trivial:
=== modified file 'bzrlib/dirstate.py'
--- bzrlib/dirstate.py 2007-11-05 19:40:28 +0000
+++ bzrlib/dirstate.py 2007-11-14 20:10:39 +0000
@@ -914,7 +914,7 @@ if (entry[1][0][0], entry[1][1][0]) in dead_patterns: deleted_positions.append(pos)
if deleted_positions:
- if len(deleted_positions) == len(block):
+ if len(deleted_positions) == len(block[1]): del block[1][:] else: for pos in reversed(deleted_positions):
The reason it is only triggered under the given conditions, is that you must have exactly 2 deleted items. And then it accidentally deletes the whole block.
I've tracked this down to a simple logic bug in _discard_ merge_parents. It iterates through, and for blocks with all removed children, it removes the whole thing in one pass, rather than removing the children one by one. But the check for 'all removed children' was incorrect.
The actual fix is almost trivial: dirstate. py'
if (entry[1][0][0], entry[1][1][0]) in dead_patterns:
deleted_ positions. append( pos) positions) == len(block): positions) == len(block[1]):
del block[1][:]
else:
for pos in reversed( deleted_ positions) :
=== modified file 'bzrlib/
--- bzrlib/dirstate.py 2007-11-05 19:40:28 +0000
+++ bzrlib/dirstate.py 2007-11-14 20:10:39 +0000
@@ -914,7 +914,7 @@
if deleted_positions:
- if len(deleted_
+ if len(deleted_
The reason it is only triggered under the given conditions, is that you must have exactly 2 deleted items. And then it accidentally deletes the whole block.