Rev 3472: (jam) Fix bug #235407, if someone merges the same revision twice, in file:///home/pqm/archives/thelove/bzr/%2Btrunk/
Canonical.com Patch Queue Manager
pqm at pqm.ubuntu.com
Wed Jun 4 23:21:56 BST 2008
At file:///home/pqm/archives/thelove/bzr/%2Btrunk/
------------------------------------------------------------
revno: 3472
revision-id:pqm at pqm.ubuntu.com-20080604222149-sq8txbpiit3ckogx
parent: pqm at pqm.ubuntu.com-20080604192001-6k9g6cztr5beg1k5
parent: john at arbash-meinel.com-20080604215505-ko3ifumiiyn2vi6k
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Wed 2008-06-04 23:21:49 +0100
message:
(jam) Fix bug #235407, if someone merges the same revision twice,
don't record the second one.
modified:
NEWS NEWS-20050323055033-4e00b5db738777ff
bzrlib/tests/blackbox/test_uncommit.py test_uncommit.py-20051027212835-84944b63adae51be
bzrlib/tests/test_workingtree_4.py test_workingtree_4.p-20070223025758-531n3tznl3zacv2o-1
bzrlib/tests/workingtree_implementations/test_parents.py test_set_parents.py-20060807231740-yicmnlci1mj8smu1-1
bzrlib/workingtree.py workingtree.py-20050511021032-29b6ec0a681e02e3
bzrlib/workingtree_4.py workingtree_4.py-20070208044105-5fgpc5j3ljlh5q6c-1
------------------------------------------------------------
revno: 3462.1.7
revision-id:john at arbash-meinel.com-20080604215505-ko3ifumiiyn2vi6k
parent: john at arbash-meinel.com-20080604175630-tngg9jlwn6jzebgv
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: status_double_pending_235407
timestamp: Wed 2008-06-04 16:55:05 -0500
message:
fix a test that assumed WT4.set_parent_trees() wouldn't filter the list.
modified:
bzrlib/tests/test_workingtree_4.py test_workingtree_4.p-20070223025758-531n3tznl3zacv2o-1
------------------------------------------------------------
revno: 3462.1.6
revision-id:john at arbash-meinel.com-20080604175630-tngg9jlwn6jzebgv
parent: john at arbash-meinel.com-20080604175452-l0iwbtdlkdrbpnjc
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: status_double_pending_235407
timestamp: Wed 2008-06-04 12:56:30 -0500
message:
Update news for IN DEVELOPMENT
modified:
NEWS NEWS-20050323055033-4e00b5db738777ff
------------------------------------------------------------
revno: 3462.1.5
revision-id:john at arbash-meinel.com-20080604175452-l0iwbtdlkdrbpnjc
parent: john at arbash-meinel.com-20080604175258-ez2d1z1vpnucpjwy
parent: pqm at pqm.ubuntu.com-20080604174215-d0m8mjs939ek9ed7
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: status_double_pending_235407
timestamp: Wed 2008-06-04 12:54:52 -0500
message:
merge bzr.dev
modified:
NEWS NEWS-20050323055033-4e00b5db738777ff
bzrlib/__init__.py __init__.py-20050309040759-33e65acf91bbcd5d
bzrlib/branch.py branch.py-20050309040759-e4baf4e0d046576e
bzrlib/lockdir.py lockdir.py-20060220222025-98258adf27fbdda3
bzrlib/remote.py remote.py-20060720103555-yeeg2x51vn0rbtdp-1
bzrlib/repository.py rev_storage.py-20051111201905-119e9401e46257e3
bzrlib/revisionspec.py revisionspec.py-20050907152633-17567659fd5c0ddb
bzrlib/smart/client.py client.py-20061116014825-2k6ada6xgulslami-1
bzrlib/smart/message.py message.py-20080222013625-ncqmh3nrxjkxab87-1
bzrlib/tests/branch_implementations/test_branch.py testbranch.py-20050711070244-121d632bc37d7253
bzrlib/tests/test_branch.py test_branch.py-20060116013032-97819aa07b8ab3b5
bzrlib/tests/test_lockdir.py test_lockdir.py-20060220222025-33d4221569a3d600
bzrlib/tests/test_revisionspec.py testrevisionnamespaces.py-20050711050225-8b4af89e6b1efe84
bzrlib/tests/test_smart_transport.py test_ssh_transport.py-20060608202016-c25gvf1ob7ypbus6-2
bzrlib/tests/test_switch.py test_switch.py-20071116011000-v5lnw7d2wkng9eux-2
bzrlib/workingtree_4.py workingtree_4.py-20070208044105-5fgpc5j3ljlh5q6c-1
------------------------------------------------------------
revno: 3462.1.4
revision-id:john at arbash-meinel.com-20080604175258-ez2d1z1vpnucpjwy
parent: john at arbash-meinel.com-20080603175114-orr0xe2xg41dus7n
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: status_double_pending_235407
timestamp: Wed 2008-06-04 12:52:58 -0500
message:
fix up the uncommit tests now that set_parent_ids is filtering out ancestors.
modified:
bzrlib/tests/blackbox/test_uncommit.py test_uncommit.py-20051027212835-84944b63adae51be
------------------------------------------------------------
revno: 3462.1.3
revision-id:john at arbash-meinel.com-20080603175114-orr0xe2xg41dus7n
parent: john at arbash-meinel.com-20080602160909-u5q4mzn2ou6kz2r7
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: status_double_pending_235407
timestamp: Tue 2008-06-03 12:51:14 -0500
message:
Remove the workaround in status, assuming that set_parent_(trees/ids) will do it for us.
modified:
bzrlib/status.py status.py-20050505062338-431bfa63ec9b19e6
------------------------------------------------------------
revno: 3462.1.2
revision-id:john at arbash-meinel.com-20080602160909-u5q4mzn2ou6kz2r7
parent: john at arbash-meinel.com-20080530222904-sn1c8r4ge8olh4r5
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: status_double_pending_235407
timestamp: Mon 2008-06-02 11:09:09 -0500
message:
Change WT.set_parent_(ids/trees) to filter out ancestors.
This makes it impossible to trigger bug #235407, since we can't have repeated
ancestors given.
modified:
NEWS NEWS-20050323055033-4e00b5db738777ff
bzrlib/tests/test_status.py test_status.py-20060516190614-fbf6432e4a6e8aa5
bzrlib/tests/workingtree_implementations/test_parents.py test_set_parents.py-20060807231740-yicmnlci1mj8smu1-1
bzrlib/workingtree.py workingtree.py-20050511021032-29b6ec0a681e02e3
bzrlib/workingtree_4.py workingtree_4.py-20070208044105-5fgpc5j3ljlh5q6c-1
------------------------------------------------------------
revno: 3462.1.1
revision-id:john at arbash-meinel.com-20080530222904-sn1c8r4ge8olh4r5
parent: pqm at pqm.ubuntu.com-20080530080302-j1jh2bwxmpd0jn2q
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: status_double_pending_235407
timestamp: Fri 2008-05-30 17:29:04 -0500
message:
Fix bug #235407, when the same revision is merged twice
bzr status should at least show the top-level revision again,
even though that merge introduced no new revisions.
modified:
NEWS NEWS-20050323055033-4e00b5db738777ff
bzrlib/status.py status.py-20050505062338-431bfa63ec9b19e6
bzrlib/tests/test_status.py test_status.py-20060516190614-fbf6432e4a6e8aa5
=== modified file 'NEWS'
--- a/NEWS 2008-06-04 07:29:35 +0000
+++ b/NEWS 2008-06-04 17:56:30 +0000
@@ -5,6 +5,23 @@
.. contents::
+IN DEVELOPMENT
+--------------
+
+ BUGFIXES:
+
+ * ``bzr status`` was breaking if you merged the same revision twice.
+ (John Arbash Meinel, #235407)
+
+ API CHANGES:
+
+ * ``WorkingTree.set_parent_(ids/trees)`` will now filter out revisions
+ which are in the ancestry of other revisions. So if you merge the same
+ tree twice, or merge an ancestor of an existing merge, it will only
+ record the newest. (If you merge a descendent, it will replace its
+ ancestor). (John Arbash Meinel, #235407)
+
+
bzr 1.6beta1 2008-06-02
-----------------------
@@ -69,6 +86,9 @@
* ``bzr merge --lca`` should handle when two revisions have no common
ancestor other than NULL_REVISION. (John Arbash Meinel, #235715)
+ * ``bzr status`` was breaking if you merged the same revision twice.
+ (John Arbash Meinel, #235407)
+
* ``bzr push`` with both ``--overwrite`` and ``-r NNN`` options no longer
fails. (Andrew Bennetts, #234229)
@@ -194,6 +214,12 @@
insert_record_stream are meant to efficiently replace this method.
(Robert Collins)
+ * ``WorkingTree.set_parent_(ids/trees)`` will now filter out revisions
+ which are in the ancestry of other revisions. So if you merge the same
+ tree twice, or merge an ancestor of an existing merge, it will only
+ record the newest. (If you merge a descendent, it will replace its
+ ancestor). (John Arbash Meinel, #235407)
+
* ``WorkingTreeFormat2.stub_initialize_remote`` is now private.
(Martin Pool)
=== modified file 'bzrlib/tests/blackbox/test_uncommit.py'
--- a/bzrlib/tests/blackbox/test_uncommit.py 2008-03-16 10:44:11 +0000
+++ b/bzrlib/tests/blackbox/test_uncommit.py 2008-06-04 17:52:58 +0000
@@ -173,47 +173,49 @@
wt = self.create_simple_tree()
tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
-
tree2.commit('unchanged', rev_id='b3')
+ tree3 = wt.bzrdir.sprout('tree3').open_workingtree()
+ tree3.commit('unchanged', rev_id='c3')
+
wt.merge_from_branch(tree2.branch)
wt.commit('merge b3', rev_id='a3')
- tree2.commit('unchanged', rev_id='b4')
-
- wt.merge_from_branch(tree2.branch)
- wt.commit('merge b4', rev_id='a4')
+ wt.merge_from_branch(tree3.branch)
+ wt.commit('merge c3', rev_id='a4')
self.assertEqual(['a4'], wt.get_parent_ids())
os.chdir('tree')
out, err = self.run_bzr('uncommit --force -r 2')
- self.assertEqual(['a2', 'b3', 'b4'], wt.get_parent_ids())
+ self.assertEqual(['a2', 'b3', 'c3'], wt.get_parent_ids())
def test_uncommit_merge_plus_pending(self):
wt = self.create_simple_tree()
tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
-
tree2.commit('unchanged', rev_id='b3')
+ tree3 = wt.bzrdir.sprout('tree3').open_workingtree()
+ tree3.commit('unchanged', rev_id='c3')
+
wt.branch.fetch(tree2.branch)
wt.set_pending_merges(['b3'])
wt.commit('merge b3', rev_id='a3')
- tree2.commit('unchanged', rev_id='b4')
- wt.branch.fetch(tree2.branch)
- wt.set_pending_merges(['b4'])
-
- self.assertEqual(['a3', 'b4'], wt.get_parent_ids())
+
+ wt.merge_from_branch(tree3.branch)
+
+ self.assertEqual(['a3', 'c3'], wt.get_parent_ids())
os.chdir('tree')
out, err = self.run_bzr('uncommit --force -r 2')
- self.assertEqual(['a2', 'b3', 'b4'], wt.get_parent_ids())
+ self.assertEqual(['a2', 'b3', 'c3'], wt.get_parent_ids())
def test_uncommit_octopus_merge(self):
# Check that uncommit keeps the pending merges in the same order
+ # though it will also filter out ones in the ancestry
wt = self.create_simple_tree()
tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
@@ -238,7 +240,7 @@
os.chdir('tree')
out, err = self.run_bzr('uncommit --force -r 2')
- self.assertEqual(['a2', 'b3', 'c3', 'c4', 'b4'], wt.get_parent_ids())
+ self.assertEqual(['a2', 'c4', 'b4'], wt.get_parent_ids())
def test_uncommit_nonascii(self):
tree = self.make_branch_and_tree('tree')
=== modified file 'bzrlib/tests/test_workingtree_4.py'
--- a/bzrlib/tests/test_workingtree_4.py 2008-03-07 14:15:10 +0000
+++ b/bzrlib/tests/test_workingtree_4.py 2008-06-04 21:55:05 +0000
@@ -115,17 +115,19 @@
rev2 = subtree2.commit('commit in subdir2')
subtree.flush()
- subtree.merge_from_branch(subtree2.branch)
- rev3 = subtree.commit('merge from subdir2')
+ subtree3 = subtree.bzrdir.sprout('subdir3').open_workingtree()
+ rev3 = subtree3.commit('merge from subdir2')
repo = tree.branch.repository
- repo.fetch(subtree.branch.repository, rev3)
+ repo.fetch(subtree.branch.repository, rev1)
+ repo.fetch(subtree2.branch.repository, rev2)
+ repo.fetch(subtree3.branch.repository, rev3)
# will also pull the others...
# create repository based revision trees
- rev1_revtree = subtree.branch.repository.revision_tree(rev1)
- rev2_revtree = subtree2.branch.repository.revision_tree(rev2)
- rev3_revtree = subtree.branch.repository.revision_tree(rev3)
+ rev1_revtree = repo.revision_tree(rev1)
+ rev2_revtree = repo.revision_tree(rev2)
+ rev3_revtree = repo.revision_tree(rev3)
# tree doesn't contain a text merge yet but we'll just
# set the parents as if a merge had taken place.
# this should cause the tree data to be folded into the
=== modified file 'bzrlib/tests/workingtree_implementations/test_parents.py'
--- a/bzrlib/tests/workingtree_implementations/test_parents.py 2008-05-02 07:31:24 +0000
+++ b/bzrlib/tests/workingtree_implementations/test_parents.py 2008-06-02 16:09:09 +0000
@@ -160,6 +160,73 @@
self.assertConsistentParents(
[first_revision, second_revision, third_revision], t)
+ def test_set_duplicate_parent_ids(self):
+ t = self.make_branch_and_tree('.')
+ rev1 = t.commit('first post')
+ uncommit(t.branch, tree=t)
+ rev2 = t.commit('second post')
+ uncommit(t.branch, tree=t)
+ rev3 = t.commit('third post')
+ uncommit(t.branch, tree=t)
+ t.set_parent_ids([rev1, rev2, rev2, rev3])
+ # We strip the duplicate, but preserve the ordering
+ self.assertConsistentParents([rev1, rev2, rev3], t)
+
+ def test_set_duplicate_parent_trees(self):
+ t = self.make_branch_and_tree('.')
+ rev1 = t.commit('first post')
+ uncommit(t.branch, tree=t)
+ rev2 = t.commit('second post')
+ uncommit(t.branch, tree=t)
+ rev3 = t.commit('third post')
+ uncommit(t.branch, tree=t)
+ rev_tree1 = t.branch.repository.revision_tree(rev1)
+ rev_tree2 = t.branch.repository.revision_tree(rev2)
+ rev_tree3 = t.branch.repository.revision_tree(rev3)
+ t.set_parent_trees([(rev1, rev_tree1), (rev2, rev_tree2),
+ (rev2, rev_tree2), (rev3, rev_tree3)])
+ # We strip the duplicate, but preserve the ordering
+ self.assertConsistentParents([rev1, rev2, rev3], t)
+
+ def test_set_parent_ids_in_ancestry(self):
+ t = self.make_branch_and_tree('.')
+ rev1 = t.commit('first post')
+ rev2 = t.commit('second post')
+ rev3 = t.commit('third post')
+ # Reset the tree, back to rev1
+ t.set_parent_ids([rev1])
+ t.branch.set_last_revision_info(1, rev1)
+ self.assertConsistentParents([rev1], t)
+ t.set_parent_ids([rev1, rev2, rev3])
+ # rev2 is in the ancestry of rev3, so it will be filtered out
+ self.assertConsistentParents([rev1, rev3], t)
+ # Order should be preserved, and the first revision should always be
+ # kept
+ t.set_parent_ids([rev2, rev3, rev1])
+ self.assertConsistentParents([rev2, rev3], t)
+
+ def test_set_parent_trees_in_ancestry(self):
+ t = self.make_branch_and_tree('.')
+ rev1 = t.commit('first post')
+ rev2 = t.commit('second post')
+ rev3 = t.commit('third post')
+ # Reset the tree, back to rev1
+ t.set_parent_ids([rev1])
+ t.branch.set_last_revision_info(1, rev1)
+ self.assertConsistentParents([rev1], t)
+ rev_tree1 = t.branch.repository.revision_tree(rev1)
+ rev_tree2 = t.branch.repository.revision_tree(rev2)
+ rev_tree3 = t.branch.repository.revision_tree(rev3)
+ t.set_parent_trees([(rev1, rev_tree1), (rev2, rev_tree2),
+ (rev3, rev_tree3)])
+ # rev2 is in the ancestry of rev3, so it will be filtered out
+ self.assertConsistentParents([rev1, rev3], t)
+ # Order should be preserved, and the first revision should always be
+ # kept
+ t.set_parent_trees([(rev2, rev_tree2), (rev1, rev_tree1),
+ (rev3, rev_tree3)])
+ self.assertConsistentParents([rev2, rev3], t)
+
class TestAddParent(TestParents):
=== modified file 'bzrlib/workingtree.py'
--- a/bzrlib/workingtree.py 2008-05-22 05:48:22 +0000
+++ b/bzrlib/workingtree.py 2008-06-02 16:09:09 +0000
@@ -724,6 +724,25 @@
self._transport.put_bytes('pending-merges', '\n'.join(merges),
mode=self._control_files._file_mode)
+ def _filter_parent_ids_by_ancestry(self, revision_ids):
+ """Check that all merged revisions are proper 'heads'.
+
+ This will always return the first revision_id, and any merged revisions
+ which are
+ """
+ if len(revision_ids) == 0:
+ return revision_ids
+ graph = self.branch.repository.get_graph()
+ heads = graph.heads(revision_ids)
+ new_revision_ids = revision_ids[:1]
+ for revision_id in revision_ids[1:]:
+ if revision_id in heads and revision_id not in new_revision_ids:
+ new_revision_ids.append(revision_id)
+ if new_revision_ids != revision_ids:
+ trace.mutter('requested to set revision_ids = %s,'
+ ' but filtered to %s', revision_ids, new_revision_ids)
+ return new_revision_ids
+
@needs_tree_write_lock
def set_parent_ids(self, revision_ids, allow_leftmost_as_ghost=False):
"""Set the parent ids to revision_ids.
@@ -742,6 +761,8 @@
for revision_id in revision_ids:
_mod_revision.check_not_reserved_id(revision_id)
+ revision_ids = self._filter_parent_ids_by_ancestry(revision_ids)
+
if len(revision_ids) > 0:
self.set_last_revision(revision_ids[0])
else:
@@ -759,6 +780,8 @@
self._check_parents_for_ghosts(parent_ids,
allow_leftmost_as_ghost=allow_leftmost_as_ghost)
+ parent_ids = self._filter_parent_ids_by_ancestry(parent_ids)
+
if len(parent_ids) == 0:
leftmost_parent_id = _mod_revision.NULL_REVISION
leftmost_parent_tree = None
=== modified file 'bzrlib/workingtree_4.py'
--- a/bzrlib/workingtree_4.py 2008-06-04 07:29:35 +0000
+++ b/bzrlib/workingtree_4.py 2008-06-04 17:54:52 +0000
@@ -1085,9 +1085,21 @@
raise errors.GhostRevisionUnusableHere(parents_list[0][0])
real_trees = []
ghosts = []
+
+ parent_ids = [rev_id for rev_id, tree in parents_list]
+ graph = self.branch.repository.get_graph()
+ heads = graph.heads(parent_ids)
+ accepted_revisions = set()
+
# convert absent trees to the null tree, which we convert back to
# missing on access.
for rev_id, tree in parents_list:
+ if len(accepted_revisions) > 0:
+ # we always accept the first tree
+ if rev_id in accepted_revisions or rev_id not in heads:
+ # We have already included either this tree, or its
+ # descendent, so we skip it.
+ continue
_mod_revision.check_not_reserved_id(rev_id)
if tree is not None:
real_trees.append((rev_id, tree))
@@ -1095,6 +1107,7 @@
real_trees.append((rev_id,
self.branch.repository.revision_tree(None)))
ghosts.append(rev_id)
+ accepted_revisions.add(rev_id)
dirstate.set_parent_trees(real_trees, ghosts=ghosts)
self._make_dirty(reset_inventory=False)
More information about the bazaar-commits
mailing list