Show copies in hg log.
The format is:
copies: destination (source)...
--- a/mercurial/commands.py Fri Sep 29 13:00:54 2006 -0700
+++ b/mercurial/commands.py Fri Sep 29 13:01:19 2006 -0700
@@ -312,7 +312,7 @@
self.ui = ui
self.repo = repo
- def show(self, rev=0, changenode=None, brinfo=None):
+ def show(self, rev=0, changenode=None, brinfo=None, copies=None):
'''show a single changeset or file revision'''
log = self.repo.changelog
if changenode is None:
@@ -359,6 +359,9 @@
self.ui.note("%-12s %s\n" % (key, " ".join(value)))
else:
self.ui.note(_("files: %s\n") % " ".join(changes[3]))
+ if copies:
+ copies = ['%s (%s)' % c for c in copies]
+ self.ui.note(_("copies: %s\n") % ' '.join(copies))
description = changes[4].strip()
if description:
@@ -1774,6 +1777,40 @@
limit = sys.maxint
count = 0
+ if opts['copies'] and opts['rev']:
+ endrev = max([int(i)
+ for i in cmdutil.revrange(ui, repo, opts['rev'])]) + 1
+ else:
+ endrev = repo.changelog.count()
+ rcache = {}
+ ncache = {}
+ dcache = []
+ def getrenamed(fn, rev, man):
+ '''looks up all renames for a file (up to endrev) the first
+ time the file is given. It indexes on the changerev and only
+ parses the manifest if linkrev != changerev.
+ Returns rename info for fn at changerev rev.'''
+ if fn not in rcache:
+ rcache[fn] = {}
+ ncache[fn] = {}
+ fl = repo.file(fn)
+ for i in xrange(fl.count()):
+ node = fl.node(i)
+ lr = fl.linkrev(node)
+ renamed = fl.renamed(node)
+ rcache[fn][lr] = renamed
+ if renamed:
+ ncache[fn][node] = renamed
+ if lr >= endrev:
+ break
+ if rev in rcache[fn]:
+ return rcache[fn][rev]
+ if not dcache or dcache[0] != man:
+ dcache[:] = [man, repo.manifest.readdelta(man)]
+ if fn in dcache[1]:
+ return ncache[fn].get(dcache[1][fn])
+ return None
+
displayer = show_changeset(ui, repo, opts)
for st, rev, fns in changeiter:
if st == 'window':
@@ -1805,7 +1842,14 @@
if opts['branches']:
br = repo.branchlookup([repo.changelog.node(rev)])
- displayer.show(rev, brinfo=br)
+ copies = []
+ if opts.get('copies') and rev:
+ mf = getchange(rev)[0]
+ for fn in getchange(rev)[3]:
+ rename = getrenamed(fn, rev, mf)
+ if rename:
+ copies.append((fn, rename[0]))
+ displayer.show(rev, brinfo=br, copies=copies)
if opts['patch']:
prev = (parents and parents[0]) or nullid
patch.diff(repo, prev, changenode, match=matchfn, fp=du)
@@ -2889,6 +2933,7 @@
_('follow changeset history, or file history across copies and renames')),
('', 'follow-first', None,
_('only follow the first parent of merge changesets')),
+ ('C', 'copies', None, _('show copied files')),
('k', 'keyword', [], _('search for a keyword')),
('l', 'limit', '', _('limit number of changes displayed')),
('r', 'rev', [], _('show the specified revision or range')),
--- a/mercurial/templater.py Fri Sep 29 13:00:54 2006 -0700
+++ b/mercurial/templater.py Fri Sep 29 13:01:19 2006 -0700
@@ -330,7 +330,8 @@
def __init__(self, ui, repo, mapfile, dest=None):
self.t = templater(mapfile, common_filters,
cache={'parent': '{rev}:{node|short} ',
- 'manifest': '{rev}:{node|short}'})
+ 'manifest': '{rev}:{node|short}',
+ 'filecopy': '{name} ({source})'})
self.ui = ui
self.dest = dest
self.repo = repo
@@ -355,7 +356,7 @@
self.write(thing, header=True)
def show(self, rev=0, changenode=None, brinfo=None, changes=None,
- **props):
+ copies=None, **props):
'''show a single changeset or file revision'''
log = self.repo.changelog
if changenode is None:
@@ -472,6 +473,13 @@
showadds = ''
showdels = ''
+ copies = [{'name': x[0], 'source': x[1]}
+ for x in copies]
+ def showcopies(**args):
+ for x in showlist('file_copy', copies, plural='file_copies',
+ **args):
+ yield x
+
defprops = {
'author': changes[1],
'branches': showbranches,
@@ -480,6 +488,7 @@
'file_adds': showadds,
'file_dels': showdels,
'files': showfiles,
+ 'file_copies': showcopies,
'manifest': showmanifest,
'node': hex(changenode),
'parents': showparents,
--- a/templates/map-cmdline.default Fri Sep 29 13:00:54 2006 -0700
+++ b/templates/map-cmdline.default Fri Sep 29 13:01:19 2006 -0700
@@ -1,12 +1,15 @@
changeset = 'changeset: {rev}:{node|short}\n{tags}{short_parents}user: {author}\ndate: {date|date}\nsummary: {desc|firstline}\n\n'
changeset_quiet = '{rev}:{node|short}\n'
-changeset_verbose = 'changeset: {rev}:{node}\n{tags}{parents}{manifest}user: {author}\ndate: {date|date}\nfiles: {files}\n{file_adds}{file_dels}description:\n{desc|strip}\n\n\n'
+changeset_verbose = 'changeset: {rev}:{node}\n{tags}{parents}{manifest}user: {author}\ndate: {date|date}\nfiles: {files}\n{file_adds}{file_dels}{file_copies}description:\n{desc|strip}\n\n\n'
start_file_adds = 'files+: '
file_add = ' {file_add}'
end_file_adds = '\n'
start_file_dels = 'files-: '
file_del = ' {file_del}'
end_file_dels = '\n'
+start_file_copies = 'copies: '
+file_copy = ' {name} ({source})'
+end_file_copies = '\n'
short_parent = 'parent: {rev}:{node|short}\n'
parent = 'parent: {rev}:{node}\n'
manifest = 'manifest: {rev}:{node}\n'
--- a/templates/template-vars.txt Fri Sep 29 13:00:54 2006 -0700
+++ b/templates/template-vars.txt Fri Sep 29 13:01:19 2006 -0700
@@ -25,6 +25,7 @@
footer the global page footer
files a list of file links
+file_copies a list of pairs of name, source filenames
dirs a set of directory links
diff a diff of one or more files
annotate an annotated file
@@ -36,4 +37,4 @@
filenodelink - jump to file diff
fileellipses - printed after maxfiles
changelogentry - an entry in the log
- manifest - browse a manifest as a directory tree
\ No newline at end of file
+ manifest - browse a manifest as a directory tree
--- a/tests/test-log Fri Sep 29 13:00:54 2006 -0700
+++ b/tests/test-log Fri Sep 29 13:01:19 2006 -0700
@@ -29,6 +29,9 @@
echo % many renames
hg log -vf e
+echo % log copies
+hg log -vC --template '{rev} {file_copies%filecopy}\n'
+
# log --follow tests
hg init ../follow
cd ../follow
--- a/tests/test-log.out Fri Sep 29 13:00:54 2006 -0700
+++ b/tests/test-log.out Fri Sep 29 13:01:19 2006 -0700
@@ -76,6 +76,12 @@
a
+% log copies
+4 e (dir/b)
+3 b (a)
+2 dir/b (b)
+1 b (a)
+0
adding base
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
adding b1