Rev 3678: Begin fixing bug #233817. in lp:~vila/bzr/233817-missing
Vincent Ladeuil
v.ladeuil+lp at free.fr
Wed Sep 3 17:33:37 BST 2008
At lp:~vila/bzr/233817-missing
------------------------------------------------------------
revno: 3678
revision-id: v.ladeuil+lp at free.fr-20080903163327-hpgcpvx2ziit96og
parent: pqm at pqm.ubuntu.com-20080902062416-dxdxccqki90bcynl
committer: Vincent Ladeuil <v.ladeuil+lp at free.fr>
branch nick: 233817-missing
timestamp: Wed 2008-09-03 18:33:27 +0200
message:
Begin fixing bug #233817.
* tests/test_missing.py:
revnos returned by fin_unmerged are strings, update tests.
(TestFindUnmerged.test_include_merges): Check that we get the
merged revisions too.
* missing.py:
(find_unmerged): Add 'reverse' and 'include_merges' parameters.
(_enumerate_mainline): Add reverse parameter so that we reverse
the mainline revision list only when needed.
(_enumerate_with_merges): When including merges, building the
revision list is a bit more work.
(_find_unmerged): Build the revision list depending on
include_merges.
* log.py:
(LineLogFormatter.log_string): Fix doc string, the revno may be a
string.
* builtins.py:
(cmd_missing): Add an '--include-merges' option. Let fin_unmerged
handles the ordering.
modified:
bzrlib/builtins.py builtins.py-20050830033751-fc01482b9ca23183
bzrlib/log.py log.py-20050505065812-c40ce11702fe5fb1
bzrlib/missing.py missing.py-20050812153334-097f7097e2a8bcd1
bzrlib/tests/test_missing.py test_missing.py-20051212000028-694fa4f658a81f48
-------------- next part --------------
=== modified file 'bzrlib/builtins.py'
--- a/bzrlib/builtins.py 2008-09-01 23:49:18 +0000
+++ b/bzrlib/builtins.py 2008-09-03 16:33:27 +0000
@@ -3318,14 +3318,17 @@
Option('other', 'Same as --theirs-only.'),
'log-format',
'show-ids',
- 'verbose'
+ 'verbose',
+ Option('include-merges', 'Show merged revisions.'),
]
encoding_type = 'replace'
@display_command
def run(self, other_branch=None, reverse=False, mine_only=False,
- theirs_only=False, log_format=None, long=False, short=False, line=False,
- show_ids=False, verbose=False, this=False, other=False):
+ theirs_only=False,
+ log_format=None, long=False, short=False, line=False,
+ show_ids=False, verbose=False, this=False, other=False,
+ include_merges=False):
from bzrlib.missing import find_unmerged, iter_log_revisions
if this:
@@ -3361,7 +3364,9 @@
remote_branch.lock_read()
try:
local_extra, remote_extra = find_unmerged(
- local_branch, remote_branch, restrict)
+ local_branch, remote_branch, restrict,
+ reverse=reverse,
+ include_merges=include_merges)
if log_format is None:
registry = log.log_formatter_registry
@@ -3369,11 +3374,6 @@
lf = log_format(to_file=self.outf,
show_ids=show_ids,
show_timezone='original')
- if reverse is False:
- if local_extra is not None:
- local_extra.reverse()
- if remote_extra is not None:
- remote_extra.reverse()
status_code = 0
if local_extra and not theirs_only:
=== modified file 'bzrlib/log.py'
--- a/bzrlib/log.py 2008-09-01 00:56:53 +0000
+++ b/bzrlib/log.py 2008-09-03 16:33:27 +0000
@@ -642,7 +642,7 @@
elif direction != 'reverse':
raise ValueError('invalid direction %r' % direction)
- for sequence, rev_id, merge_depth, revno, end_of_merge in merge_sorted_revisions:
+ for seq, rev_id, merge_depth, revno, end_of_merge in merge_sorted_revisions:
yield rev_id, '.'.join(map(str, revno)), merge_depth
@@ -865,7 +865,7 @@
def log_string(self, revno, rev, max_chars):
"""Format log info into one string. Truncate tail of string
- :param revno: revision number (int) or None.
+ :param revno: revision number or None.
Revision numbers counts from 1.
:param rev: revision info object
:param max_chars: maximum length of resulting string
=== modified file 'bzrlib/missing.py'
--- a/bzrlib/missing.py 2008-05-20 02:34:01 +0000
+++ b/bzrlib/missing.py 2008-09-03 16:33:27 +0000
@@ -16,8 +16,10 @@
"""Display what revisions are missing in 'other' from 'this' and vice versa."""
-from bzrlib.log import (
- LogRevision,
+from bzrlib import (
+ log,
+ repository as _mod_repository,
+ tsort,
)
@@ -39,10 +41,11 @@
delta = revision_tree.changes_from(parent_tree)
else:
delta = None
- yield LogRevision(rev, revno, delta=delta)
-
-
-def find_unmerged(local_branch, remote_branch, restrict='all'):
+ yield log.LogRevision(rev, revno, delta=delta)
+
+
+def find_unmerged(local_branch, remote_branch, restrict='all',
+ include_merges=False, reverse=False):
"""Find revisions from each side that have not been merged.
:param local_branch: Compare the history of local_branch
@@ -52,6 +55,10 @@
unique revisions from both sides. If 'local', we will return None
for the remote revisions, similarly if 'remote' we will return None for
the local revisions.
+ :param include_merges: Show mainline revisions only if False,
+ all revisions otherwise.
+ :param reverse: Show oldest versions first when True, newest versions
+ first when False.
:return: A list of [(revno, revision_id)] for the mainline revisions on
each side.
@@ -60,15 +67,16 @@
try:
remote_branch.lock_read()
try:
- return _find_unmerged(local_branch,
- remote_branch, restrict=restrict)
+ return _find_unmerged(
+ local_branch, remote_branch, restrict=restrict,
+ include_merges=include_merges, reverse=reverse)
finally:
remote_branch.unlock()
finally:
local_branch.unlock()
-def _enumerate_mainline(ancestry, graph, tip_revno, tip):
+def _enumerate_mainline(ancestry, graph, tip_revno, tip, reverse=False):
"""Enumerate the mainline revisions for these revisions.
:param ancestry: A set of revisions that we care about
@@ -95,14 +103,51 @@
parents = parent_map.get(cur)
if not parents:
break # Ghost, we are done
- mainline.append((cur_revno, cur))
+ mainline.append((str(cur_revno), cur))
cur = parents[0]
cur_revno -= 1
- mainline.reverse()
+ if reverse:
+ mainline.reverse()
return mainline
-def _find_unmerged(local_branch, remote_branch, restrict):
+def _enumerate_with_merges(ancestry, graph, tip_revno, tip, reverse=False):
+ """Enumerate the revisions for the ancestry.
+
+ :param ancestry: A set of revisions that we care about
+ :param graph: A Graph which lets us find the parents for a revision
+ :param tip_revno: The revision number for the tip revision
+ :param tip: The tip of the ancsetry
+ :return: [(revno, revision_id)] for all revisions in ancestry that
+ are parents from tip, or None if ancestry is None.
+ """
+ if ancestry is None:
+ return None
+ if not ancestry: #Empty ancestry, no need to do any work
+ return []
+
+ parent_map = graph.get_parent_map(ancestry)
+ # filter out ghosts; merge_sort errors on ghosts.
+ # XXX: is this needed here ? -- vila080903
+ rev_graph = _mod_repository._strip_NULL_ghosts(parent_map)
+ # XXX: what if rev_graph is empty now ?
+ merge_sorted_revisions = tsort.merge_sort(rev_graph, tip,
+ None, generate_revno=True)
+ # merge_sort calculate revno for the given graph, we have to recalculate
+ # the correct revno from the tip_revno.
+ ms_tip_revno = merge_sorted_revisions[0][3]
+ revno_delta = tip_revno - ms_tip_revno[0]
+ if reverse:
+ merge_sorted_revisions = log.reverse_by_depth(merge_sorted_revisions)
+ revline = []
+ for seq, rev_id, merge_depth, revno, end_of_merge in merge_sorted_revisions:
+ real_revno = (revno[0] + revno_delta,) + revno[1:]
+ revline.append(('.'.join(map(str, real_revno)), rev_id))
+ return revline
+
+
+def _find_unmerged(local_branch, remote_branch, restrict,
+ include_merges, reverse):
"""See find_unmerged.
The branches should already be locked before entering.
@@ -112,29 +157,34 @@
if local_revno == remote_revno and local_revision_id == remote_revision_id:
# A simple shortcut when the tips are at the same point
return [], []
- graph = local_branch.repository.get_graph(
- remote_branch.repository)
+ graph = local_branch.repository.get_graph(remote_branch.repository)
if restrict == 'remote':
local_extra = None
- remote_extra = graph.find_unique_ancestors(
- remote_revision_id, [local_revision_id])
+ remote_extra = graph.find_unique_ancestors(remote_revision_id,
+ [local_revision_id])
elif restrict == 'local':
remote_extra = None
- local_extra = graph.find_unique_ancestors(
- local_revision_id, [remote_revision_id])
+ local_extra = graph.find_unique_ancestors(local_revision_id,
+ [remote_revision_id])
else:
if restrict != 'all':
raise ValueError('param restrict not one of "all", "local",'
' "remote": %r' % (restrict,))
- local_extra, remote_extra = graph.find_difference(
- local_revision_id, remote_revision_id)
- # Now that we have unique ancestors, compute just the mainline, and
- # generate revnos for them.
- local_mainline = _enumerate_mainline(local_extra, graph, local_revno,
- local_revision_id)
- remote_mainline = _enumerate_mainline(remote_extra, graph, remote_revno,
- remote_revision_id)
- return local_mainline, remote_mainline
+ local_extra, remote_extra = graph.find_difference(local_revision_id,
+ remote_revision_id)
+ if include_merges:
+ locals = _enumerate_with_merges(local_extra, graph, local_revno,
+ local_revision_id, reverse)
+ remotes = _enumerate_with_merges(remote_extra, graph, remote_revno,
+ remote_revision_id, reverse)
+ else:
+ # Now that we have unique ancestors, compute just the mainline, and
+ # generate revnos for them.
+ locals = _enumerate_mainline(local_extra, graph, local_revno,
+ local_revision_id, reverse)
+ remotes = _enumerate_mainline(remote_extra, graph, remote_revno,
+ remote_revision_id, reverse)
+ return locals, remotes
def sorted_revisions(revisions, history_map):
=== modified file 'bzrlib/tests/test_missing.py'
--- a/bzrlib/tests/test_missing.py 2008-05-19 21:35:52 +0000
+++ b/bzrlib/tests/test_missing.py 2008-09-03 16:33:27 +0000
@@ -33,7 +33,7 @@
def assertUnmerged(self, expected, source, target, restrict='all'):
unmerged = missing.find_unmerged(source, target, restrict=restrict)
self.assertEqual(expected, unmerged)
-
+
def test_find_unmerged(self):
original_tree = self.make_branch_and_tree('original')
original = original_tree.branch
@@ -43,24 +43,24 @@
merger = merger_tree.branch
self.assertUnmerged(([], []), original, puller)
original_tree.commit('a', rev_id='a')
- self.assertUnmerged(([(1, 'a')], []), original, puller)
+ self.assertUnmerged(([('1', 'a')], []), original, puller)
puller_tree.pull(original)
self.assertUnmerged(([], []), original, puller)
merger_tree.pull(original)
original_tree.commit('b', rev_id='b')
original_tree.commit('c', rev_id='c')
- self.assertUnmerged(([(2, 'b'), (3, 'c')], []),
+ self.assertUnmerged(([('2', 'b'), ('3', 'c')], []),
original, puller)
puller_tree.pull(original)
self.assertUnmerged(([], []), original, puller)
- self.assertUnmerged(([(2, 'b'), (3, 'c')], []),
+ self.assertUnmerged(([('2', 'b'), ('3', 'c')], []),
original, merger)
merger_tree.merge_from_branch(original)
- self.assertUnmerged(([(2, 'b'), (3, 'c')], []),
+ self.assertUnmerged(([('2', 'b'), ('3', 'c')], []),
original, merger)
merger_tree.commit('d', rev_id='d')
- self.assertUnmerged(([], [(2, 'd')]), original, merger)
+ self.assertUnmerged(([], [('2', 'd')]), original, merger)
def test_iter_log_revisions(self):
base_tree = self.make_branch_and_tree('base')
@@ -85,7 +85,7 @@
base_extra, child_extra = missing.find_unmerged(base_tree.branch,
child_tree.branch)
- results = list(iter_log_revisions(base_extra,
+ results = list(iter_log_revisions(base_extra,
base_tree.branch.repository,
verbose=True))
self.assertEqual([], results)
@@ -97,10 +97,10 @@
r0,r1,r2,r3 = results
- self.assertEqual((2, 'c-2'), (r0.revno, r0.rev.revision_id))
- self.assertEqual((3, 'c-3'), (r1.revno, r1.rev.revision_id))
- self.assertEqual((4, 'c-4'), (r2.revno, r2.rev.revision_id))
- self.assertEqual((5, 'c-5'), (r3.revno, r3.rev.revision_id))
+ self.assertEqual(('2', 'c-2'), (r0.revno, r0.rev.revision_id))
+ self.assertEqual(('3', 'c-3'), (r1.revno, r1.rev.revision_id))
+ self.assertEqual(('4', 'c-4'), (r2.revno, r2.rev.revision_id))
+ self.assertEqual(('5', 'c-5'), (r3.revno, r3.rev.revision_id))
delta0 = r0.delta
self.assertNotEqual(None, delta0)
@@ -135,10 +135,11 @@
class TestFindUnmerged(tests.TestCaseWithTransport):
def assertUnmerged(self, local, remote, local_branch, remote_branch,
- restrict):
+ restrict, include_merges=False):
"""Check the output of find_unmerged_mainline_revisions"""
local_extra, remote_extra = missing.find_unmerged(
- local_branch, remote_branch, restrict)
+ local_branch, remote_branch, restrict,
+ include_merges=include_merges)
self.assertEqual(local, local_extra)
self.assertEqual(remote, remote_extra)
@@ -154,25 +155,17 @@
rev1 = tree.commit('one')
tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
rev2 = tree2.commit('two')
- tree.lock_read()
- self.addCleanup(tree.unlock)
- tree2.lock_read()
- self.addCleanup(tree2.unlock)
- self.assertUnmerged([], [(2, rev2)], tree.branch, tree2.branch, 'all')
- self.assertUnmerged([(2, rev2)], [], tree2.branch, tree.branch, 'all')
+ self.assertUnmerged([], [('2', rev2)], tree.branch, tree2.branch, 'all')
+ self.assertUnmerged([('2', rev2)], [], tree2.branch, tree.branch, 'all')
def test_restrict(self):
tree = self.make_branch_and_tree('tree')
rev1 = tree.commit('one')
tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
rev2 = tree2.commit('two')
- tree.lock_read()
- self.addCleanup(tree.unlock)
- tree2.lock_read()
- self.addCleanup(tree2.unlock)
- self.assertUnmerged([], [(2, rev2)], tree.branch, tree2.branch, 'all')
+ self.assertUnmerged([], [('2', rev2)], tree.branch, tree2.branch, 'all')
self.assertUnmerged([], None, tree.branch, tree2.branch, 'local')
- self.assertUnmerged(None, [(2, rev2)], tree.branch, tree2.branch,
+ self.assertUnmerged(None, [('2', rev2)], tree.branch, tree2.branch,
'remote')
def test_merged(self):
@@ -184,9 +177,29 @@
tree.merge_from_branch(tree2.branch)
rev4 = tree.commit('four')
- tree.lock_read()
- self.addCleanup(tree.unlock)
- tree2.lock_read()
- self.addCleanup(tree2.unlock)
-
- self.assertUnmerged([(2, rev4)], [], tree.branch, tree2.branch, 'all')
+ self.assertUnmerged([('2', rev4)], [], tree.branch, tree2.branch, 'all')
+
+ def test_include_merges(self):
+ tree = self.make_branch_and_tree('tree')
+ rev1 = tree.commit('one', rev_id='rev1')
+
+ tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
+ rev2 = tree2.commit('two', rev_id='rev2')
+ rev3 = tree2.commit('three', rev_id='rev3')
+
+ tree3 = tree2.bzrdir.sprout('tree3').open_workingtree()
+ rev4 = tree3.commit('four', rev_id='rev4')
+ rev5 = tree3.commit('five', rev_id='rev5')
+
+ tree2.merge_from_branch(tree3.branch)
+ rev6 = tree2.commit('six', rev_id='rev6')
+
+ import pdb; pdb.set_trace()
+ self.assertUnmerged([], [('4', 'rev6'),
+ ('3.1.2', 'rev5'), ('3.1.1', 'rev4'),
+ ('3', 'rev3'), ('2', 'rev2'),
+ ],
+ tree.branch, tree2.branch, 'all',
+ include_merges=True)
+
+ # TODO: test_dont_include_already_merged_merges ?
More information about the bazaar-commits
mailing list