[RFC] _show_log supporting unmerged revisions (first step towards lp #4663)
Wouter van Heyst
larstiq at larstiq.dyndns.org
Mon Jun 19 13:53:23 BST 2006
On Sun, Jun 18, 2006 at 01:04:13PM -0500, John Arbash Meinel wrote:
...
> I didn't really look at all of your steps, so I'll wait for your new
> patch and review again.
Just to get it out in the open, this is what I currently have.
Wouter van Heyst
-------------- next part --------------
=== modified file 'README'
--- README 2006-06-15 14:12:06 +0000
+++ README 2006-06-16 15:56:09 +0000
@@ -30,4 +30,3 @@
or run "bzr help"
For installation instructions see ./INSTALL
-aaaaa
=== modified file 'bzrlib/log.py'
--- bzrlib/log.py 2006-06-18 23:06:36 +0000
+++ bzrlib/log.py 2006-06-19 00:05:36 +0000
@@ -190,48 +190,87 @@
else:
searchRE = None
- which_revs = _enumerate_history(branch)
-
+ revision_history = set(branch.revision_history())
+
+ def is_mainline(rev):
+ """Check if a revision is in the mainline of a branch."""
+ return rev in revision_history
+
+
if start_revision is None:
- start_revision = 1
+ start_revno = 1
else:
- branch.check_real_revno(start_revision)
+ if isinstance(start_revision, basestring):
+ # start from the last revision in the ancestry of start_revision
+ # that is still on the mainline. This can be start_revision itself.
+ start_revno = None
+
+ for ancestor in reversed(branch.repository.get_ancestry(start_revision)):
+ if is_mainline(ancestor):
+ start_revno = branch.revision_id_to_revno(ancestor)
+ break
+ branch.check_real_revno(start_revno)
+ else:
+ # if we get passed a revno, check that it is real
+ start_revno = start_revision
+ branch.check_real_revno(start_revno)
+ start_revision = branch.get_rev_id(start_revno)
if end_revision is None:
- end_revision = len(which_revs)
- else:
- branch.check_real_revno(end_revision)
-
- # list indexes are 0-based; revisions are 1-based
- cut_revs = which_revs[(start_revision-1):(end_revision)]
- if not cut_revs:
- return
- # override the mainline to look like the revision history.
- mainline_revs = [revision_id for index, revision_id in cut_revs]
- if cut_revs[0][0] == 1:
- mainline_revs.insert(0, None)
- else:
- mainline_revs.insert(0, which_revs[start_revision-2][1])
+ end_revno = len(revision_history)
+ if end_revno == 0:
+ return
+ tip = branch.last_revision()
+ else:
+ if isinstance(end_revision, basestring):
+ # make sure it is in the ancestry
+ tip = end_revision
+ else:
+ # if we get passed a revno, check that it is real
+ branch.check_real_revno(end_revision)
+ tip = branch.get_rev_id(end_revision)
merge_sorted_revisions = merge_sort(
- branch.repository.get_revision_graph(mainline_revs[-1]),
- mainline_revs[-1],
- mainline_revs)
+ branch.repository.get_revision_graph(tip),
+ tip
+ )
+
+ # how many mainline revisions does merge_sort() think we have?
+ zerodepths = 0
+
+ if start_revision is not start_revno:
+ sorted_merge = []
+ hit = False
+ for packed in merge_sorted_revisions:
+ rev_id = packed[1]
+ if hit:
+ if is_mainline(rev_id):
+ break
+
+ if packed[2] == 0:
+ zerodepths += 1
+
+ sorted_merge.append(packed)
+ if rev_id == start_revision:
+ # for mainline revisions we also want to show merged revisions
+ if is_mainline(start_revision):
+ hit = True
+ else:
+ break
+
+ merge_sorted_revisions = sorted_merge
+ else:
+ zerodepths = sum(1 for pack in merge_sorted_revisions if pack[2] == 0)
+ rev_nos = range(start_revno, start_revno + zerodepths)
if direction == 'reverse':
- cut_revs.reverse()
+ rev_nos.reverse()
elif direction == 'forward':
# forward means oldest first.
merge_sorted_revisions.reverse()
else:
raise ValueError('invalid direction %r' % direction)
- revision_history = branch.revision_history()
-
- # convert the revision history to a dictionary:
- rev_nos = {}
- for index, rev_id in cut_revs:
- rev_nos[rev_id] = index
def iter_revisions():
revision_ids = [r for s, r, m, e in merge_sorted_revisions]
@@ -246,7 +285,9 @@
revisions = branch.repository.get_revisions()
for revision in revisions:
yield revision
+
# now we just print all the revisions
+ rev_index = 0
for ((sequence, rev_id, merge_depth, end_of_merge), rev) in \
izip(merge_sorted_revisions, iter_revisions()):
@@ -257,7 +298,8 @@
if merge_depth == 0:
# a mainline revision.
if verbose or specific_fileid:
- delta = _get_revision_delta(branch, rev_nos[rev_id])
+ # FIXME: this will go wrong for non-mainline as 'mainline' revisions
+ delta = _get_revision_delta(branch, rev_nos[rev_index])
if specific_fileid:
if not delta.touches_file_id(specific_fileid):
@@ -267,7 +309,8 @@
# although we calculated it, throw it away without display
delta = None
- lf.show(rev_nos[rev_id], rev, delta)
+ lf.show(rev_nos[rev_index], rev, delta)
+ rev_index += 1
elif hasattr(lf, 'show_merge'):
lf.show_merge(rev, merge_depth)
=== modified file 'bzrlib/tests/test_log.py'
--- bzrlib/tests/test_log.py 2006-06-14 11:00:25 +0000
+++ bzrlib/tests/test_log.py 2006-06-18 21:18:53 +0000
@@ -301,3 +301,119 @@
logfile.seek(0)
log_contents = logfile.read()
self.assertEqualDiff(log_contents, '1: Line-Log-Formatte... 2005-11-23 add a\n')
+
+ def test_revision_id_log(self):
+ wt = self.make_branch_and_tree('parent')
+ b = wt.branch
+ os.chdir('parent')
+ self.build_tree(['a', 'b'])
+ wt.add('a')
+ wt.update()
+
+ wt.commit(message='add a',
+ timestamp=1132711707,
+ timezone=36000,
+ rev_id='rev1',
+ committer='merged revision tester <test at merged.rev>')
+
+ wt2 = self.make_branch_and_tree('../child')
+ wt2.pull(wt.branch)
+
+ wt.add('b')
+ wt.commit(message='add b',
+ timestamp=1132711708,
+ timezone=36000,
+ rev_id='rev2',
+ committer='merged revision tester <test at merged.rev>')
+
+ os.chdir('../child')
+ self.build_tree(['c', 'd'])
+ #wt2.update()
+ wt2.add('c')
+ wt2.commit(message='add c',
+ timestamp=1132711709,
+ timezone=36000,
+ rev_id='revchild1',
+ committer='merged revision tester <test at merged.rev>')
+
+ wt2.add('d')
+ wt2.commit(message='add d',
+ timestamp=1132711710,
+ timezone=36000,
+ rev_id='revchild2',
+ committer='merged revision tester <test at merged.rev>')
+
+ os.chdir('../parent')
+ self.run_bzr('merge', '../child')
+ wt.commit(message='[merge] child',
+ timestamp=1132711710,
+ timezone=36000,
+ rev_id='rev3',
+ committer='merged revision tester <test at merged.rev>')
+
+ wt.commit(message='top revision',
+ timestamp=1132711711,
+ timezone=36000,
+ rev_id='rev4',
+ committer='merged revision tester <test at merged.rev>')
+
+ revisions = b.repository.all_revision_ids()
+ rev1, rev2, rev3, rev4 = map(b.get_rev_id, [1, 2, 3, 4])
+ childrev1, childrev2 = set(revisions) - set([rev1, rev2, rev3, rev4])
+
+ def test(expected, rev1, rev2):
+ logfile = file('out.tmp', 'wb')
+ try:
+ lf = LongLogFormatter(to_file=logfile, show_ids=True)
+ show_log(b, lf, start_revision=rev1, end_revision=rev2)
+ finally:
+ logfile.close()
+
+ logfile = file('out.tmp', 'rb')
+ logtext = logfile.read()
+ logfile.close()
+
+ actual = []
+ for rev in revisions:
+ if ((('revision-id: ' + rev) in logtext) or (('merged: ' + rev) in logtext)):
+ actual.append(rev)
+
+ mutter("actual revisions: %r", actual)
+ unwanted = set(revisions) - set(expected)
+
+ for rev in expected:
+ self.assertTrue(rev in actual)
+
+ if unwanted:
+ for rev in unwanted:
+ self.assertFalse(rev in actual)
+
+ from bzrlib.trace import mutter
+
+ test(revisions, None, None)
+ test(revisions, rev1, None)
+ test([rev1], None, rev1)
+
+ test([rev1, rev2], None, rev2)
+ test([rev2, rev3, rev4, childrev1, childrev2], rev2, None)
+
+ test([childrev1, childrev2, rev3], rev3, rev3)
+ test([rev2], rev2, rev2)
+
+ # we look at the mainline of the branch childrev1 was in, not the
+ # mainline of this branch *but up to chilredv1*.
+ # So that does not include rev2, as it is not in the ancestry of
+ # childrev1
+ test([rev1, childrev1], None, childrev1)
+ test([childrev1, childrev2, rev3, rev4], childrev1, None)
+
+ test([childrev1], childrev1, childrev1)
+ test([childrev2, rev3, rev4], childrev2, None)
+ test([rev1, childrev1, childrev2], None, childrev2)
+ test([childrev1, childrev2], childrev1, childrev2)
+
+ # mix revnos and revisions ids
+ test([rev2, rev3, childrev1, childrev2], 2, rev3)
+ test([rev2, rev3, childrev1, childrev2], rev2, 3)
+
+ # TODO: multiple branches that get merged
More information about the bazaar
mailing list