Show More
@@ -612,8 +612,9 b' def annotate(ui, repo, *pats, **opts):' | |||||
612 | opmap = [['user', lambda x: ui.shortuser(x.user())], |
|
612 | opmap = [['user', lambda x: ui.shortuser(x.user())], | |
613 | ['number', lambda x: str(x.rev())], |
|
613 | ['number', lambda x: str(x.rev())], | |
614 | ['changeset', lambda x: short(x.node())], |
|
614 | ['changeset', lambda x: short(x.node())], | |
615 | ['date', getdate]] |
|
615 | ['date', getdate], ['follow', lambda x: x.path()]] | |
616 |
if not opts['user'] and not opts['changeset'] and not opts['date'] |
|
616 | if (not opts['user'] and not opts['changeset'] and not opts['date'] | |
|
617 | and not opts['follow']): | |||
617 | opts['number'] = 1 |
|
618 | opts['number'] = 1 | |
618 |
|
619 | |||
619 | ctx = repo.changectx(opts['rev']) |
|
620 | ctx = repo.changectx(opts['rev']) | |
@@ -625,7 +626,7 b' def annotate(ui, repo, *pats, **opts):' | |||||
625 | ui.write(_("%s: binary file\n") % ((pats and rel) or abs)) |
|
626 | ui.write(_("%s: binary file\n") % ((pats and rel) or abs)) | |
626 | continue |
|
627 | continue | |
627 |
|
628 | |||
628 | lines = fctx.annotate() |
|
629 | lines = fctx.annotate(follow=opts.get('follow')) | |
629 | pieces = [] |
|
630 | pieces = [] | |
630 |
|
631 | |||
631 | for o, f in opmap: |
|
632 | for o, f in opmap: | |
@@ -2671,6 +2672,7 b' table = {' | |||||
2671 | "^annotate": |
|
2672 | "^annotate": | |
2672 | (annotate, |
|
2673 | (annotate, | |
2673 | [('r', 'rev', '', _('annotate the specified revision')), |
|
2674 | [('r', 'rev', '', _('annotate the specified revision')), | |
|
2675 | ('f', 'follow', None, _('follow file copies and renames')), | |||
2674 | ('a', 'text', None, _('treat all files as text')), |
|
2676 | ('a', 'text', None, _('treat all files as text')), | |
2675 | ('u', 'user', None, _('list the author')), |
|
2677 | ('u', 'user', None, _('list the author')), | |
2676 | ('d', 'date', None, _('list the date')), |
|
2678 | ('d', 'date', None, _('list the date')), |
@@ -5,6 +5,10 b'' | |||||
5 | # This software may be used and distributed according to the terms |
|
5 | # This software may be used and distributed according to the terms | |
6 | # of the GNU General Public License, incorporated herein by reference. |
|
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 | from node import * |
|
12 | from node import * | |
9 | from demandload import demandload |
|
13 | from demandload import demandload | |
10 | demandload(globals(), "ancestor util") |
|
14 | demandload(globals(), "ancestor util") | |
@@ -165,13 +169,74 b' class filectx(object):' | |||||
165 | return [ filectx(self._repo, self._path, fileid=x, |
|
169 | return [ filectx(self._repo, self._path, fileid=x, | |
166 | filelog=self._filelog) for x in c ] |
|
170 | filelog=self._filelog) for x in c ] | |
167 |
|
171 | |||
168 | def annotate(self): |
|
172 | def annotate(self, follow=False): | |
169 | getctx = util.cachefunc(lambda x: filectx(self._repo, self._path, |
|
173 | '''returns a list of tuples of (ctx, line) for each line | |
170 | changeid=x, |
|
174 | in the file, where ctx is the filectx of the node where | |
171 | filelog=self._filelog)) |
|
175 | that line was last changed''' | |
172 | hist = self._filelog.annotate(self._filenode) |
|
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 [ |
|
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 | def ancestor(self, fc2): |
|
241 | def ancestor(self, fc2): | |
177 | """ |
|
242 | """ |
@@ -1,5 +1,7 b'' | |||||
1 | #!/bin/sh |
|
1 | #!/bin/sh | |
2 |
|
2 | |||
|
3 | export HGMERGE=true | |||
|
4 | ||||
3 | echo % init |
|
5 | echo % init | |
4 | hg init |
|
6 | hg init | |
5 |
|
7 | |||
@@ -21,3 +23,53 b' hg annotate -u a' | |||||
21 |
|
23 | |||
22 | echo % annotate -cdnu |
|
24 | echo % annotate -cdnu | |
23 | hg annotate -cdnu a |
|
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 | nobody: a |
|
11 | nobody: a | |
12 | % annotate -cdnu |
|
12 | % annotate -cdnu | |
13 | nobody 0 8435f90966e4 Thu Jan 01 00:00:01 1970 +0000: a |
|
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