##// END OF EJS Templates
Refactor annotate copy support.
Brendan Cully -
r3172:5c93dd0a default
parent child Browse files
Show More
@@ -612,8 +612,9 b' def annotate(ui, repo, *pats, **opts):'
612 612 opmap = [['user', lambda x: ui.shortuser(x.user())],
613 613 ['number', lambda x: str(x.rev())],
614 614 ['changeset', lambda x: short(x.node())],
615 ['date', getdate]]
616 if not opts['user'] and not opts['changeset'] and not opts['date']:
615 ['date', getdate], ['follow', lambda x: x.path()]]
616 if (not opts['user'] and not opts['changeset'] and not opts['date']
617 and not opts['follow']):
617 618 opts['number'] = 1
618 619
619 620 ctx = repo.changectx(opts['rev'])
@@ -625,7 +626,7 b' def annotate(ui, repo, *pats, **opts):'
625 626 ui.write(_("%s: binary file\n") % ((pats and rel) or abs))
626 627 continue
627 628
628 lines = fctx.annotate()
629 lines = fctx.annotate(follow=opts.get('follow'))
629 630 pieces = []
630 631
631 632 for o, f in opmap:
@@ -2671,6 +2672,7 b' table = {'
2671 2672 "^annotate":
2672 2673 (annotate,
2673 2674 [('r', 'rev', '', _('annotate the specified revision')),
2675 ('f', 'follow', None, _('follow file copies and renames')),
2674 2676 ('a', 'text', None, _('treat all files as text')),
2675 2677 ('u', 'user', None, _('list the author')),
2676 2678 ('d', 'date', None, _('list the date')),
@@ -5,6 +5,10 b''
5 5 # This software may be used and distributed according to the terms
6 6 # of the GNU General Public License, incorporated herein by reference.
7 7
8 from demandload import *
9 from node import *
10 demandload(globals(), 'bdiff')
11
8 12 from node import *
9 13 from demandload import demandload
10 14 demandload(globals(), "ancestor util")
@@ -165,13 +169,74 b' class filectx(object):'
165 169 return [ filectx(self._repo, self._path, fileid=x,
166 170 filelog=self._filelog) for x in c ]
167 171
168 def annotate(self):
169 getctx = util.cachefunc(lambda x: filectx(self._repo, self._path,
170 changeid=x,
171 filelog=self._filelog))
172 hist = self._filelog.annotate(self._filenode)
172 def annotate(self, follow=False):
173 '''returns a list of tuples of (ctx, line) for each line
174 in the file, where ctx is the filectx of the node where
175 that line was last changed'''
176
177 def decorate(text, rev):
178 return ([rev] * len(text.splitlines()), text)
179
180 def pair(parent, child):
181 for a1, a2, b1, b2 in bdiff.blocks(parent[1], child[1]):
182 child[0][b1:b2] = parent[0][a1:a2]
183 return child
184
185 getlog = util.cachefunc(lambda x: self._repo.file(x))
186 def getctx(path, fileid):
187 log = path == self._path and self._filelog or getlog(path)
188 return filectx(self._repo, path, fileid=fileid, filelog=log)
189 getctx = util.cachefunc(getctx)
190
191 def parents(f):
192 # we want to reuse filectx objects as much as possible
193 p = f._path
194 pl = [ (p, f._filelog.rev(n)) for n in f._filelog.parents(f._filenode) ]
195
196 if follow:
197 r = f.renamed()
198 if r:
199 pl[0] = (r[0], getlog(r[0]).rev(r[1]))
173 200
174 return [(getctx(rev), line) for rev, line in hist]
201 return [ getctx(p, n) for p, n in pl if n != -1 ]
202
203 # find all ancestors
204 needed = {self: 1}
205 visit = [self]
206 files = [self._path]
207 while visit:
208 f = visit.pop(0)
209 for p in parents(f):
210 if p not in needed:
211 needed[p] = 1
212 visit.append(p)
213 if p._path not in files:
214 files.append(p._path)
215 else:
216 # count how many times we'll use this
217 needed[p] += 1
218
219 # sort by revision (per file) which is a topological order
220 visit = []
221 files.reverse()
222 for f in files:
223 fn = [(n._filerev, n) for n in needed.keys() if n._path == f]
224 fn.sort()
225 visit.extend(fn)
226 hist = {}
227
228 for r, f in visit:
229 curr = decorate(f.data(), f)
230 for p in parents(f):
231 if p != nullid:
232 curr = pair(hist[p], curr)
233 # trim the history of unneeded revs
234 needed[p] -= 1
235 if not needed[p]:
236 del hist[p]
237 hist[f] = curr
238
239 return zip(hist[f][0], hist[f][1].splitlines(1))
175 240
176 241 def ancestor(self, fc2):
177 242 """
@@ -1,5 +1,7 b''
1 1 #!/bin/sh
2 2
3 export HGMERGE=true
4
3 5 echo % init
4 6 hg init
5 7
@@ -21,3 +23,53 b' hg annotate -u a'
21 23
22 24 echo % annotate -cdnu
23 25 hg annotate -cdnu a
26
27 cat <<EOF >>a
28 a
29 a
30 EOF
31 hg ci -ma1 -d '1 0'
32 hg cp a b
33 hg ci -mb -d '1 0'
34 cat <<EOF >> b
35 b
36 b
37 b
38 EOF
39 hg ci -mb2 -d '2 0'
40
41 echo % annotate b
42 hg annotate b
43 echo % annotate -nf b
44 hg annotate -nf b
45
46 hg up -C 2
47 cat <<EOF >> b
48 b
49 c
50 b
51 EOF
52 hg ci -mb2.1 -d '2 0'
53 hg merge
54 hg ci -mmergeb -d '3 0'
55 echo % annotate after merge
56 hg annotate -nf b
57
58 hg up -C 1
59 hg cp a b
60 cat <<EOF > b
61 a
62 z
63 a
64 EOF
65 hg ci -mc -d '3 0'
66 hg merge
67 cat <<EOF >> b
68 b
69 c
70 b
71 EOF
72 echo d >> b
73 hg ci -mmerge2 -d '4 0'
74 echo % annotate after rename merge
75 hg annotate -nf b
@@ -11,3 +11,40 b' 0: a'
11 11 nobody: a
12 12 % annotate -cdnu
13 13 nobody 0 8435f90966e4 Thu Jan 01 00:00:01 1970 +0000: a
14 % annotate b
15 2: a
16 2: a
17 2: a
18 3: b
19 3: b
20 3: b
21 % annotate -nf b
22 0 a: a
23 1 a: a
24 1 a: a
25 3 b: b
26 3 b: b
27 3 b: b
28 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
29 merging b
30 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
31 (branch merge, don't forget to commit)
32 % annotate after merge
33 0 a: a
34 1 a: a
35 1 a: a
36 3 b: b
37 4 b: c
38 3 b: b
39 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
40 merging b
41 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
42 (branch merge, don't forget to commit)
43 % annotate after rename merge
44 0 a: a
45 6 b: z
46 1 a: a
47 3 b: b
48 4 b: c
49 3 b: b
50 7 b: d
General Comments 0
You need to be logged in to leave comments. Login now