Merged revisions in log
Gustavo Niemeyer
gustavo at niemeyer.net
Fri Sep 30 17:08:12 BST 2005
The attached patch adds support for showing merged revisions
in the log, and was built against the current newformat branch.
Here is an example of how it looks.
------------------------------------------------------------
revno: 2
committer: Gustavo Niemeyer <gustavo at niemeyer.net>
timestamp: Thu 2005-09-29 13:41:13 -0300
message:
Merging file2 and file3, from repos2, into repos1.
------------------------------------------------------------
merged: gustavo at niemeyer.net-20050929164020-03a1d6aafde5c9b7
committer: Gustavo Niemeyer <gustavo at niemeyer.net>
timestamp: Thu 2005-09-29 13:40:20 -0300
message:
Merging file3, from repos3, into repos2.
------------------------------------------------------------
merged: gustavo at niemeyer.net-20050929163936-b5eb0a989f29a33d
committer: Gustavo Niemeyer <gustavo at niemeyer.net>
timestamp: Thu 2005-09-29 13:39:36 -0300
message:
Adding file3, on repos3.
------------------------------------------------------------
merged: gustavo at niemeyer.net-20050929163846-4b1c341a976143cf
committer: Gustavo Niemeyer <gustavo at niemeyer.net>
timestamp: Thu 2005-09-29 13:38:46 -0300
message:
Added file2, on repos2.
------------------------------------------------------------
revno: 1
committer: Gustavo Niemeyer <gustavo at niemeyer.net>
timestamp: Thu 2005-09-29 13:37:58 -0300
message:
Added file1, on repos1.
Enjoy!
--
Gustavo Niemeyer
http://niemeyer.net
-------------- next part --------------
=== modified file 'bzrlib/log.py'
--- bzrlib/log.py
+++ bzrlib/log.py
@@ -139,6 +139,7 @@
end_revision
If not None, only show revisions <= end_revision
"""
+ from bzrlib.revision import get_merged_revisions
from bzrlib.osutils import format_date
from bzrlib.errors import BzrCheckError
from bzrlib.textui import show_status
@@ -172,6 +173,8 @@
# list indexes are 0-based; revisions are 1-based
cut_revs = which_revs[(start_revision-1):(end_revision)]
+ merged_revs = get_merged_revisions(cut_revs[-1][1], branch)
+
if direction == 'reverse':
cut_revs.reverse()
elif direction == 'forward':
@@ -198,6 +201,10 @@
continue
lf.show(revno, rev, delta)
+
+ if rev_id in merged_revs:
+ for merged_rev_id in merged_revs[rev_id]:
+ lf.show_merge(branch.get_revision(merged_rev_id))
@@ -294,6 +301,8 @@
def show(self, revno, rev, delta):
raise NotImplementedError('not implemented in abstract base')
+ def show_merge(self, rev):
+ pass
@@ -330,6 +339,32 @@
if delta != None:
delta.show(to_file, self.show_ids)
+ def show_merge(self, rev):
+ from osutils import format_date
+
+ to_file = self.to_file
+
+ indent = ' '
+
+ print >>to_file, indent+'-' * 60
+ print >>to_file, indent+'merged:', rev.revision_id
+ if self.show_ids:
+ for parent_id in rev.parent_ids:
+ print >>to_file, indent+'parent:', parent_id
+
+ print >>to_file, indent+'committer:', rev.committer
+
+ date_str = format_date(rev.timestamp,
+ rev.timezone or 0,
+ self.show_timezone)
+ print >>to_file, indent+'timestamp: %s' % date_str
+
+ print >>to_file, indent+'message:'
+ if not rev.message:
+ print >>to_file, indent+' (no message)'
+ else:
+ for l in rev.message.split('\n'):
+ print >>to_file, indent+' ' + l
class ShortLogFormatter(LogFormatter):
=== modified file 'bzrlib/revision.py'
--- bzrlib/revision.py
+++ bzrlib/revision.py
@@ -302,3 +302,85 @@
next = best_ancestor(next)
path.reverse()
return path
+
+
+def get_merged_revisions(revision_id, branch):
+ """
+ revision_id must be in the revision history of the given branch.
+
+ Suppose the following revision graph:
+
+ F --- G
+ / \
+ A --- B --- C --- D --- E
+ \ / /
+ H --- I --- J
+ \ /
+ K ---- L
+
+ Considering that A, B, C, D, E are the only revisions present in
+ the revision history for the given branch, when queried on E
+ that function may return:
+
+ { C: [I, H], D: [G, F, J, L, K] }
+
+ "may" because the order between G, F and J, L, K is not guaranteed.
+ """
+ history = branch.revision_history()
+ del history[history.index(revision_id)+1:]
+
+ skip = dict.fromkeys(history, True)
+
+ merged = {}
+
+ for hist_revision_id in history:
+
+ revision = branch.get_revision(hist_revision_id)
+
+ queue = []
+ for parent_id in revision.parent_ids:
+ if parent_id not in skip:
+ skip[parent_id] = True
+ queue.append((hist_revision_id, parent_id))
+
+ if not queue:
+ continue
+
+ # Reversed topological sorting of merged ids.
+ succ_num = {}
+ pred_ids = {}
+ while queue:
+
+ revision_id, parent_id = queue.pop()
+
+ try:
+ parent = branch.get_revision(parent_id)
+ except bzrlib.errors.NoSuchRevision:
+ continue
+
+ if revision_id in pred_ids:
+ pred_ids[revision_id].append(parent_id)
+ else:
+ pred_ids[revision_id] = [parent_id]
+ if parent_id in succ_num:
+ succ_num[parent_id] += 1
+ else:
+ succ_num[parent_id] = 1
+
+ for parent_parent_id in parent.parent_ids:
+ if parent_parent_id not in skip:
+ skip[parent_parent_id] = True
+ queue.append((parent_id, parent_parent_id))
+
+ revision_merged_ids = merged[hist_revision_id] = [hist_revision_id]
+
+ for revision_id in revision_merged_ids:
+ for parent_id in pred_ids.get(revision_id, ()):
+ succ_num[parent_id] -= 1
+ if not succ_num[parent_id]:
+ revision_merged_ids.append(parent_id)
+
+ del revision_merged_ids[0]
+
+ return merged
+
More information about the bazaar
mailing list