[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