##// END OF EJS Templates
context: start walking from "introrev" in blockancestors()...
Denis Laxalde -
r32063:befefdd3 stable
parent child Browse files
Show More
@@ -1,2167 +1,2170 b''
1 # context.py - changeset and file context objects for mercurial
1 # context.py - changeset and file context objects for mercurial
2 #
2 #
3 # Copyright 2006, 2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2006, 2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import errno
10 import errno
11 import os
11 import os
12 import re
12 import re
13 import stat
13 import stat
14
14
15 from .i18n import _
15 from .i18n import _
16 from .node import (
16 from .node import (
17 addednodeid,
17 addednodeid,
18 bin,
18 bin,
19 hex,
19 hex,
20 modifiednodeid,
20 modifiednodeid,
21 nullid,
21 nullid,
22 nullrev,
22 nullrev,
23 short,
23 short,
24 wdirid,
24 wdirid,
25 wdirnodes,
25 wdirnodes,
26 )
26 )
27 from . import (
27 from . import (
28 encoding,
28 encoding,
29 error,
29 error,
30 fileset,
30 fileset,
31 match as matchmod,
31 match as matchmod,
32 mdiff,
32 mdiff,
33 obsolete as obsmod,
33 obsolete as obsmod,
34 patch,
34 patch,
35 phases,
35 phases,
36 pycompat,
36 pycompat,
37 repoview,
37 repoview,
38 revlog,
38 revlog,
39 scmutil,
39 scmutil,
40 subrepo,
40 subrepo,
41 util,
41 util,
42 )
42 )
43
43
44 propertycache = util.propertycache
44 propertycache = util.propertycache
45
45
46 nonascii = re.compile(r'[^\x21-\x7f]').search
46 nonascii = re.compile(r'[^\x21-\x7f]').search
47
47
48 class basectx(object):
48 class basectx(object):
49 """A basectx object represents the common logic for its children:
49 """A basectx object represents the common logic for its children:
50 changectx: read-only context that is already present in the repo,
50 changectx: read-only context that is already present in the repo,
51 workingctx: a context that represents the working directory and can
51 workingctx: a context that represents the working directory and can
52 be committed,
52 be committed,
53 memctx: a context that represents changes in-memory and can also
53 memctx: a context that represents changes in-memory and can also
54 be committed."""
54 be committed."""
55 def __new__(cls, repo, changeid='', *args, **kwargs):
55 def __new__(cls, repo, changeid='', *args, **kwargs):
56 if isinstance(changeid, basectx):
56 if isinstance(changeid, basectx):
57 return changeid
57 return changeid
58
58
59 o = super(basectx, cls).__new__(cls)
59 o = super(basectx, cls).__new__(cls)
60
60
61 o._repo = repo
61 o._repo = repo
62 o._rev = nullrev
62 o._rev = nullrev
63 o._node = nullid
63 o._node = nullid
64
64
65 return o
65 return o
66
66
67 def __str__(self):
67 def __str__(self):
68 r = short(self.node())
68 r = short(self.node())
69 if pycompat.ispy3:
69 if pycompat.ispy3:
70 return r.decode('ascii')
70 return r.decode('ascii')
71 return r
71 return r
72
72
73 def __bytes__(self):
73 def __bytes__(self):
74 return short(self.node())
74 return short(self.node())
75
75
76 def __int__(self):
76 def __int__(self):
77 return self.rev()
77 return self.rev()
78
78
79 def __repr__(self):
79 def __repr__(self):
80 return "<%s %s>" % (type(self).__name__, str(self))
80 return "<%s %s>" % (type(self).__name__, str(self))
81
81
82 def __eq__(self, other):
82 def __eq__(self, other):
83 try:
83 try:
84 return type(self) == type(other) and self._rev == other._rev
84 return type(self) == type(other) and self._rev == other._rev
85 except AttributeError:
85 except AttributeError:
86 return False
86 return False
87
87
88 def __ne__(self, other):
88 def __ne__(self, other):
89 return not (self == other)
89 return not (self == other)
90
90
91 def __contains__(self, key):
91 def __contains__(self, key):
92 return key in self._manifest
92 return key in self._manifest
93
93
94 def __getitem__(self, key):
94 def __getitem__(self, key):
95 return self.filectx(key)
95 return self.filectx(key)
96
96
97 def __iter__(self):
97 def __iter__(self):
98 return iter(self._manifest)
98 return iter(self._manifest)
99
99
100 def _buildstatusmanifest(self, status):
100 def _buildstatusmanifest(self, status):
101 """Builds a manifest that includes the given status results, if this is
101 """Builds a manifest that includes the given status results, if this is
102 a working copy context. For non-working copy contexts, it just returns
102 a working copy context. For non-working copy contexts, it just returns
103 the normal manifest."""
103 the normal manifest."""
104 return self.manifest()
104 return self.manifest()
105
105
106 def _matchstatus(self, other, match):
106 def _matchstatus(self, other, match):
107 """return match.always if match is none
107 """return match.always if match is none
108
108
109 This internal method provides a way for child objects to override the
109 This internal method provides a way for child objects to override the
110 match operator.
110 match operator.
111 """
111 """
112 return match or matchmod.always(self._repo.root, self._repo.getcwd())
112 return match or matchmod.always(self._repo.root, self._repo.getcwd())
113
113
114 def _buildstatus(self, other, s, match, listignored, listclean,
114 def _buildstatus(self, other, s, match, listignored, listclean,
115 listunknown):
115 listunknown):
116 """build a status with respect to another context"""
116 """build a status with respect to another context"""
117 # Load earliest manifest first for caching reasons. More specifically,
117 # Load earliest manifest first for caching reasons. More specifically,
118 # if you have revisions 1000 and 1001, 1001 is probably stored as a
118 # if you have revisions 1000 and 1001, 1001 is probably stored as a
119 # delta against 1000. Thus, if you read 1000 first, we'll reconstruct
119 # delta against 1000. Thus, if you read 1000 first, we'll reconstruct
120 # 1000 and cache it so that when you read 1001, we just need to apply a
120 # 1000 and cache it so that when you read 1001, we just need to apply a
121 # delta to what's in the cache. So that's one full reconstruction + one
121 # delta to what's in the cache. So that's one full reconstruction + one
122 # delta application.
122 # delta application.
123 mf2 = None
123 mf2 = None
124 if self.rev() is not None and self.rev() < other.rev():
124 if self.rev() is not None and self.rev() < other.rev():
125 mf2 = self._buildstatusmanifest(s)
125 mf2 = self._buildstatusmanifest(s)
126 mf1 = other._buildstatusmanifest(s)
126 mf1 = other._buildstatusmanifest(s)
127 if mf2 is None:
127 if mf2 is None:
128 mf2 = self._buildstatusmanifest(s)
128 mf2 = self._buildstatusmanifest(s)
129
129
130 modified, added = [], []
130 modified, added = [], []
131 removed = []
131 removed = []
132 clean = []
132 clean = []
133 deleted, unknown, ignored = s.deleted, s.unknown, s.ignored
133 deleted, unknown, ignored = s.deleted, s.unknown, s.ignored
134 deletedset = set(deleted)
134 deletedset = set(deleted)
135 d = mf1.diff(mf2, match=match, clean=listclean)
135 d = mf1.diff(mf2, match=match, clean=listclean)
136 for fn, value in d.iteritems():
136 for fn, value in d.iteritems():
137 if fn in deletedset:
137 if fn in deletedset:
138 continue
138 continue
139 if value is None:
139 if value is None:
140 clean.append(fn)
140 clean.append(fn)
141 continue
141 continue
142 (node1, flag1), (node2, flag2) = value
142 (node1, flag1), (node2, flag2) = value
143 if node1 is None:
143 if node1 is None:
144 added.append(fn)
144 added.append(fn)
145 elif node2 is None:
145 elif node2 is None:
146 removed.append(fn)
146 removed.append(fn)
147 elif flag1 != flag2:
147 elif flag1 != flag2:
148 modified.append(fn)
148 modified.append(fn)
149 elif node2 not in wdirnodes:
149 elif node2 not in wdirnodes:
150 # When comparing files between two commits, we save time by
150 # When comparing files between two commits, we save time by
151 # not comparing the file contents when the nodeids differ.
151 # not comparing the file contents when the nodeids differ.
152 # Note that this means we incorrectly report a reverted change
152 # Note that this means we incorrectly report a reverted change
153 # to a file as a modification.
153 # to a file as a modification.
154 modified.append(fn)
154 modified.append(fn)
155 elif self[fn].cmp(other[fn]):
155 elif self[fn].cmp(other[fn]):
156 modified.append(fn)
156 modified.append(fn)
157 else:
157 else:
158 clean.append(fn)
158 clean.append(fn)
159
159
160 if removed:
160 if removed:
161 # need to filter files if they are already reported as removed
161 # need to filter files if they are already reported as removed
162 unknown = [fn for fn in unknown if fn not in mf1 and
162 unknown = [fn for fn in unknown if fn not in mf1 and
163 (not match or match(fn))]
163 (not match or match(fn))]
164 ignored = [fn for fn in ignored if fn not in mf1 and
164 ignored = [fn for fn in ignored if fn not in mf1 and
165 (not match or match(fn))]
165 (not match or match(fn))]
166 # if they're deleted, don't report them as removed
166 # if they're deleted, don't report them as removed
167 removed = [fn for fn in removed if fn not in deletedset]
167 removed = [fn for fn in removed if fn not in deletedset]
168
168
169 return scmutil.status(modified, added, removed, deleted, unknown,
169 return scmutil.status(modified, added, removed, deleted, unknown,
170 ignored, clean)
170 ignored, clean)
171
171
172 @propertycache
172 @propertycache
173 def substate(self):
173 def substate(self):
174 return subrepo.state(self, self._repo.ui)
174 return subrepo.state(self, self._repo.ui)
175
175
176 def subrev(self, subpath):
176 def subrev(self, subpath):
177 return self.substate[subpath][1]
177 return self.substate[subpath][1]
178
178
179 def rev(self):
179 def rev(self):
180 return self._rev
180 return self._rev
181 def node(self):
181 def node(self):
182 return self._node
182 return self._node
183 def hex(self):
183 def hex(self):
184 return hex(self.node())
184 return hex(self.node())
185 def manifest(self):
185 def manifest(self):
186 return self._manifest
186 return self._manifest
187 def manifestctx(self):
187 def manifestctx(self):
188 return self._manifestctx
188 return self._manifestctx
189 def repo(self):
189 def repo(self):
190 return self._repo
190 return self._repo
191 def phasestr(self):
191 def phasestr(self):
192 return phases.phasenames[self.phase()]
192 return phases.phasenames[self.phase()]
193 def mutable(self):
193 def mutable(self):
194 return self.phase() > phases.public
194 return self.phase() > phases.public
195
195
196 def getfileset(self, expr):
196 def getfileset(self, expr):
197 return fileset.getfileset(self, expr)
197 return fileset.getfileset(self, expr)
198
198
199 def obsolete(self):
199 def obsolete(self):
200 """True if the changeset is obsolete"""
200 """True if the changeset is obsolete"""
201 return self.rev() in obsmod.getrevs(self._repo, 'obsolete')
201 return self.rev() in obsmod.getrevs(self._repo, 'obsolete')
202
202
203 def extinct(self):
203 def extinct(self):
204 """True if the changeset is extinct"""
204 """True if the changeset is extinct"""
205 return self.rev() in obsmod.getrevs(self._repo, 'extinct')
205 return self.rev() in obsmod.getrevs(self._repo, 'extinct')
206
206
207 def unstable(self):
207 def unstable(self):
208 """True if the changeset is not obsolete but it's ancestor are"""
208 """True if the changeset is not obsolete but it's ancestor are"""
209 return self.rev() in obsmod.getrevs(self._repo, 'unstable')
209 return self.rev() in obsmod.getrevs(self._repo, 'unstable')
210
210
211 def bumped(self):
211 def bumped(self):
212 """True if the changeset try to be a successor of a public changeset
212 """True if the changeset try to be a successor of a public changeset
213
213
214 Only non-public and non-obsolete changesets may be bumped.
214 Only non-public and non-obsolete changesets may be bumped.
215 """
215 """
216 return self.rev() in obsmod.getrevs(self._repo, 'bumped')
216 return self.rev() in obsmod.getrevs(self._repo, 'bumped')
217
217
218 def divergent(self):
218 def divergent(self):
219 """Is a successors of a changeset with multiple possible successors set
219 """Is a successors of a changeset with multiple possible successors set
220
220
221 Only non-public and non-obsolete changesets may be divergent.
221 Only non-public and non-obsolete changesets may be divergent.
222 """
222 """
223 return self.rev() in obsmod.getrevs(self._repo, 'divergent')
223 return self.rev() in obsmod.getrevs(self._repo, 'divergent')
224
224
225 def troubled(self):
225 def troubled(self):
226 """True if the changeset is either unstable, bumped or divergent"""
226 """True if the changeset is either unstable, bumped or divergent"""
227 return self.unstable() or self.bumped() or self.divergent()
227 return self.unstable() or self.bumped() or self.divergent()
228
228
229 def troubles(self):
229 def troubles(self):
230 """return the list of troubles affecting this changesets.
230 """return the list of troubles affecting this changesets.
231
231
232 Troubles are returned as strings. possible values are:
232 Troubles are returned as strings. possible values are:
233 - unstable,
233 - unstable,
234 - bumped,
234 - bumped,
235 - divergent.
235 - divergent.
236 """
236 """
237 troubles = []
237 troubles = []
238 if self.unstable():
238 if self.unstable():
239 troubles.append('unstable')
239 troubles.append('unstable')
240 if self.bumped():
240 if self.bumped():
241 troubles.append('bumped')
241 troubles.append('bumped')
242 if self.divergent():
242 if self.divergent():
243 troubles.append('divergent')
243 troubles.append('divergent')
244 return troubles
244 return troubles
245
245
246 def parents(self):
246 def parents(self):
247 """return contexts for each parent changeset"""
247 """return contexts for each parent changeset"""
248 return self._parents
248 return self._parents
249
249
250 def p1(self):
250 def p1(self):
251 return self._parents[0]
251 return self._parents[0]
252
252
253 def p2(self):
253 def p2(self):
254 parents = self._parents
254 parents = self._parents
255 if len(parents) == 2:
255 if len(parents) == 2:
256 return parents[1]
256 return parents[1]
257 return changectx(self._repo, nullrev)
257 return changectx(self._repo, nullrev)
258
258
259 def _fileinfo(self, path):
259 def _fileinfo(self, path):
260 if '_manifest' in self.__dict__:
260 if '_manifest' in self.__dict__:
261 try:
261 try:
262 return self._manifest[path], self._manifest.flags(path)
262 return self._manifest[path], self._manifest.flags(path)
263 except KeyError:
263 except KeyError:
264 raise error.ManifestLookupError(self._node, path,
264 raise error.ManifestLookupError(self._node, path,
265 _('not found in manifest'))
265 _('not found in manifest'))
266 if '_manifestdelta' in self.__dict__ or path in self.files():
266 if '_manifestdelta' in self.__dict__ or path in self.files():
267 if path in self._manifestdelta:
267 if path in self._manifestdelta:
268 return (self._manifestdelta[path],
268 return (self._manifestdelta[path],
269 self._manifestdelta.flags(path))
269 self._manifestdelta.flags(path))
270 mfl = self._repo.manifestlog
270 mfl = self._repo.manifestlog
271 try:
271 try:
272 node, flag = mfl[self._changeset.manifest].find(path)
272 node, flag = mfl[self._changeset.manifest].find(path)
273 except KeyError:
273 except KeyError:
274 raise error.ManifestLookupError(self._node, path,
274 raise error.ManifestLookupError(self._node, path,
275 _('not found in manifest'))
275 _('not found in manifest'))
276
276
277 return node, flag
277 return node, flag
278
278
279 def filenode(self, path):
279 def filenode(self, path):
280 return self._fileinfo(path)[0]
280 return self._fileinfo(path)[0]
281
281
282 def flags(self, path):
282 def flags(self, path):
283 try:
283 try:
284 return self._fileinfo(path)[1]
284 return self._fileinfo(path)[1]
285 except error.LookupError:
285 except error.LookupError:
286 return ''
286 return ''
287
287
288 def sub(self, path, allowcreate=True):
288 def sub(self, path, allowcreate=True):
289 '''return a subrepo for the stored revision of path, never wdir()'''
289 '''return a subrepo for the stored revision of path, never wdir()'''
290 return subrepo.subrepo(self, path, allowcreate=allowcreate)
290 return subrepo.subrepo(self, path, allowcreate=allowcreate)
291
291
292 def nullsub(self, path, pctx):
292 def nullsub(self, path, pctx):
293 return subrepo.nullsubrepo(self, path, pctx)
293 return subrepo.nullsubrepo(self, path, pctx)
294
294
295 def workingsub(self, path):
295 def workingsub(self, path):
296 '''return a subrepo for the stored revision, or wdir if this is a wdir
296 '''return a subrepo for the stored revision, or wdir if this is a wdir
297 context.
297 context.
298 '''
298 '''
299 return subrepo.subrepo(self, path, allowwdir=True)
299 return subrepo.subrepo(self, path, allowwdir=True)
300
300
301 def match(self, pats=None, include=None, exclude=None, default='glob',
301 def match(self, pats=None, include=None, exclude=None, default='glob',
302 listsubrepos=False, badfn=None):
302 listsubrepos=False, badfn=None):
303 if pats is None:
303 if pats is None:
304 pats = []
304 pats = []
305 r = self._repo
305 r = self._repo
306 return matchmod.match(r.root, r.getcwd(), pats,
306 return matchmod.match(r.root, r.getcwd(), pats,
307 include, exclude, default,
307 include, exclude, default,
308 auditor=r.nofsauditor, ctx=self,
308 auditor=r.nofsauditor, ctx=self,
309 listsubrepos=listsubrepos, badfn=badfn)
309 listsubrepos=listsubrepos, badfn=badfn)
310
310
311 def diff(self, ctx2=None, match=None, **opts):
311 def diff(self, ctx2=None, match=None, **opts):
312 """Returns a diff generator for the given contexts and matcher"""
312 """Returns a diff generator for the given contexts and matcher"""
313 if ctx2 is None:
313 if ctx2 is None:
314 ctx2 = self.p1()
314 ctx2 = self.p1()
315 if ctx2 is not None:
315 if ctx2 is not None:
316 ctx2 = self._repo[ctx2]
316 ctx2 = self._repo[ctx2]
317 diffopts = patch.diffopts(self._repo.ui, opts)
317 diffopts = patch.diffopts(self._repo.ui, opts)
318 return patch.diff(self._repo, ctx2, self, match=match, opts=diffopts)
318 return patch.diff(self._repo, ctx2, self, match=match, opts=diffopts)
319
319
320 def dirs(self):
320 def dirs(self):
321 return self._manifest.dirs()
321 return self._manifest.dirs()
322
322
323 def hasdir(self, dir):
323 def hasdir(self, dir):
324 return self._manifest.hasdir(dir)
324 return self._manifest.hasdir(dir)
325
325
326 def dirty(self, missing=False, merge=True, branch=True):
326 def dirty(self, missing=False, merge=True, branch=True):
327 return False
327 return False
328
328
329 def status(self, other=None, match=None, listignored=False,
329 def status(self, other=None, match=None, listignored=False,
330 listclean=False, listunknown=False, listsubrepos=False):
330 listclean=False, listunknown=False, listsubrepos=False):
331 """return status of files between two nodes or node and working
331 """return status of files between two nodes or node and working
332 directory.
332 directory.
333
333
334 If other is None, compare this node with working directory.
334 If other is None, compare this node with working directory.
335
335
336 returns (modified, added, removed, deleted, unknown, ignored, clean)
336 returns (modified, added, removed, deleted, unknown, ignored, clean)
337 """
337 """
338
338
339 ctx1 = self
339 ctx1 = self
340 ctx2 = self._repo[other]
340 ctx2 = self._repo[other]
341
341
342 # This next code block is, admittedly, fragile logic that tests for
342 # This next code block is, admittedly, fragile logic that tests for
343 # reversing the contexts and wouldn't need to exist if it weren't for
343 # reversing the contexts and wouldn't need to exist if it weren't for
344 # the fast (and common) code path of comparing the working directory
344 # the fast (and common) code path of comparing the working directory
345 # with its first parent.
345 # with its first parent.
346 #
346 #
347 # What we're aiming for here is the ability to call:
347 # What we're aiming for here is the ability to call:
348 #
348 #
349 # workingctx.status(parentctx)
349 # workingctx.status(parentctx)
350 #
350 #
351 # If we always built the manifest for each context and compared those,
351 # If we always built the manifest for each context and compared those,
352 # then we'd be done. But the special case of the above call means we
352 # then we'd be done. But the special case of the above call means we
353 # just copy the manifest of the parent.
353 # just copy the manifest of the parent.
354 reversed = False
354 reversed = False
355 if (not isinstance(ctx1, changectx)
355 if (not isinstance(ctx1, changectx)
356 and isinstance(ctx2, changectx)):
356 and isinstance(ctx2, changectx)):
357 reversed = True
357 reversed = True
358 ctx1, ctx2 = ctx2, ctx1
358 ctx1, ctx2 = ctx2, ctx1
359
359
360 match = ctx2._matchstatus(ctx1, match)
360 match = ctx2._matchstatus(ctx1, match)
361 r = scmutil.status([], [], [], [], [], [], [])
361 r = scmutil.status([], [], [], [], [], [], [])
362 r = ctx2._buildstatus(ctx1, r, match, listignored, listclean,
362 r = ctx2._buildstatus(ctx1, r, match, listignored, listclean,
363 listunknown)
363 listunknown)
364
364
365 if reversed:
365 if reversed:
366 # Reverse added and removed. Clear deleted, unknown and ignored as
366 # Reverse added and removed. Clear deleted, unknown and ignored as
367 # these make no sense to reverse.
367 # these make no sense to reverse.
368 r = scmutil.status(r.modified, r.removed, r.added, [], [], [],
368 r = scmutil.status(r.modified, r.removed, r.added, [], [], [],
369 r.clean)
369 r.clean)
370
370
371 if listsubrepos:
371 if listsubrepos:
372 for subpath, sub in scmutil.itersubrepos(ctx1, ctx2):
372 for subpath, sub in scmutil.itersubrepos(ctx1, ctx2):
373 try:
373 try:
374 rev2 = ctx2.subrev(subpath)
374 rev2 = ctx2.subrev(subpath)
375 except KeyError:
375 except KeyError:
376 # A subrepo that existed in node1 was deleted between
376 # A subrepo that existed in node1 was deleted between
377 # node1 and node2 (inclusive). Thus, ctx2's substate
377 # node1 and node2 (inclusive). Thus, ctx2's substate
378 # won't contain that subpath. The best we can do ignore it.
378 # won't contain that subpath. The best we can do ignore it.
379 rev2 = None
379 rev2 = None
380 submatch = matchmod.subdirmatcher(subpath, match)
380 submatch = matchmod.subdirmatcher(subpath, match)
381 s = sub.status(rev2, match=submatch, ignored=listignored,
381 s = sub.status(rev2, match=submatch, ignored=listignored,
382 clean=listclean, unknown=listunknown,
382 clean=listclean, unknown=listunknown,
383 listsubrepos=True)
383 listsubrepos=True)
384 for rfiles, sfiles in zip(r, s):
384 for rfiles, sfiles in zip(r, s):
385 rfiles.extend("%s/%s" % (subpath, f) for f in sfiles)
385 rfiles.extend("%s/%s" % (subpath, f) for f in sfiles)
386
386
387 for l in r:
387 for l in r:
388 l.sort()
388 l.sort()
389
389
390 return r
390 return r
391
391
392
392
393 def makememctx(repo, parents, text, user, date, branch, files, store,
393 def makememctx(repo, parents, text, user, date, branch, files, store,
394 editor=None, extra=None):
394 editor=None, extra=None):
395 def getfilectx(repo, memctx, path):
395 def getfilectx(repo, memctx, path):
396 data, mode, copied = store.getfile(path)
396 data, mode, copied = store.getfile(path)
397 if data is None:
397 if data is None:
398 return None
398 return None
399 islink, isexec = mode
399 islink, isexec = mode
400 return memfilectx(repo, path, data, islink=islink, isexec=isexec,
400 return memfilectx(repo, path, data, islink=islink, isexec=isexec,
401 copied=copied, memctx=memctx)
401 copied=copied, memctx=memctx)
402 if extra is None:
402 if extra is None:
403 extra = {}
403 extra = {}
404 if branch:
404 if branch:
405 extra['branch'] = encoding.fromlocal(branch)
405 extra['branch'] = encoding.fromlocal(branch)
406 ctx = memctx(repo, parents, text, files, getfilectx, user,
406 ctx = memctx(repo, parents, text, files, getfilectx, user,
407 date, extra, editor)
407 date, extra, editor)
408 return ctx
408 return ctx
409
409
410 def _filterederror(repo, changeid):
410 def _filterederror(repo, changeid):
411 """build an exception to be raised about a filtered changeid
411 """build an exception to be raised about a filtered changeid
412
412
413 This is extracted in a function to help extensions (eg: evolve) to
413 This is extracted in a function to help extensions (eg: evolve) to
414 experiment with various message variants."""
414 experiment with various message variants."""
415 if repo.filtername.startswith('visible'):
415 if repo.filtername.startswith('visible'):
416 msg = _("hidden revision '%s'") % changeid
416 msg = _("hidden revision '%s'") % changeid
417 hint = _('use --hidden to access hidden revisions')
417 hint = _('use --hidden to access hidden revisions')
418 return error.FilteredRepoLookupError(msg, hint=hint)
418 return error.FilteredRepoLookupError(msg, hint=hint)
419 msg = _("filtered revision '%s' (not in '%s' subset)")
419 msg = _("filtered revision '%s' (not in '%s' subset)")
420 msg %= (changeid, repo.filtername)
420 msg %= (changeid, repo.filtername)
421 return error.FilteredRepoLookupError(msg)
421 return error.FilteredRepoLookupError(msg)
422
422
423 class changectx(basectx):
423 class changectx(basectx):
424 """A changecontext object makes access to data related to a particular
424 """A changecontext object makes access to data related to a particular
425 changeset convenient. It represents a read-only context already present in
425 changeset convenient. It represents a read-only context already present in
426 the repo."""
426 the repo."""
427 def __init__(self, repo, changeid=''):
427 def __init__(self, repo, changeid=''):
428 """changeid is a revision number, node, or tag"""
428 """changeid is a revision number, node, or tag"""
429
429
430 # since basectx.__new__ already took care of copying the object, we
430 # since basectx.__new__ already took care of copying the object, we
431 # don't need to do anything in __init__, so we just exit here
431 # don't need to do anything in __init__, so we just exit here
432 if isinstance(changeid, basectx):
432 if isinstance(changeid, basectx):
433 return
433 return
434
434
435 if changeid == '':
435 if changeid == '':
436 changeid = '.'
436 changeid = '.'
437 self._repo = repo
437 self._repo = repo
438
438
439 try:
439 try:
440 if isinstance(changeid, int):
440 if isinstance(changeid, int):
441 self._node = repo.changelog.node(changeid)
441 self._node = repo.changelog.node(changeid)
442 self._rev = changeid
442 self._rev = changeid
443 return
443 return
444 if not pycompat.ispy3 and isinstance(changeid, long):
444 if not pycompat.ispy3 and isinstance(changeid, long):
445 changeid = str(changeid)
445 changeid = str(changeid)
446 if changeid == 'null':
446 if changeid == 'null':
447 self._node = nullid
447 self._node = nullid
448 self._rev = nullrev
448 self._rev = nullrev
449 return
449 return
450 if changeid == 'tip':
450 if changeid == 'tip':
451 self._node = repo.changelog.tip()
451 self._node = repo.changelog.tip()
452 self._rev = repo.changelog.rev(self._node)
452 self._rev = repo.changelog.rev(self._node)
453 return
453 return
454 if changeid == '.' or changeid == repo.dirstate.p1():
454 if changeid == '.' or changeid == repo.dirstate.p1():
455 # this is a hack to delay/avoid loading obsmarkers
455 # this is a hack to delay/avoid loading obsmarkers
456 # when we know that '.' won't be hidden
456 # when we know that '.' won't be hidden
457 self._node = repo.dirstate.p1()
457 self._node = repo.dirstate.p1()
458 self._rev = repo.unfiltered().changelog.rev(self._node)
458 self._rev = repo.unfiltered().changelog.rev(self._node)
459 return
459 return
460 if len(changeid) == 20:
460 if len(changeid) == 20:
461 try:
461 try:
462 self._node = changeid
462 self._node = changeid
463 self._rev = repo.changelog.rev(changeid)
463 self._rev = repo.changelog.rev(changeid)
464 return
464 return
465 except error.FilteredRepoLookupError:
465 except error.FilteredRepoLookupError:
466 raise
466 raise
467 except LookupError:
467 except LookupError:
468 pass
468 pass
469
469
470 try:
470 try:
471 r = int(changeid)
471 r = int(changeid)
472 if '%d' % r != changeid:
472 if '%d' % r != changeid:
473 raise ValueError
473 raise ValueError
474 l = len(repo.changelog)
474 l = len(repo.changelog)
475 if r < 0:
475 if r < 0:
476 r += l
476 r += l
477 if r < 0 or r >= l:
477 if r < 0 or r >= l:
478 raise ValueError
478 raise ValueError
479 self._rev = r
479 self._rev = r
480 self._node = repo.changelog.node(r)
480 self._node = repo.changelog.node(r)
481 return
481 return
482 except error.FilteredIndexError:
482 except error.FilteredIndexError:
483 raise
483 raise
484 except (ValueError, OverflowError, IndexError):
484 except (ValueError, OverflowError, IndexError):
485 pass
485 pass
486
486
487 if len(changeid) == 40:
487 if len(changeid) == 40:
488 try:
488 try:
489 self._node = bin(changeid)
489 self._node = bin(changeid)
490 self._rev = repo.changelog.rev(self._node)
490 self._rev = repo.changelog.rev(self._node)
491 return
491 return
492 except error.FilteredLookupError:
492 except error.FilteredLookupError:
493 raise
493 raise
494 except (TypeError, LookupError):
494 except (TypeError, LookupError):
495 pass
495 pass
496
496
497 # lookup bookmarks through the name interface
497 # lookup bookmarks through the name interface
498 try:
498 try:
499 self._node = repo.names.singlenode(repo, changeid)
499 self._node = repo.names.singlenode(repo, changeid)
500 self._rev = repo.changelog.rev(self._node)
500 self._rev = repo.changelog.rev(self._node)
501 return
501 return
502 except KeyError:
502 except KeyError:
503 pass
503 pass
504 except error.FilteredRepoLookupError:
504 except error.FilteredRepoLookupError:
505 raise
505 raise
506 except error.RepoLookupError:
506 except error.RepoLookupError:
507 pass
507 pass
508
508
509 self._node = repo.unfiltered().changelog._partialmatch(changeid)
509 self._node = repo.unfiltered().changelog._partialmatch(changeid)
510 if self._node is not None:
510 if self._node is not None:
511 self._rev = repo.changelog.rev(self._node)
511 self._rev = repo.changelog.rev(self._node)
512 return
512 return
513
513
514 # lookup failed
514 # lookup failed
515 # check if it might have come from damaged dirstate
515 # check if it might have come from damaged dirstate
516 #
516 #
517 # XXX we could avoid the unfiltered if we had a recognizable
517 # XXX we could avoid the unfiltered if we had a recognizable
518 # exception for filtered changeset access
518 # exception for filtered changeset access
519 if changeid in repo.unfiltered().dirstate.parents():
519 if changeid in repo.unfiltered().dirstate.parents():
520 msg = _("working directory has unknown parent '%s'!")
520 msg = _("working directory has unknown parent '%s'!")
521 raise error.Abort(msg % short(changeid))
521 raise error.Abort(msg % short(changeid))
522 try:
522 try:
523 if len(changeid) == 20 and nonascii(changeid):
523 if len(changeid) == 20 and nonascii(changeid):
524 changeid = hex(changeid)
524 changeid = hex(changeid)
525 except TypeError:
525 except TypeError:
526 pass
526 pass
527 except (error.FilteredIndexError, error.FilteredLookupError,
527 except (error.FilteredIndexError, error.FilteredLookupError,
528 error.FilteredRepoLookupError):
528 error.FilteredRepoLookupError):
529 raise _filterederror(repo, changeid)
529 raise _filterederror(repo, changeid)
530 except IndexError:
530 except IndexError:
531 pass
531 pass
532 raise error.RepoLookupError(
532 raise error.RepoLookupError(
533 _("unknown revision '%s'") % changeid)
533 _("unknown revision '%s'") % changeid)
534
534
535 def __hash__(self):
535 def __hash__(self):
536 try:
536 try:
537 return hash(self._rev)
537 return hash(self._rev)
538 except AttributeError:
538 except AttributeError:
539 return id(self)
539 return id(self)
540
540
541 def __nonzero__(self):
541 def __nonzero__(self):
542 return self._rev != nullrev
542 return self._rev != nullrev
543
543
544 __bool__ = __nonzero__
544 __bool__ = __nonzero__
545
545
546 @propertycache
546 @propertycache
547 def _changeset(self):
547 def _changeset(self):
548 return self._repo.changelog.changelogrevision(self.rev())
548 return self._repo.changelog.changelogrevision(self.rev())
549
549
550 @propertycache
550 @propertycache
551 def _manifest(self):
551 def _manifest(self):
552 return self._manifestctx.read()
552 return self._manifestctx.read()
553
553
554 @propertycache
554 @propertycache
555 def _manifestctx(self):
555 def _manifestctx(self):
556 return self._repo.manifestlog[self._changeset.manifest]
556 return self._repo.manifestlog[self._changeset.manifest]
557
557
558 @propertycache
558 @propertycache
559 def _manifestdelta(self):
559 def _manifestdelta(self):
560 return self._manifestctx.readdelta()
560 return self._manifestctx.readdelta()
561
561
562 @propertycache
562 @propertycache
563 def _parents(self):
563 def _parents(self):
564 repo = self._repo
564 repo = self._repo
565 p1, p2 = repo.changelog.parentrevs(self._rev)
565 p1, p2 = repo.changelog.parentrevs(self._rev)
566 if p2 == nullrev:
566 if p2 == nullrev:
567 return [changectx(repo, p1)]
567 return [changectx(repo, p1)]
568 return [changectx(repo, p1), changectx(repo, p2)]
568 return [changectx(repo, p1), changectx(repo, p2)]
569
569
570 def changeset(self):
570 def changeset(self):
571 c = self._changeset
571 c = self._changeset
572 return (
572 return (
573 c.manifest,
573 c.manifest,
574 c.user,
574 c.user,
575 c.date,
575 c.date,
576 c.files,
576 c.files,
577 c.description,
577 c.description,
578 c.extra,
578 c.extra,
579 )
579 )
580 def manifestnode(self):
580 def manifestnode(self):
581 return self._changeset.manifest
581 return self._changeset.manifest
582
582
583 def user(self):
583 def user(self):
584 return self._changeset.user
584 return self._changeset.user
585 def date(self):
585 def date(self):
586 return self._changeset.date
586 return self._changeset.date
587 def files(self):
587 def files(self):
588 return self._changeset.files
588 return self._changeset.files
589 def description(self):
589 def description(self):
590 return self._changeset.description
590 return self._changeset.description
591 def branch(self):
591 def branch(self):
592 return encoding.tolocal(self._changeset.extra.get("branch"))
592 return encoding.tolocal(self._changeset.extra.get("branch"))
593 def closesbranch(self):
593 def closesbranch(self):
594 return 'close' in self._changeset.extra
594 return 'close' in self._changeset.extra
595 def extra(self):
595 def extra(self):
596 return self._changeset.extra
596 return self._changeset.extra
597 def tags(self):
597 def tags(self):
598 return self._repo.nodetags(self._node)
598 return self._repo.nodetags(self._node)
599 def bookmarks(self):
599 def bookmarks(self):
600 return self._repo.nodebookmarks(self._node)
600 return self._repo.nodebookmarks(self._node)
601 def phase(self):
601 def phase(self):
602 return self._repo._phasecache.phase(self._repo, self._rev)
602 return self._repo._phasecache.phase(self._repo, self._rev)
603 def hidden(self):
603 def hidden(self):
604 return self._rev in repoview.filterrevs(self._repo, 'visible')
604 return self._rev in repoview.filterrevs(self._repo, 'visible')
605
605
606 def children(self):
606 def children(self):
607 """return contexts for each child changeset"""
607 """return contexts for each child changeset"""
608 c = self._repo.changelog.children(self._node)
608 c = self._repo.changelog.children(self._node)
609 return [changectx(self._repo, x) for x in c]
609 return [changectx(self._repo, x) for x in c]
610
610
611 def ancestors(self):
611 def ancestors(self):
612 for a in self._repo.changelog.ancestors([self._rev]):
612 for a in self._repo.changelog.ancestors([self._rev]):
613 yield changectx(self._repo, a)
613 yield changectx(self._repo, a)
614
614
615 def descendants(self):
615 def descendants(self):
616 for d in self._repo.changelog.descendants([self._rev]):
616 for d in self._repo.changelog.descendants([self._rev]):
617 yield changectx(self._repo, d)
617 yield changectx(self._repo, d)
618
618
619 def filectx(self, path, fileid=None, filelog=None):
619 def filectx(self, path, fileid=None, filelog=None):
620 """get a file context from this changeset"""
620 """get a file context from this changeset"""
621 if fileid is None:
621 if fileid is None:
622 fileid = self.filenode(path)
622 fileid = self.filenode(path)
623 return filectx(self._repo, path, fileid=fileid,
623 return filectx(self._repo, path, fileid=fileid,
624 changectx=self, filelog=filelog)
624 changectx=self, filelog=filelog)
625
625
626 def ancestor(self, c2, warn=False):
626 def ancestor(self, c2, warn=False):
627 """return the "best" ancestor context of self and c2
627 """return the "best" ancestor context of self and c2
628
628
629 If there are multiple candidates, it will show a message and check
629 If there are multiple candidates, it will show a message and check
630 merge.preferancestor configuration before falling back to the
630 merge.preferancestor configuration before falling back to the
631 revlog ancestor."""
631 revlog ancestor."""
632 # deal with workingctxs
632 # deal with workingctxs
633 n2 = c2._node
633 n2 = c2._node
634 if n2 is None:
634 if n2 is None:
635 n2 = c2._parents[0]._node
635 n2 = c2._parents[0]._node
636 cahs = self._repo.changelog.commonancestorsheads(self._node, n2)
636 cahs = self._repo.changelog.commonancestorsheads(self._node, n2)
637 if not cahs:
637 if not cahs:
638 anc = nullid
638 anc = nullid
639 elif len(cahs) == 1:
639 elif len(cahs) == 1:
640 anc = cahs[0]
640 anc = cahs[0]
641 else:
641 else:
642 # experimental config: merge.preferancestor
642 # experimental config: merge.preferancestor
643 for r in self._repo.ui.configlist('merge', 'preferancestor', ['*']):
643 for r in self._repo.ui.configlist('merge', 'preferancestor', ['*']):
644 try:
644 try:
645 ctx = changectx(self._repo, r)
645 ctx = changectx(self._repo, r)
646 except error.RepoLookupError:
646 except error.RepoLookupError:
647 continue
647 continue
648 anc = ctx.node()
648 anc = ctx.node()
649 if anc in cahs:
649 if anc in cahs:
650 break
650 break
651 else:
651 else:
652 anc = self._repo.changelog.ancestor(self._node, n2)
652 anc = self._repo.changelog.ancestor(self._node, n2)
653 if warn:
653 if warn:
654 self._repo.ui.status(
654 self._repo.ui.status(
655 (_("note: using %s as ancestor of %s and %s\n") %
655 (_("note: using %s as ancestor of %s and %s\n") %
656 (short(anc), short(self._node), short(n2))) +
656 (short(anc), short(self._node), short(n2))) +
657 ''.join(_(" alternatively, use --config "
657 ''.join(_(" alternatively, use --config "
658 "merge.preferancestor=%s\n") %
658 "merge.preferancestor=%s\n") %
659 short(n) for n in sorted(cahs) if n != anc))
659 short(n) for n in sorted(cahs) if n != anc))
660 return changectx(self._repo, anc)
660 return changectx(self._repo, anc)
661
661
662 def descendant(self, other):
662 def descendant(self, other):
663 """True if other is descendant of this changeset"""
663 """True if other is descendant of this changeset"""
664 return self._repo.changelog.descendant(self._rev, other._rev)
664 return self._repo.changelog.descendant(self._rev, other._rev)
665
665
666 def walk(self, match):
666 def walk(self, match):
667 '''Generates matching file names.'''
667 '''Generates matching file names.'''
668
668
669 # Wrap match.bad method to have message with nodeid
669 # Wrap match.bad method to have message with nodeid
670 def bad(fn, msg):
670 def bad(fn, msg):
671 # The manifest doesn't know about subrepos, so don't complain about
671 # The manifest doesn't know about subrepos, so don't complain about
672 # paths into valid subrepos.
672 # paths into valid subrepos.
673 if any(fn == s or fn.startswith(s + '/')
673 if any(fn == s or fn.startswith(s + '/')
674 for s in self.substate):
674 for s in self.substate):
675 return
675 return
676 match.bad(fn, _('no such file in rev %s') % self)
676 match.bad(fn, _('no such file in rev %s') % self)
677
677
678 m = matchmod.badmatch(match, bad)
678 m = matchmod.badmatch(match, bad)
679 return self._manifest.walk(m)
679 return self._manifest.walk(m)
680
680
681 def matches(self, match):
681 def matches(self, match):
682 return self.walk(match)
682 return self.walk(match)
683
683
684 class basefilectx(object):
684 class basefilectx(object):
685 """A filecontext object represents the common logic for its children:
685 """A filecontext object represents the common logic for its children:
686 filectx: read-only access to a filerevision that is already present
686 filectx: read-only access to a filerevision that is already present
687 in the repo,
687 in the repo,
688 workingfilectx: a filecontext that represents files from the working
688 workingfilectx: a filecontext that represents files from the working
689 directory,
689 directory,
690 memfilectx: a filecontext that represents files in-memory."""
690 memfilectx: a filecontext that represents files in-memory."""
691 def __new__(cls, repo, path, *args, **kwargs):
691 def __new__(cls, repo, path, *args, **kwargs):
692 return super(basefilectx, cls).__new__(cls)
692 return super(basefilectx, cls).__new__(cls)
693
693
694 @propertycache
694 @propertycache
695 def _filelog(self):
695 def _filelog(self):
696 return self._repo.file(self._path)
696 return self._repo.file(self._path)
697
697
698 @propertycache
698 @propertycache
699 def _changeid(self):
699 def _changeid(self):
700 if '_changeid' in self.__dict__:
700 if '_changeid' in self.__dict__:
701 return self._changeid
701 return self._changeid
702 elif '_changectx' in self.__dict__:
702 elif '_changectx' in self.__dict__:
703 return self._changectx.rev()
703 return self._changectx.rev()
704 elif '_descendantrev' in self.__dict__:
704 elif '_descendantrev' in self.__dict__:
705 # this file context was created from a revision with a known
705 # this file context was created from a revision with a known
706 # descendant, we can (lazily) correct for linkrev aliases
706 # descendant, we can (lazily) correct for linkrev aliases
707 return self._adjustlinkrev(self._descendantrev)
707 return self._adjustlinkrev(self._descendantrev)
708 else:
708 else:
709 return self._filelog.linkrev(self._filerev)
709 return self._filelog.linkrev(self._filerev)
710
710
711 @propertycache
711 @propertycache
712 def _filenode(self):
712 def _filenode(self):
713 if '_fileid' in self.__dict__:
713 if '_fileid' in self.__dict__:
714 return self._filelog.lookup(self._fileid)
714 return self._filelog.lookup(self._fileid)
715 else:
715 else:
716 return self._changectx.filenode(self._path)
716 return self._changectx.filenode(self._path)
717
717
718 @propertycache
718 @propertycache
719 def _filerev(self):
719 def _filerev(self):
720 return self._filelog.rev(self._filenode)
720 return self._filelog.rev(self._filenode)
721
721
722 @propertycache
722 @propertycache
723 def _repopath(self):
723 def _repopath(self):
724 return self._path
724 return self._path
725
725
726 def __nonzero__(self):
726 def __nonzero__(self):
727 try:
727 try:
728 self._filenode
728 self._filenode
729 return True
729 return True
730 except error.LookupError:
730 except error.LookupError:
731 # file is missing
731 # file is missing
732 return False
732 return False
733
733
734 __bool__ = __nonzero__
734 __bool__ = __nonzero__
735
735
736 def __str__(self):
736 def __str__(self):
737 try:
737 try:
738 return "%s@%s" % (self.path(), self._changectx)
738 return "%s@%s" % (self.path(), self._changectx)
739 except error.LookupError:
739 except error.LookupError:
740 return "%s@???" % self.path()
740 return "%s@???" % self.path()
741
741
742 def __repr__(self):
742 def __repr__(self):
743 return "<%s %s>" % (type(self).__name__, str(self))
743 return "<%s %s>" % (type(self).__name__, str(self))
744
744
745 def __hash__(self):
745 def __hash__(self):
746 try:
746 try:
747 return hash((self._path, self._filenode))
747 return hash((self._path, self._filenode))
748 except AttributeError:
748 except AttributeError:
749 return id(self)
749 return id(self)
750
750
751 def __eq__(self, other):
751 def __eq__(self, other):
752 try:
752 try:
753 return (type(self) == type(other) and self._path == other._path
753 return (type(self) == type(other) and self._path == other._path
754 and self._filenode == other._filenode)
754 and self._filenode == other._filenode)
755 except AttributeError:
755 except AttributeError:
756 return False
756 return False
757
757
758 def __ne__(self, other):
758 def __ne__(self, other):
759 return not (self == other)
759 return not (self == other)
760
760
761 def filerev(self):
761 def filerev(self):
762 return self._filerev
762 return self._filerev
763 def filenode(self):
763 def filenode(self):
764 return self._filenode
764 return self._filenode
765 def flags(self):
765 def flags(self):
766 return self._changectx.flags(self._path)
766 return self._changectx.flags(self._path)
767 def filelog(self):
767 def filelog(self):
768 return self._filelog
768 return self._filelog
769 def rev(self):
769 def rev(self):
770 return self._changeid
770 return self._changeid
771 def linkrev(self):
771 def linkrev(self):
772 return self._filelog.linkrev(self._filerev)
772 return self._filelog.linkrev(self._filerev)
773 def node(self):
773 def node(self):
774 return self._changectx.node()
774 return self._changectx.node()
775 def hex(self):
775 def hex(self):
776 return self._changectx.hex()
776 return self._changectx.hex()
777 def user(self):
777 def user(self):
778 return self._changectx.user()
778 return self._changectx.user()
779 def date(self):
779 def date(self):
780 return self._changectx.date()
780 return self._changectx.date()
781 def files(self):
781 def files(self):
782 return self._changectx.files()
782 return self._changectx.files()
783 def description(self):
783 def description(self):
784 return self._changectx.description()
784 return self._changectx.description()
785 def branch(self):
785 def branch(self):
786 return self._changectx.branch()
786 return self._changectx.branch()
787 def extra(self):
787 def extra(self):
788 return self._changectx.extra()
788 return self._changectx.extra()
789 def phase(self):
789 def phase(self):
790 return self._changectx.phase()
790 return self._changectx.phase()
791 def phasestr(self):
791 def phasestr(self):
792 return self._changectx.phasestr()
792 return self._changectx.phasestr()
793 def manifest(self):
793 def manifest(self):
794 return self._changectx.manifest()
794 return self._changectx.manifest()
795 def changectx(self):
795 def changectx(self):
796 return self._changectx
796 return self._changectx
797 def repo(self):
797 def repo(self):
798 return self._repo
798 return self._repo
799
799
800 def path(self):
800 def path(self):
801 return self._path
801 return self._path
802
802
803 def isbinary(self):
803 def isbinary(self):
804 try:
804 try:
805 return util.binary(self.data())
805 return util.binary(self.data())
806 except IOError:
806 except IOError:
807 return False
807 return False
808 def isexec(self):
808 def isexec(self):
809 return 'x' in self.flags()
809 return 'x' in self.flags()
810 def islink(self):
810 def islink(self):
811 return 'l' in self.flags()
811 return 'l' in self.flags()
812
812
813 def isabsent(self):
813 def isabsent(self):
814 """whether this filectx represents a file not in self._changectx
814 """whether this filectx represents a file not in self._changectx
815
815
816 This is mainly for merge code to detect change/delete conflicts. This is
816 This is mainly for merge code to detect change/delete conflicts. This is
817 expected to be True for all subclasses of basectx."""
817 expected to be True for all subclasses of basectx."""
818 return False
818 return False
819
819
820 _customcmp = False
820 _customcmp = False
821 def cmp(self, fctx):
821 def cmp(self, fctx):
822 """compare with other file context
822 """compare with other file context
823
823
824 returns True if different than fctx.
824 returns True if different than fctx.
825 """
825 """
826 if fctx._customcmp:
826 if fctx._customcmp:
827 return fctx.cmp(self)
827 return fctx.cmp(self)
828
828
829 if (fctx._filenode is None
829 if (fctx._filenode is None
830 and (self._repo._encodefilterpats
830 and (self._repo._encodefilterpats
831 # if file data starts with '\1\n', empty metadata block is
831 # if file data starts with '\1\n', empty metadata block is
832 # prepended, which adds 4 bytes to filelog.size().
832 # prepended, which adds 4 bytes to filelog.size().
833 or self.size() - 4 == fctx.size())
833 or self.size() - 4 == fctx.size())
834 or self.size() == fctx.size()):
834 or self.size() == fctx.size()):
835 return self._filelog.cmp(self._filenode, fctx.data())
835 return self._filelog.cmp(self._filenode, fctx.data())
836
836
837 return True
837 return True
838
838
839 def _adjustlinkrev(self, srcrev, inclusive=False):
839 def _adjustlinkrev(self, srcrev, inclusive=False):
840 """return the first ancestor of <srcrev> introducing <fnode>
840 """return the first ancestor of <srcrev> introducing <fnode>
841
841
842 If the linkrev of the file revision does not point to an ancestor of
842 If the linkrev of the file revision does not point to an ancestor of
843 srcrev, we'll walk down the ancestors until we find one introducing
843 srcrev, we'll walk down the ancestors until we find one introducing
844 this file revision.
844 this file revision.
845
845
846 :srcrev: the changeset revision we search ancestors from
846 :srcrev: the changeset revision we search ancestors from
847 :inclusive: if true, the src revision will also be checked
847 :inclusive: if true, the src revision will also be checked
848 """
848 """
849 repo = self._repo
849 repo = self._repo
850 cl = repo.unfiltered().changelog
850 cl = repo.unfiltered().changelog
851 mfl = repo.manifestlog
851 mfl = repo.manifestlog
852 # fetch the linkrev
852 # fetch the linkrev
853 lkr = self.linkrev()
853 lkr = self.linkrev()
854 # hack to reuse ancestor computation when searching for renames
854 # hack to reuse ancestor computation when searching for renames
855 memberanc = getattr(self, '_ancestrycontext', None)
855 memberanc = getattr(self, '_ancestrycontext', None)
856 iteranc = None
856 iteranc = None
857 if srcrev is None:
857 if srcrev is None:
858 # wctx case, used by workingfilectx during mergecopy
858 # wctx case, used by workingfilectx during mergecopy
859 revs = [p.rev() for p in self._repo[None].parents()]
859 revs = [p.rev() for p in self._repo[None].parents()]
860 inclusive = True # we skipped the real (revless) source
860 inclusive = True # we skipped the real (revless) source
861 else:
861 else:
862 revs = [srcrev]
862 revs = [srcrev]
863 if memberanc is None:
863 if memberanc is None:
864 memberanc = iteranc = cl.ancestors(revs, lkr,
864 memberanc = iteranc = cl.ancestors(revs, lkr,
865 inclusive=inclusive)
865 inclusive=inclusive)
866 # check if this linkrev is an ancestor of srcrev
866 # check if this linkrev is an ancestor of srcrev
867 if lkr not in memberanc:
867 if lkr not in memberanc:
868 if iteranc is None:
868 if iteranc is None:
869 iteranc = cl.ancestors(revs, lkr, inclusive=inclusive)
869 iteranc = cl.ancestors(revs, lkr, inclusive=inclusive)
870 fnode = self._filenode
870 fnode = self._filenode
871 path = self._path
871 path = self._path
872 for a in iteranc:
872 for a in iteranc:
873 ac = cl.read(a) # get changeset data (we avoid object creation)
873 ac = cl.read(a) # get changeset data (we avoid object creation)
874 if path in ac[3]: # checking the 'files' field.
874 if path in ac[3]: # checking the 'files' field.
875 # The file has been touched, check if the content is
875 # The file has been touched, check if the content is
876 # similar to the one we search for.
876 # similar to the one we search for.
877 if fnode == mfl[ac[0]].readfast().get(path):
877 if fnode == mfl[ac[0]].readfast().get(path):
878 return a
878 return a
879 # In theory, we should never get out of that loop without a result.
879 # In theory, we should never get out of that loop without a result.
880 # But if manifest uses a buggy file revision (not children of the
880 # But if manifest uses a buggy file revision (not children of the
881 # one it replaces) we could. Such a buggy situation will likely
881 # one it replaces) we could. Such a buggy situation will likely
882 # result is crash somewhere else at to some point.
882 # result is crash somewhere else at to some point.
883 return lkr
883 return lkr
884
884
885 def introrev(self):
885 def introrev(self):
886 """return the rev of the changeset which introduced this file revision
886 """return the rev of the changeset which introduced this file revision
887
887
888 This method is different from linkrev because it take into account the
888 This method is different from linkrev because it take into account the
889 changeset the filectx was created from. It ensures the returned
889 changeset the filectx was created from. It ensures the returned
890 revision is one of its ancestors. This prevents bugs from
890 revision is one of its ancestors. This prevents bugs from
891 'linkrev-shadowing' when a file revision is used by multiple
891 'linkrev-shadowing' when a file revision is used by multiple
892 changesets.
892 changesets.
893 """
893 """
894 lkr = self.linkrev()
894 lkr = self.linkrev()
895 attrs = vars(self)
895 attrs = vars(self)
896 noctx = not ('_changeid' in attrs or '_changectx' in attrs)
896 noctx = not ('_changeid' in attrs or '_changectx' in attrs)
897 if noctx or self.rev() == lkr:
897 if noctx or self.rev() == lkr:
898 return self.linkrev()
898 return self.linkrev()
899 return self._adjustlinkrev(self.rev(), inclusive=True)
899 return self._adjustlinkrev(self.rev(), inclusive=True)
900
900
901 def _parentfilectx(self, path, fileid, filelog):
901 def _parentfilectx(self, path, fileid, filelog):
902 """create parent filectx keeping ancestry info for _adjustlinkrev()"""
902 """create parent filectx keeping ancestry info for _adjustlinkrev()"""
903 fctx = filectx(self._repo, path, fileid=fileid, filelog=filelog)
903 fctx = filectx(self._repo, path, fileid=fileid, filelog=filelog)
904 if '_changeid' in vars(self) or '_changectx' in vars(self):
904 if '_changeid' in vars(self) or '_changectx' in vars(self):
905 # If self is associated with a changeset (probably explicitly
905 # If self is associated with a changeset (probably explicitly
906 # fed), ensure the created filectx is associated with a
906 # fed), ensure the created filectx is associated with a
907 # changeset that is an ancestor of self.changectx.
907 # changeset that is an ancestor of self.changectx.
908 # This lets us later use _adjustlinkrev to get a correct link.
908 # This lets us later use _adjustlinkrev to get a correct link.
909 fctx._descendantrev = self.rev()
909 fctx._descendantrev = self.rev()
910 fctx._ancestrycontext = getattr(self, '_ancestrycontext', None)
910 fctx._ancestrycontext = getattr(self, '_ancestrycontext', None)
911 elif '_descendantrev' in vars(self):
911 elif '_descendantrev' in vars(self):
912 # Otherwise propagate _descendantrev if we have one associated.
912 # Otherwise propagate _descendantrev if we have one associated.
913 fctx._descendantrev = self._descendantrev
913 fctx._descendantrev = self._descendantrev
914 fctx._ancestrycontext = getattr(self, '_ancestrycontext', None)
914 fctx._ancestrycontext = getattr(self, '_ancestrycontext', None)
915 return fctx
915 return fctx
916
916
917 def parents(self):
917 def parents(self):
918 _path = self._path
918 _path = self._path
919 fl = self._filelog
919 fl = self._filelog
920 parents = self._filelog.parents(self._filenode)
920 parents = self._filelog.parents(self._filenode)
921 pl = [(_path, node, fl) for node in parents if node != nullid]
921 pl = [(_path, node, fl) for node in parents if node != nullid]
922
922
923 r = fl.renamed(self._filenode)
923 r = fl.renamed(self._filenode)
924 if r:
924 if r:
925 # - In the simple rename case, both parent are nullid, pl is empty.
925 # - In the simple rename case, both parent are nullid, pl is empty.
926 # - In case of merge, only one of the parent is null id and should
926 # - In case of merge, only one of the parent is null id and should
927 # be replaced with the rename information. This parent is -always-
927 # be replaced with the rename information. This parent is -always-
928 # the first one.
928 # the first one.
929 #
929 #
930 # As null id have always been filtered out in the previous list
930 # As null id have always been filtered out in the previous list
931 # comprehension, inserting to 0 will always result in "replacing
931 # comprehension, inserting to 0 will always result in "replacing
932 # first nullid parent with rename information.
932 # first nullid parent with rename information.
933 pl.insert(0, (r[0], r[1], self._repo.file(r[0])))
933 pl.insert(0, (r[0], r[1], self._repo.file(r[0])))
934
934
935 return [self._parentfilectx(path, fnode, l) for path, fnode, l in pl]
935 return [self._parentfilectx(path, fnode, l) for path, fnode, l in pl]
936
936
937 def p1(self):
937 def p1(self):
938 return self.parents()[0]
938 return self.parents()[0]
939
939
940 def p2(self):
940 def p2(self):
941 p = self.parents()
941 p = self.parents()
942 if len(p) == 2:
942 if len(p) == 2:
943 return p[1]
943 return p[1]
944 return filectx(self._repo, self._path, fileid=-1, filelog=self._filelog)
944 return filectx(self._repo, self._path, fileid=-1, filelog=self._filelog)
945
945
946 def annotate(self, follow=False, linenumber=False, diffopts=None):
946 def annotate(self, follow=False, linenumber=False, diffopts=None):
947 '''returns a list of tuples of ((ctx, number), line) for each line
947 '''returns a list of tuples of ((ctx, number), line) for each line
948 in the file, where ctx is the filectx of the node where
948 in the file, where ctx is the filectx of the node where
949 that line was last changed; if linenumber parameter is true, number is
949 that line was last changed; if linenumber parameter is true, number is
950 the line number at the first appearance in the managed file, otherwise,
950 the line number at the first appearance in the managed file, otherwise,
951 number has a fixed value of False.
951 number has a fixed value of False.
952 '''
952 '''
953
953
954 def lines(text):
954 def lines(text):
955 if text.endswith("\n"):
955 if text.endswith("\n"):
956 return text.count("\n")
956 return text.count("\n")
957 return text.count("\n") + int(bool(text))
957 return text.count("\n") + int(bool(text))
958
958
959 if linenumber:
959 if linenumber:
960 def decorate(text, rev):
960 def decorate(text, rev):
961 return ([(rev, i) for i in xrange(1, lines(text) + 1)], text)
961 return ([(rev, i) for i in xrange(1, lines(text) + 1)], text)
962 else:
962 else:
963 def decorate(text, rev):
963 def decorate(text, rev):
964 return ([(rev, False)] * lines(text), text)
964 return ([(rev, False)] * lines(text), text)
965
965
966 def pair(parent, child):
966 def pair(parent, child):
967 blocks = mdiff.allblocks(parent[1], child[1], opts=diffopts)
967 blocks = mdiff.allblocks(parent[1], child[1], opts=diffopts)
968 for (a1, a2, b1, b2), t in blocks:
968 for (a1, a2, b1, b2), t in blocks:
969 # Changed blocks ('!') or blocks made only of blank lines ('~')
969 # Changed blocks ('!') or blocks made only of blank lines ('~')
970 # belong to the child.
970 # belong to the child.
971 if t == '=':
971 if t == '=':
972 child[0][b1:b2] = parent[0][a1:a2]
972 child[0][b1:b2] = parent[0][a1:a2]
973 return child
973 return child
974
974
975 getlog = util.lrucachefunc(lambda x: self._repo.file(x))
975 getlog = util.lrucachefunc(lambda x: self._repo.file(x))
976
976
977 def parents(f):
977 def parents(f):
978 # Cut _descendantrev here to mitigate the penalty of lazy linkrev
978 # Cut _descendantrev here to mitigate the penalty of lazy linkrev
979 # adjustment. Otherwise, p._adjustlinkrev() would walk changelog
979 # adjustment. Otherwise, p._adjustlinkrev() would walk changelog
980 # from the topmost introrev (= srcrev) down to p.linkrev() if it
980 # from the topmost introrev (= srcrev) down to p.linkrev() if it
981 # isn't an ancestor of the srcrev.
981 # isn't an ancestor of the srcrev.
982 f._changeid
982 f._changeid
983 pl = f.parents()
983 pl = f.parents()
984
984
985 # Don't return renamed parents if we aren't following.
985 # Don't return renamed parents if we aren't following.
986 if not follow:
986 if not follow:
987 pl = [p for p in pl if p.path() == f.path()]
987 pl = [p for p in pl if p.path() == f.path()]
988
988
989 # renamed filectx won't have a filelog yet, so set it
989 # renamed filectx won't have a filelog yet, so set it
990 # from the cache to save time
990 # from the cache to save time
991 for p in pl:
991 for p in pl:
992 if not '_filelog' in p.__dict__:
992 if not '_filelog' in p.__dict__:
993 p._filelog = getlog(p.path())
993 p._filelog = getlog(p.path())
994
994
995 return pl
995 return pl
996
996
997 # use linkrev to find the first changeset where self appeared
997 # use linkrev to find the first changeset where self appeared
998 base = self
998 base = self
999 introrev = self.introrev()
999 introrev = self.introrev()
1000 if self.rev() != introrev:
1000 if self.rev() != introrev:
1001 base = self.filectx(self.filenode(), changeid=introrev)
1001 base = self.filectx(self.filenode(), changeid=introrev)
1002 if getattr(base, '_ancestrycontext', None) is None:
1002 if getattr(base, '_ancestrycontext', None) is None:
1003 cl = self._repo.changelog
1003 cl = self._repo.changelog
1004 if introrev is None:
1004 if introrev is None:
1005 # wctx is not inclusive, but works because _ancestrycontext
1005 # wctx is not inclusive, but works because _ancestrycontext
1006 # is used to test filelog revisions
1006 # is used to test filelog revisions
1007 ac = cl.ancestors([p.rev() for p in base.parents()],
1007 ac = cl.ancestors([p.rev() for p in base.parents()],
1008 inclusive=True)
1008 inclusive=True)
1009 else:
1009 else:
1010 ac = cl.ancestors([introrev], inclusive=True)
1010 ac = cl.ancestors([introrev], inclusive=True)
1011 base._ancestrycontext = ac
1011 base._ancestrycontext = ac
1012
1012
1013 # This algorithm would prefer to be recursive, but Python is a
1013 # This algorithm would prefer to be recursive, but Python is a
1014 # bit recursion-hostile. Instead we do an iterative
1014 # bit recursion-hostile. Instead we do an iterative
1015 # depth-first search.
1015 # depth-first search.
1016
1016
1017 # 1st DFS pre-calculates pcache and needed
1017 # 1st DFS pre-calculates pcache and needed
1018 visit = [base]
1018 visit = [base]
1019 pcache = {}
1019 pcache = {}
1020 needed = {base: 1}
1020 needed = {base: 1}
1021 while visit:
1021 while visit:
1022 f = visit.pop()
1022 f = visit.pop()
1023 if f in pcache:
1023 if f in pcache:
1024 continue
1024 continue
1025 pl = parents(f)
1025 pl = parents(f)
1026 pcache[f] = pl
1026 pcache[f] = pl
1027 for p in pl:
1027 for p in pl:
1028 needed[p] = needed.get(p, 0) + 1
1028 needed[p] = needed.get(p, 0) + 1
1029 if p not in pcache:
1029 if p not in pcache:
1030 visit.append(p)
1030 visit.append(p)
1031
1031
1032 # 2nd DFS does the actual annotate
1032 # 2nd DFS does the actual annotate
1033 visit[:] = [base]
1033 visit[:] = [base]
1034 hist = {}
1034 hist = {}
1035 while visit:
1035 while visit:
1036 f = visit[-1]
1036 f = visit[-1]
1037 if f in hist:
1037 if f in hist:
1038 visit.pop()
1038 visit.pop()
1039 continue
1039 continue
1040
1040
1041 ready = True
1041 ready = True
1042 pl = pcache[f]
1042 pl = pcache[f]
1043 for p in pl:
1043 for p in pl:
1044 if p not in hist:
1044 if p not in hist:
1045 ready = False
1045 ready = False
1046 visit.append(p)
1046 visit.append(p)
1047 if ready:
1047 if ready:
1048 visit.pop()
1048 visit.pop()
1049 curr = decorate(f.data(), f)
1049 curr = decorate(f.data(), f)
1050 for p in pl:
1050 for p in pl:
1051 curr = pair(hist[p], curr)
1051 curr = pair(hist[p], curr)
1052 if needed[p] == 1:
1052 if needed[p] == 1:
1053 del hist[p]
1053 del hist[p]
1054 del needed[p]
1054 del needed[p]
1055 else:
1055 else:
1056 needed[p] -= 1
1056 needed[p] -= 1
1057
1057
1058 hist[f] = curr
1058 hist[f] = curr
1059 del pcache[f]
1059 del pcache[f]
1060
1060
1061 return zip(hist[base][0], hist[base][1].splitlines(True))
1061 return zip(hist[base][0], hist[base][1].splitlines(True))
1062
1062
1063 def ancestors(self, followfirst=False):
1063 def ancestors(self, followfirst=False):
1064 visit = {}
1064 visit = {}
1065 c = self
1065 c = self
1066 if followfirst:
1066 if followfirst:
1067 cut = 1
1067 cut = 1
1068 else:
1068 else:
1069 cut = None
1069 cut = None
1070
1070
1071 while True:
1071 while True:
1072 for parent in c.parents()[:cut]:
1072 for parent in c.parents()[:cut]:
1073 visit[(parent.linkrev(), parent.filenode())] = parent
1073 visit[(parent.linkrev(), parent.filenode())] = parent
1074 if not visit:
1074 if not visit:
1075 break
1075 break
1076 c = visit.pop(max(visit))
1076 c = visit.pop(max(visit))
1077 yield c
1077 yield c
1078
1078
1079 class filectx(basefilectx):
1079 class filectx(basefilectx):
1080 """A filecontext object makes access to data related to a particular
1080 """A filecontext object makes access to data related to a particular
1081 filerevision convenient."""
1081 filerevision convenient."""
1082 def __init__(self, repo, path, changeid=None, fileid=None,
1082 def __init__(self, repo, path, changeid=None, fileid=None,
1083 filelog=None, changectx=None):
1083 filelog=None, changectx=None):
1084 """changeid can be a changeset revision, node, or tag.
1084 """changeid can be a changeset revision, node, or tag.
1085 fileid can be a file revision or node."""
1085 fileid can be a file revision or node."""
1086 self._repo = repo
1086 self._repo = repo
1087 self._path = path
1087 self._path = path
1088
1088
1089 assert (changeid is not None
1089 assert (changeid is not None
1090 or fileid is not None
1090 or fileid is not None
1091 or changectx is not None), \
1091 or changectx is not None), \
1092 ("bad args: changeid=%r, fileid=%r, changectx=%r"
1092 ("bad args: changeid=%r, fileid=%r, changectx=%r"
1093 % (changeid, fileid, changectx))
1093 % (changeid, fileid, changectx))
1094
1094
1095 if filelog is not None:
1095 if filelog is not None:
1096 self._filelog = filelog
1096 self._filelog = filelog
1097
1097
1098 if changeid is not None:
1098 if changeid is not None:
1099 self._changeid = changeid
1099 self._changeid = changeid
1100 if changectx is not None:
1100 if changectx is not None:
1101 self._changectx = changectx
1101 self._changectx = changectx
1102 if fileid is not None:
1102 if fileid is not None:
1103 self._fileid = fileid
1103 self._fileid = fileid
1104
1104
1105 @propertycache
1105 @propertycache
1106 def _changectx(self):
1106 def _changectx(self):
1107 try:
1107 try:
1108 return changectx(self._repo, self._changeid)
1108 return changectx(self._repo, self._changeid)
1109 except error.FilteredRepoLookupError:
1109 except error.FilteredRepoLookupError:
1110 # Linkrev may point to any revision in the repository. When the
1110 # Linkrev may point to any revision in the repository. When the
1111 # repository is filtered this may lead to `filectx` trying to build
1111 # repository is filtered this may lead to `filectx` trying to build
1112 # `changectx` for filtered revision. In such case we fallback to
1112 # `changectx` for filtered revision. In such case we fallback to
1113 # creating `changectx` on the unfiltered version of the reposition.
1113 # creating `changectx` on the unfiltered version of the reposition.
1114 # This fallback should not be an issue because `changectx` from
1114 # This fallback should not be an issue because `changectx` from
1115 # `filectx` are not used in complex operations that care about
1115 # `filectx` are not used in complex operations that care about
1116 # filtering.
1116 # filtering.
1117 #
1117 #
1118 # This fallback is a cheap and dirty fix that prevent several
1118 # This fallback is a cheap and dirty fix that prevent several
1119 # crashes. It does not ensure the behavior is correct. However the
1119 # crashes. It does not ensure the behavior is correct. However the
1120 # behavior was not correct before filtering either and "incorrect
1120 # behavior was not correct before filtering either and "incorrect
1121 # behavior" is seen as better as "crash"
1121 # behavior" is seen as better as "crash"
1122 #
1122 #
1123 # Linkrevs have several serious troubles with filtering that are
1123 # Linkrevs have several serious troubles with filtering that are
1124 # complicated to solve. Proper handling of the issue here should be
1124 # complicated to solve. Proper handling of the issue here should be
1125 # considered when solving linkrev issue are on the table.
1125 # considered when solving linkrev issue are on the table.
1126 return changectx(self._repo.unfiltered(), self._changeid)
1126 return changectx(self._repo.unfiltered(), self._changeid)
1127
1127
1128 def filectx(self, fileid, changeid=None):
1128 def filectx(self, fileid, changeid=None):
1129 '''opens an arbitrary revision of the file without
1129 '''opens an arbitrary revision of the file without
1130 opening a new filelog'''
1130 opening a new filelog'''
1131 return filectx(self._repo, self._path, fileid=fileid,
1131 return filectx(self._repo, self._path, fileid=fileid,
1132 filelog=self._filelog, changeid=changeid)
1132 filelog=self._filelog, changeid=changeid)
1133
1133
1134 def rawdata(self):
1134 def rawdata(self):
1135 return self._filelog.revision(self._filenode, raw=True)
1135 return self._filelog.revision(self._filenode, raw=True)
1136
1136
1137 def data(self):
1137 def data(self):
1138 try:
1138 try:
1139 return self._filelog.read(self._filenode)
1139 return self._filelog.read(self._filenode)
1140 except error.CensoredNodeError:
1140 except error.CensoredNodeError:
1141 if self._repo.ui.config("censor", "policy", "abort") == "ignore":
1141 if self._repo.ui.config("censor", "policy", "abort") == "ignore":
1142 return ""
1142 return ""
1143 raise error.Abort(_("censored node: %s") % short(self._filenode),
1143 raise error.Abort(_("censored node: %s") % short(self._filenode),
1144 hint=_("set censor.policy to ignore errors"))
1144 hint=_("set censor.policy to ignore errors"))
1145
1145
1146 def size(self):
1146 def size(self):
1147 return self._filelog.size(self._filerev)
1147 return self._filelog.size(self._filerev)
1148
1148
1149 def renamed(self):
1149 def renamed(self):
1150 """check if file was actually renamed in this changeset revision
1150 """check if file was actually renamed in this changeset revision
1151
1151
1152 If rename logged in file revision, we report copy for changeset only
1152 If rename logged in file revision, we report copy for changeset only
1153 if file revisions linkrev points back to the changeset in question
1153 if file revisions linkrev points back to the changeset in question
1154 or both changeset parents contain different file revisions.
1154 or both changeset parents contain different file revisions.
1155 """
1155 """
1156
1156
1157 renamed = self._filelog.renamed(self._filenode)
1157 renamed = self._filelog.renamed(self._filenode)
1158 if not renamed:
1158 if not renamed:
1159 return renamed
1159 return renamed
1160
1160
1161 if self.rev() == self.linkrev():
1161 if self.rev() == self.linkrev():
1162 return renamed
1162 return renamed
1163
1163
1164 name = self.path()
1164 name = self.path()
1165 fnode = self._filenode
1165 fnode = self._filenode
1166 for p in self._changectx.parents():
1166 for p in self._changectx.parents():
1167 try:
1167 try:
1168 if fnode == p.filenode(name):
1168 if fnode == p.filenode(name):
1169 return None
1169 return None
1170 except error.LookupError:
1170 except error.LookupError:
1171 pass
1171 pass
1172 return renamed
1172 return renamed
1173
1173
1174 def children(self):
1174 def children(self):
1175 # hard for renames
1175 # hard for renames
1176 c = self._filelog.children(self._filenode)
1176 c = self._filelog.children(self._filenode)
1177 return [filectx(self._repo, self._path, fileid=x,
1177 return [filectx(self._repo, self._path, fileid=x,
1178 filelog=self._filelog) for x in c]
1178 filelog=self._filelog) for x in c]
1179
1179
1180 def _changesrange(fctx1, fctx2, linerange2, diffopts):
1180 def _changesrange(fctx1, fctx2, linerange2, diffopts):
1181 """Return `(diffinrange, linerange1)` where `diffinrange` is True
1181 """Return `(diffinrange, linerange1)` where `diffinrange` is True
1182 if diff from fctx2 to fctx1 has changes in linerange2 and
1182 if diff from fctx2 to fctx1 has changes in linerange2 and
1183 `linerange1` is the new line range for fctx1.
1183 `linerange1` is the new line range for fctx1.
1184 """
1184 """
1185 blocks = mdiff.allblocks(fctx1.data(), fctx2.data(), diffopts)
1185 blocks = mdiff.allblocks(fctx1.data(), fctx2.data(), diffopts)
1186 filteredblocks, linerange1 = mdiff.blocksinrange(blocks, linerange2)
1186 filteredblocks, linerange1 = mdiff.blocksinrange(blocks, linerange2)
1187 diffinrange = any(stype == '!' for _, stype in filteredblocks)
1187 diffinrange = any(stype == '!' for _, stype in filteredblocks)
1188 return diffinrange, linerange1
1188 return diffinrange, linerange1
1189
1189
1190 def blockancestors(fctx, fromline, toline, followfirst=False):
1190 def blockancestors(fctx, fromline, toline, followfirst=False):
1191 """Yield ancestors of `fctx` with respect to the block of lines within
1191 """Yield ancestors of `fctx` with respect to the block of lines within
1192 `fromline`-`toline` range.
1192 `fromline`-`toline` range.
1193 """
1193 """
1194 diffopts = patch.diffopts(fctx._repo.ui)
1194 diffopts = patch.diffopts(fctx._repo.ui)
1195 introrev = fctx.introrev()
1196 if fctx.rev() != introrev:
1197 fctx = fctx.filectx(fctx.filenode(), changeid=introrev)
1195 visit = {(fctx.linkrev(), fctx.filenode()): (fctx, (fromline, toline))}
1198 visit = {(fctx.linkrev(), fctx.filenode()): (fctx, (fromline, toline))}
1196 while visit:
1199 while visit:
1197 c, linerange2 = visit.pop(max(visit))
1200 c, linerange2 = visit.pop(max(visit))
1198 pl = c.parents()
1201 pl = c.parents()
1199 if followfirst:
1202 if followfirst:
1200 pl = pl[:1]
1203 pl = pl[:1]
1201 if not pl:
1204 if not pl:
1202 # The block originates from the initial revision.
1205 # The block originates from the initial revision.
1203 yield c, linerange2
1206 yield c, linerange2
1204 continue
1207 continue
1205 inrange = False
1208 inrange = False
1206 for p in pl:
1209 for p in pl:
1207 inrangep, linerange1 = _changesrange(p, c, linerange2, diffopts)
1210 inrangep, linerange1 = _changesrange(p, c, linerange2, diffopts)
1208 inrange = inrange or inrangep
1211 inrange = inrange or inrangep
1209 if linerange1[0] == linerange1[1]:
1212 if linerange1[0] == linerange1[1]:
1210 # Parent's linerange is empty, meaning that the block got
1213 # Parent's linerange is empty, meaning that the block got
1211 # introduced in this revision; no need to go futher in this
1214 # introduced in this revision; no need to go futher in this
1212 # branch.
1215 # branch.
1213 continue
1216 continue
1214 visit[p.linkrev(), p.filenode()] = p, linerange1
1217 visit[p.linkrev(), p.filenode()] = p, linerange1
1215 if inrange:
1218 if inrange:
1216 yield c, linerange2
1219 yield c, linerange2
1217
1220
1218 def blockdescendants(fctx, fromline, toline):
1221 def blockdescendants(fctx, fromline, toline):
1219 """Yield descendants of `fctx` with respect to the block of lines within
1222 """Yield descendants of `fctx` with respect to the block of lines within
1220 `fromline`-`toline` range.
1223 `fromline`-`toline` range.
1221 """
1224 """
1222 # First possibly yield 'fctx' if it has changes in range with respect to
1225 # First possibly yield 'fctx' if it has changes in range with respect to
1223 # its parents.
1226 # its parents.
1224 try:
1227 try:
1225 c, linerange1 = next(blockancestors(fctx, fromline, toline))
1228 c, linerange1 = next(blockancestors(fctx, fromline, toline))
1226 except StopIteration:
1229 except StopIteration:
1227 pass
1230 pass
1228 else:
1231 else:
1229 if c == fctx:
1232 if c == fctx:
1230 yield c, linerange1
1233 yield c, linerange1
1231
1234
1232 diffopts = patch.diffopts(fctx._repo.ui)
1235 diffopts = patch.diffopts(fctx._repo.ui)
1233 fl = fctx.filelog()
1236 fl = fctx.filelog()
1234 seen = {fctx.filerev(): (fctx, (fromline, toline))}
1237 seen = {fctx.filerev(): (fctx, (fromline, toline))}
1235 for i in fl.descendants([fctx.filerev()]):
1238 for i in fl.descendants([fctx.filerev()]):
1236 c = fctx.filectx(i)
1239 c = fctx.filectx(i)
1237 inrange = False
1240 inrange = False
1238 for x in fl.parentrevs(i):
1241 for x in fl.parentrevs(i):
1239 try:
1242 try:
1240 p, linerange2 = seen[x]
1243 p, linerange2 = seen[x]
1241 except KeyError:
1244 except KeyError:
1242 # nullrev or other branch
1245 # nullrev or other branch
1243 continue
1246 continue
1244 inrangep, linerange1 = _changesrange(c, p, linerange2, diffopts)
1247 inrangep, linerange1 = _changesrange(c, p, linerange2, diffopts)
1245 inrange = inrange or inrangep
1248 inrange = inrange or inrangep
1246 # If revision 'i' has been seen (it's a merge), we assume that its
1249 # If revision 'i' has been seen (it's a merge), we assume that its
1247 # line range is the same independently of which parents was used
1250 # line range is the same independently of which parents was used
1248 # to compute it.
1251 # to compute it.
1249 assert i not in seen or seen[i][1] == linerange1, (
1252 assert i not in seen or seen[i][1] == linerange1, (
1250 'computed line range for %s is not consistent between '
1253 'computed line range for %s is not consistent between '
1251 'ancestor branches' % c)
1254 'ancestor branches' % c)
1252 seen[i] = c, linerange1
1255 seen[i] = c, linerange1
1253 if inrange:
1256 if inrange:
1254 yield c, linerange1
1257 yield c, linerange1
1255
1258
1256 class committablectx(basectx):
1259 class committablectx(basectx):
1257 """A committablectx object provides common functionality for a context that
1260 """A committablectx object provides common functionality for a context that
1258 wants the ability to commit, e.g. workingctx or memctx."""
1261 wants the ability to commit, e.g. workingctx or memctx."""
1259 def __init__(self, repo, text="", user=None, date=None, extra=None,
1262 def __init__(self, repo, text="", user=None, date=None, extra=None,
1260 changes=None):
1263 changes=None):
1261 self._repo = repo
1264 self._repo = repo
1262 self._rev = None
1265 self._rev = None
1263 self._node = None
1266 self._node = None
1264 self._text = text
1267 self._text = text
1265 if date:
1268 if date:
1266 self._date = util.parsedate(date)
1269 self._date = util.parsedate(date)
1267 if user:
1270 if user:
1268 self._user = user
1271 self._user = user
1269 if changes:
1272 if changes:
1270 self._status = changes
1273 self._status = changes
1271
1274
1272 self._extra = {}
1275 self._extra = {}
1273 if extra:
1276 if extra:
1274 self._extra = extra.copy()
1277 self._extra = extra.copy()
1275 if 'branch' not in self._extra:
1278 if 'branch' not in self._extra:
1276 try:
1279 try:
1277 branch = encoding.fromlocal(self._repo.dirstate.branch())
1280 branch = encoding.fromlocal(self._repo.dirstate.branch())
1278 except UnicodeDecodeError:
1281 except UnicodeDecodeError:
1279 raise error.Abort(_('branch name not in UTF-8!'))
1282 raise error.Abort(_('branch name not in UTF-8!'))
1280 self._extra['branch'] = branch
1283 self._extra['branch'] = branch
1281 if self._extra['branch'] == '':
1284 if self._extra['branch'] == '':
1282 self._extra['branch'] = 'default'
1285 self._extra['branch'] = 'default'
1283
1286
1284 def __str__(self):
1287 def __str__(self):
1285 return str(self._parents[0]) + "+"
1288 return str(self._parents[0]) + "+"
1286
1289
1287 def __nonzero__(self):
1290 def __nonzero__(self):
1288 return True
1291 return True
1289
1292
1290 __bool__ = __nonzero__
1293 __bool__ = __nonzero__
1291
1294
1292 def _buildflagfunc(self):
1295 def _buildflagfunc(self):
1293 # Create a fallback function for getting file flags when the
1296 # Create a fallback function for getting file flags when the
1294 # filesystem doesn't support them
1297 # filesystem doesn't support them
1295
1298
1296 copiesget = self._repo.dirstate.copies().get
1299 copiesget = self._repo.dirstate.copies().get
1297 parents = self.parents()
1300 parents = self.parents()
1298 if len(parents) < 2:
1301 if len(parents) < 2:
1299 # when we have one parent, it's easy: copy from parent
1302 # when we have one parent, it's easy: copy from parent
1300 man = parents[0].manifest()
1303 man = parents[0].manifest()
1301 def func(f):
1304 def func(f):
1302 f = copiesget(f, f)
1305 f = copiesget(f, f)
1303 return man.flags(f)
1306 return man.flags(f)
1304 else:
1307 else:
1305 # merges are tricky: we try to reconstruct the unstored
1308 # merges are tricky: we try to reconstruct the unstored
1306 # result from the merge (issue1802)
1309 # result from the merge (issue1802)
1307 p1, p2 = parents
1310 p1, p2 = parents
1308 pa = p1.ancestor(p2)
1311 pa = p1.ancestor(p2)
1309 m1, m2, ma = p1.manifest(), p2.manifest(), pa.manifest()
1312 m1, m2, ma = p1.manifest(), p2.manifest(), pa.manifest()
1310
1313
1311 def func(f):
1314 def func(f):
1312 f = copiesget(f, f) # may be wrong for merges with copies
1315 f = copiesget(f, f) # may be wrong for merges with copies
1313 fl1, fl2, fla = m1.flags(f), m2.flags(f), ma.flags(f)
1316 fl1, fl2, fla = m1.flags(f), m2.flags(f), ma.flags(f)
1314 if fl1 == fl2:
1317 if fl1 == fl2:
1315 return fl1
1318 return fl1
1316 if fl1 == fla:
1319 if fl1 == fla:
1317 return fl2
1320 return fl2
1318 if fl2 == fla:
1321 if fl2 == fla:
1319 return fl1
1322 return fl1
1320 return '' # punt for conflicts
1323 return '' # punt for conflicts
1321
1324
1322 return func
1325 return func
1323
1326
1324 @propertycache
1327 @propertycache
1325 def _flagfunc(self):
1328 def _flagfunc(self):
1326 return self._repo.dirstate.flagfunc(self._buildflagfunc)
1329 return self._repo.dirstate.flagfunc(self._buildflagfunc)
1327
1330
1328 @propertycache
1331 @propertycache
1329 def _status(self):
1332 def _status(self):
1330 return self._repo.status()
1333 return self._repo.status()
1331
1334
1332 @propertycache
1335 @propertycache
1333 def _user(self):
1336 def _user(self):
1334 return self._repo.ui.username()
1337 return self._repo.ui.username()
1335
1338
1336 @propertycache
1339 @propertycache
1337 def _date(self):
1340 def _date(self):
1338 return util.makedate()
1341 return util.makedate()
1339
1342
1340 def subrev(self, subpath):
1343 def subrev(self, subpath):
1341 return None
1344 return None
1342
1345
1343 def manifestnode(self):
1346 def manifestnode(self):
1344 return None
1347 return None
1345 def user(self):
1348 def user(self):
1346 return self._user or self._repo.ui.username()
1349 return self._user or self._repo.ui.username()
1347 def date(self):
1350 def date(self):
1348 return self._date
1351 return self._date
1349 def description(self):
1352 def description(self):
1350 return self._text
1353 return self._text
1351 def files(self):
1354 def files(self):
1352 return sorted(self._status.modified + self._status.added +
1355 return sorted(self._status.modified + self._status.added +
1353 self._status.removed)
1356 self._status.removed)
1354
1357
1355 def modified(self):
1358 def modified(self):
1356 return self._status.modified
1359 return self._status.modified
1357 def added(self):
1360 def added(self):
1358 return self._status.added
1361 return self._status.added
1359 def removed(self):
1362 def removed(self):
1360 return self._status.removed
1363 return self._status.removed
1361 def deleted(self):
1364 def deleted(self):
1362 return self._status.deleted
1365 return self._status.deleted
1363 def branch(self):
1366 def branch(self):
1364 return encoding.tolocal(self._extra['branch'])
1367 return encoding.tolocal(self._extra['branch'])
1365 def closesbranch(self):
1368 def closesbranch(self):
1366 return 'close' in self._extra
1369 return 'close' in self._extra
1367 def extra(self):
1370 def extra(self):
1368 return self._extra
1371 return self._extra
1369
1372
1370 def tags(self):
1373 def tags(self):
1371 return []
1374 return []
1372
1375
1373 def bookmarks(self):
1376 def bookmarks(self):
1374 b = []
1377 b = []
1375 for p in self.parents():
1378 for p in self.parents():
1376 b.extend(p.bookmarks())
1379 b.extend(p.bookmarks())
1377 return b
1380 return b
1378
1381
1379 def phase(self):
1382 def phase(self):
1380 phase = phases.draft # default phase to draft
1383 phase = phases.draft # default phase to draft
1381 for p in self.parents():
1384 for p in self.parents():
1382 phase = max(phase, p.phase())
1385 phase = max(phase, p.phase())
1383 return phase
1386 return phase
1384
1387
1385 def hidden(self):
1388 def hidden(self):
1386 return False
1389 return False
1387
1390
1388 def children(self):
1391 def children(self):
1389 return []
1392 return []
1390
1393
1391 def flags(self, path):
1394 def flags(self, path):
1392 if '_manifest' in self.__dict__:
1395 if '_manifest' in self.__dict__:
1393 try:
1396 try:
1394 return self._manifest.flags(path)
1397 return self._manifest.flags(path)
1395 except KeyError:
1398 except KeyError:
1396 return ''
1399 return ''
1397
1400
1398 try:
1401 try:
1399 return self._flagfunc(path)
1402 return self._flagfunc(path)
1400 except OSError:
1403 except OSError:
1401 return ''
1404 return ''
1402
1405
1403 def ancestor(self, c2):
1406 def ancestor(self, c2):
1404 """return the "best" ancestor context of self and c2"""
1407 """return the "best" ancestor context of self and c2"""
1405 return self._parents[0].ancestor(c2) # punt on two parents for now
1408 return self._parents[0].ancestor(c2) # punt on two parents for now
1406
1409
1407 def walk(self, match):
1410 def walk(self, match):
1408 '''Generates matching file names.'''
1411 '''Generates matching file names.'''
1409 return sorted(self._repo.dirstate.walk(match, sorted(self.substate),
1412 return sorted(self._repo.dirstate.walk(match, sorted(self.substate),
1410 True, False))
1413 True, False))
1411
1414
1412 def matches(self, match):
1415 def matches(self, match):
1413 return sorted(self._repo.dirstate.matches(match))
1416 return sorted(self._repo.dirstate.matches(match))
1414
1417
1415 def ancestors(self):
1418 def ancestors(self):
1416 for p in self._parents:
1419 for p in self._parents:
1417 yield p
1420 yield p
1418 for a in self._repo.changelog.ancestors(
1421 for a in self._repo.changelog.ancestors(
1419 [p.rev() for p in self._parents]):
1422 [p.rev() for p in self._parents]):
1420 yield changectx(self._repo, a)
1423 yield changectx(self._repo, a)
1421
1424
1422 def markcommitted(self, node):
1425 def markcommitted(self, node):
1423 """Perform post-commit cleanup necessary after committing this ctx
1426 """Perform post-commit cleanup necessary after committing this ctx
1424
1427
1425 Specifically, this updates backing stores this working context
1428 Specifically, this updates backing stores this working context
1426 wraps to reflect the fact that the changes reflected by this
1429 wraps to reflect the fact that the changes reflected by this
1427 workingctx have been committed. For example, it marks
1430 workingctx have been committed. For example, it marks
1428 modified and added files as normal in the dirstate.
1431 modified and added files as normal in the dirstate.
1429
1432
1430 """
1433 """
1431
1434
1432 self._repo.dirstate.beginparentchange()
1435 self._repo.dirstate.beginparentchange()
1433 for f in self.modified() + self.added():
1436 for f in self.modified() + self.added():
1434 self._repo.dirstate.normal(f)
1437 self._repo.dirstate.normal(f)
1435 for f in self.removed():
1438 for f in self.removed():
1436 self._repo.dirstate.drop(f)
1439 self._repo.dirstate.drop(f)
1437 self._repo.dirstate.setparents(node)
1440 self._repo.dirstate.setparents(node)
1438 self._repo.dirstate.endparentchange()
1441 self._repo.dirstate.endparentchange()
1439
1442
1440 # write changes out explicitly, because nesting wlock at
1443 # write changes out explicitly, because nesting wlock at
1441 # runtime may prevent 'wlock.release()' in 'repo.commit()'
1444 # runtime may prevent 'wlock.release()' in 'repo.commit()'
1442 # from immediately doing so for subsequent changing files
1445 # from immediately doing so for subsequent changing files
1443 self._repo.dirstate.write(self._repo.currenttransaction())
1446 self._repo.dirstate.write(self._repo.currenttransaction())
1444
1447
1445 class workingctx(committablectx):
1448 class workingctx(committablectx):
1446 """A workingctx object makes access to data related to
1449 """A workingctx object makes access to data related to
1447 the current working directory convenient.
1450 the current working directory convenient.
1448 date - any valid date string or (unixtime, offset), or None.
1451 date - any valid date string or (unixtime, offset), or None.
1449 user - username string, or None.
1452 user - username string, or None.
1450 extra - a dictionary of extra values, or None.
1453 extra - a dictionary of extra values, or None.
1451 changes - a list of file lists as returned by localrepo.status()
1454 changes - a list of file lists as returned by localrepo.status()
1452 or None to use the repository status.
1455 or None to use the repository status.
1453 """
1456 """
1454 def __init__(self, repo, text="", user=None, date=None, extra=None,
1457 def __init__(self, repo, text="", user=None, date=None, extra=None,
1455 changes=None):
1458 changes=None):
1456 super(workingctx, self).__init__(repo, text, user, date, extra, changes)
1459 super(workingctx, self).__init__(repo, text, user, date, extra, changes)
1457
1460
1458 def __iter__(self):
1461 def __iter__(self):
1459 d = self._repo.dirstate
1462 d = self._repo.dirstate
1460 for f in d:
1463 for f in d:
1461 if d[f] != 'r':
1464 if d[f] != 'r':
1462 yield f
1465 yield f
1463
1466
1464 def __contains__(self, key):
1467 def __contains__(self, key):
1465 return self._repo.dirstate[key] not in "?r"
1468 return self._repo.dirstate[key] not in "?r"
1466
1469
1467 def hex(self):
1470 def hex(self):
1468 return hex(wdirid)
1471 return hex(wdirid)
1469
1472
1470 @propertycache
1473 @propertycache
1471 def _parents(self):
1474 def _parents(self):
1472 p = self._repo.dirstate.parents()
1475 p = self._repo.dirstate.parents()
1473 if p[1] == nullid:
1476 if p[1] == nullid:
1474 p = p[:-1]
1477 p = p[:-1]
1475 return [changectx(self._repo, x) for x in p]
1478 return [changectx(self._repo, x) for x in p]
1476
1479
1477 def filectx(self, path, filelog=None):
1480 def filectx(self, path, filelog=None):
1478 """get a file context from the working directory"""
1481 """get a file context from the working directory"""
1479 return workingfilectx(self._repo, path, workingctx=self,
1482 return workingfilectx(self._repo, path, workingctx=self,
1480 filelog=filelog)
1483 filelog=filelog)
1481
1484
1482 def dirty(self, missing=False, merge=True, branch=True):
1485 def dirty(self, missing=False, merge=True, branch=True):
1483 "check whether a working directory is modified"
1486 "check whether a working directory is modified"
1484 # check subrepos first
1487 # check subrepos first
1485 for s in sorted(self.substate):
1488 for s in sorted(self.substate):
1486 if self.sub(s).dirty():
1489 if self.sub(s).dirty():
1487 return True
1490 return True
1488 # check current working dir
1491 # check current working dir
1489 return ((merge and self.p2()) or
1492 return ((merge and self.p2()) or
1490 (branch and self.branch() != self.p1().branch()) or
1493 (branch and self.branch() != self.p1().branch()) or
1491 self.modified() or self.added() or self.removed() or
1494 self.modified() or self.added() or self.removed() or
1492 (missing and self.deleted()))
1495 (missing and self.deleted()))
1493
1496
1494 def add(self, list, prefix=""):
1497 def add(self, list, prefix=""):
1495 join = lambda f: os.path.join(prefix, f)
1498 join = lambda f: os.path.join(prefix, f)
1496 with self._repo.wlock():
1499 with self._repo.wlock():
1497 ui, ds = self._repo.ui, self._repo.dirstate
1500 ui, ds = self._repo.ui, self._repo.dirstate
1498 rejected = []
1501 rejected = []
1499 lstat = self._repo.wvfs.lstat
1502 lstat = self._repo.wvfs.lstat
1500 for f in list:
1503 for f in list:
1501 scmutil.checkportable(ui, join(f))
1504 scmutil.checkportable(ui, join(f))
1502 try:
1505 try:
1503 st = lstat(f)
1506 st = lstat(f)
1504 except OSError:
1507 except OSError:
1505 ui.warn(_("%s does not exist!\n") % join(f))
1508 ui.warn(_("%s does not exist!\n") % join(f))
1506 rejected.append(f)
1509 rejected.append(f)
1507 continue
1510 continue
1508 if st.st_size > 10000000:
1511 if st.st_size > 10000000:
1509 ui.warn(_("%s: up to %d MB of RAM may be required "
1512 ui.warn(_("%s: up to %d MB of RAM may be required "
1510 "to manage this file\n"
1513 "to manage this file\n"
1511 "(use 'hg revert %s' to cancel the "
1514 "(use 'hg revert %s' to cancel the "
1512 "pending addition)\n")
1515 "pending addition)\n")
1513 % (f, 3 * st.st_size // 1000000, join(f)))
1516 % (f, 3 * st.st_size // 1000000, join(f)))
1514 if not (stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode)):
1517 if not (stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode)):
1515 ui.warn(_("%s not added: only files and symlinks "
1518 ui.warn(_("%s not added: only files and symlinks "
1516 "supported currently\n") % join(f))
1519 "supported currently\n") % join(f))
1517 rejected.append(f)
1520 rejected.append(f)
1518 elif ds[f] in 'amn':
1521 elif ds[f] in 'amn':
1519 ui.warn(_("%s already tracked!\n") % join(f))
1522 ui.warn(_("%s already tracked!\n") % join(f))
1520 elif ds[f] == 'r':
1523 elif ds[f] == 'r':
1521 ds.normallookup(f)
1524 ds.normallookup(f)
1522 else:
1525 else:
1523 ds.add(f)
1526 ds.add(f)
1524 return rejected
1527 return rejected
1525
1528
1526 def forget(self, files, prefix=""):
1529 def forget(self, files, prefix=""):
1527 join = lambda f: os.path.join(prefix, f)
1530 join = lambda f: os.path.join(prefix, f)
1528 with self._repo.wlock():
1531 with self._repo.wlock():
1529 rejected = []
1532 rejected = []
1530 for f in files:
1533 for f in files:
1531 if f not in self._repo.dirstate:
1534 if f not in self._repo.dirstate:
1532 self._repo.ui.warn(_("%s not tracked!\n") % join(f))
1535 self._repo.ui.warn(_("%s not tracked!\n") % join(f))
1533 rejected.append(f)
1536 rejected.append(f)
1534 elif self._repo.dirstate[f] != 'a':
1537 elif self._repo.dirstate[f] != 'a':
1535 self._repo.dirstate.remove(f)
1538 self._repo.dirstate.remove(f)
1536 else:
1539 else:
1537 self._repo.dirstate.drop(f)
1540 self._repo.dirstate.drop(f)
1538 return rejected
1541 return rejected
1539
1542
1540 def undelete(self, list):
1543 def undelete(self, list):
1541 pctxs = self.parents()
1544 pctxs = self.parents()
1542 with self._repo.wlock():
1545 with self._repo.wlock():
1543 for f in list:
1546 for f in list:
1544 if self._repo.dirstate[f] != 'r':
1547 if self._repo.dirstate[f] != 'r':
1545 self._repo.ui.warn(_("%s not removed!\n") % f)
1548 self._repo.ui.warn(_("%s not removed!\n") % f)
1546 else:
1549 else:
1547 fctx = f in pctxs[0] and pctxs[0][f] or pctxs[1][f]
1550 fctx = f in pctxs[0] and pctxs[0][f] or pctxs[1][f]
1548 t = fctx.data()
1551 t = fctx.data()
1549 self._repo.wwrite(f, t, fctx.flags())
1552 self._repo.wwrite(f, t, fctx.flags())
1550 self._repo.dirstate.normal(f)
1553 self._repo.dirstate.normal(f)
1551
1554
1552 def copy(self, source, dest):
1555 def copy(self, source, dest):
1553 try:
1556 try:
1554 st = self._repo.wvfs.lstat(dest)
1557 st = self._repo.wvfs.lstat(dest)
1555 except OSError as err:
1558 except OSError as err:
1556 if err.errno != errno.ENOENT:
1559 if err.errno != errno.ENOENT:
1557 raise
1560 raise
1558 self._repo.ui.warn(_("%s does not exist!\n") % dest)
1561 self._repo.ui.warn(_("%s does not exist!\n") % dest)
1559 return
1562 return
1560 if not (stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode)):
1563 if not (stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode)):
1561 self._repo.ui.warn(_("copy failed: %s is not a file or a "
1564 self._repo.ui.warn(_("copy failed: %s is not a file or a "
1562 "symbolic link\n") % dest)
1565 "symbolic link\n") % dest)
1563 else:
1566 else:
1564 with self._repo.wlock():
1567 with self._repo.wlock():
1565 if self._repo.dirstate[dest] in '?':
1568 if self._repo.dirstate[dest] in '?':
1566 self._repo.dirstate.add(dest)
1569 self._repo.dirstate.add(dest)
1567 elif self._repo.dirstate[dest] in 'r':
1570 elif self._repo.dirstate[dest] in 'r':
1568 self._repo.dirstate.normallookup(dest)
1571 self._repo.dirstate.normallookup(dest)
1569 self._repo.dirstate.copy(source, dest)
1572 self._repo.dirstate.copy(source, dest)
1570
1573
1571 def match(self, pats=None, include=None, exclude=None, default='glob',
1574 def match(self, pats=None, include=None, exclude=None, default='glob',
1572 listsubrepos=False, badfn=None):
1575 listsubrepos=False, badfn=None):
1573 if pats is None:
1576 if pats is None:
1574 pats = []
1577 pats = []
1575 r = self._repo
1578 r = self._repo
1576
1579
1577 # Only a case insensitive filesystem needs magic to translate user input
1580 # Only a case insensitive filesystem needs magic to translate user input
1578 # to actual case in the filesystem.
1581 # to actual case in the filesystem.
1579 matcherfunc = matchmod.match
1582 matcherfunc = matchmod.match
1580 if not util.fscasesensitive(r.root):
1583 if not util.fscasesensitive(r.root):
1581 matcherfunc = matchmod.icasefsmatcher
1584 matcherfunc = matchmod.icasefsmatcher
1582 return matcherfunc(r.root, r.getcwd(), pats,
1585 return matcherfunc(r.root, r.getcwd(), pats,
1583 include, exclude, default,
1586 include, exclude, default,
1584 auditor=r.auditor, ctx=self,
1587 auditor=r.auditor, ctx=self,
1585 listsubrepos=listsubrepos, badfn=badfn)
1588 listsubrepos=listsubrepos, badfn=badfn)
1586
1589
1587 def _filtersuspectsymlink(self, files):
1590 def _filtersuspectsymlink(self, files):
1588 if not files or self._repo.dirstate._checklink:
1591 if not files or self._repo.dirstate._checklink:
1589 return files
1592 return files
1590
1593
1591 # Symlink placeholders may get non-symlink-like contents
1594 # Symlink placeholders may get non-symlink-like contents
1592 # via user error or dereferencing by NFS or Samba servers,
1595 # via user error or dereferencing by NFS or Samba servers,
1593 # so we filter out any placeholders that don't look like a
1596 # so we filter out any placeholders that don't look like a
1594 # symlink
1597 # symlink
1595 sane = []
1598 sane = []
1596 for f in files:
1599 for f in files:
1597 if self.flags(f) == 'l':
1600 if self.flags(f) == 'l':
1598 d = self[f].data()
1601 d = self[f].data()
1599 if d == '' or len(d) >= 1024 or '\n' in d or util.binary(d):
1602 if d == '' or len(d) >= 1024 or '\n' in d or util.binary(d):
1600 self._repo.ui.debug('ignoring suspect symlink placeholder'
1603 self._repo.ui.debug('ignoring suspect symlink placeholder'
1601 ' "%s"\n' % f)
1604 ' "%s"\n' % f)
1602 continue
1605 continue
1603 sane.append(f)
1606 sane.append(f)
1604 return sane
1607 return sane
1605
1608
1606 def _checklookup(self, files):
1609 def _checklookup(self, files):
1607 # check for any possibly clean files
1610 # check for any possibly clean files
1608 if not files:
1611 if not files:
1609 return [], []
1612 return [], []
1610
1613
1611 modified = []
1614 modified = []
1612 fixup = []
1615 fixup = []
1613 pctx = self._parents[0]
1616 pctx = self._parents[0]
1614 # do a full compare of any files that might have changed
1617 # do a full compare of any files that might have changed
1615 for f in sorted(files):
1618 for f in sorted(files):
1616 if (f not in pctx or self.flags(f) != pctx.flags(f)
1619 if (f not in pctx or self.flags(f) != pctx.flags(f)
1617 or pctx[f].cmp(self[f])):
1620 or pctx[f].cmp(self[f])):
1618 modified.append(f)
1621 modified.append(f)
1619 else:
1622 else:
1620 fixup.append(f)
1623 fixup.append(f)
1621
1624
1622 # update dirstate for files that are actually clean
1625 # update dirstate for files that are actually clean
1623 if fixup:
1626 if fixup:
1624 try:
1627 try:
1625 # updating the dirstate is optional
1628 # updating the dirstate is optional
1626 # so we don't wait on the lock
1629 # so we don't wait on the lock
1627 # wlock can invalidate the dirstate, so cache normal _after_
1630 # wlock can invalidate the dirstate, so cache normal _after_
1628 # taking the lock
1631 # taking the lock
1629 with self._repo.wlock(False):
1632 with self._repo.wlock(False):
1630 normal = self._repo.dirstate.normal
1633 normal = self._repo.dirstate.normal
1631 for f in fixup:
1634 for f in fixup:
1632 normal(f)
1635 normal(f)
1633 # write changes out explicitly, because nesting
1636 # write changes out explicitly, because nesting
1634 # wlock at runtime may prevent 'wlock.release()'
1637 # wlock at runtime may prevent 'wlock.release()'
1635 # after this block from doing so for subsequent
1638 # after this block from doing so for subsequent
1636 # changing files
1639 # changing files
1637 self._repo.dirstate.write(self._repo.currenttransaction())
1640 self._repo.dirstate.write(self._repo.currenttransaction())
1638 except error.LockError:
1641 except error.LockError:
1639 pass
1642 pass
1640 return modified, fixup
1643 return modified, fixup
1641
1644
1642 def _dirstatestatus(self, match=None, ignored=False, clean=False,
1645 def _dirstatestatus(self, match=None, ignored=False, clean=False,
1643 unknown=False):
1646 unknown=False):
1644 '''Gets the status from the dirstate -- internal use only.'''
1647 '''Gets the status from the dirstate -- internal use only.'''
1645 listignored, listclean, listunknown = ignored, clean, unknown
1648 listignored, listclean, listunknown = ignored, clean, unknown
1646 match = match or matchmod.always(self._repo.root, self._repo.getcwd())
1649 match = match or matchmod.always(self._repo.root, self._repo.getcwd())
1647 subrepos = []
1650 subrepos = []
1648 if '.hgsub' in self:
1651 if '.hgsub' in self:
1649 subrepos = sorted(self.substate)
1652 subrepos = sorted(self.substate)
1650 cmp, s = self._repo.dirstate.status(match, subrepos, listignored,
1653 cmp, s = self._repo.dirstate.status(match, subrepos, listignored,
1651 listclean, listunknown)
1654 listclean, listunknown)
1652
1655
1653 # check for any possibly clean files
1656 # check for any possibly clean files
1654 if cmp:
1657 if cmp:
1655 modified2, fixup = self._checklookup(cmp)
1658 modified2, fixup = self._checklookup(cmp)
1656 s.modified.extend(modified2)
1659 s.modified.extend(modified2)
1657
1660
1658 # update dirstate for files that are actually clean
1661 # update dirstate for files that are actually clean
1659 if fixup and listclean:
1662 if fixup and listclean:
1660 s.clean.extend(fixup)
1663 s.clean.extend(fixup)
1661
1664
1662 if match.always():
1665 if match.always():
1663 # cache for performance
1666 # cache for performance
1664 if s.unknown or s.ignored or s.clean:
1667 if s.unknown or s.ignored or s.clean:
1665 # "_status" is cached with list*=False in the normal route
1668 # "_status" is cached with list*=False in the normal route
1666 self._status = scmutil.status(s.modified, s.added, s.removed,
1669 self._status = scmutil.status(s.modified, s.added, s.removed,
1667 s.deleted, [], [], [])
1670 s.deleted, [], [], [])
1668 else:
1671 else:
1669 self._status = s
1672 self._status = s
1670
1673
1671 return s
1674 return s
1672
1675
1673 @propertycache
1676 @propertycache
1674 def _manifest(self):
1677 def _manifest(self):
1675 """generate a manifest corresponding to the values in self._status
1678 """generate a manifest corresponding to the values in self._status
1676
1679
1677 This reuse the file nodeid from parent, but we use special node
1680 This reuse the file nodeid from parent, but we use special node
1678 identifiers for added and modified files. This is used by manifests
1681 identifiers for added and modified files. This is used by manifests
1679 merge to see that files are different and by update logic to avoid
1682 merge to see that files are different and by update logic to avoid
1680 deleting newly added files.
1683 deleting newly added files.
1681 """
1684 """
1682 return self._buildstatusmanifest(self._status)
1685 return self._buildstatusmanifest(self._status)
1683
1686
1684 def _buildstatusmanifest(self, status):
1687 def _buildstatusmanifest(self, status):
1685 """Builds a manifest that includes the given status results."""
1688 """Builds a manifest that includes the given status results."""
1686 parents = self.parents()
1689 parents = self.parents()
1687
1690
1688 man = parents[0].manifest().copy()
1691 man = parents[0].manifest().copy()
1689
1692
1690 ff = self._flagfunc
1693 ff = self._flagfunc
1691 for i, l in ((addednodeid, status.added),
1694 for i, l in ((addednodeid, status.added),
1692 (modifiednodeid, status.modified)):
1695 (modifiednodeid, status.modified)):
1693 for f in l:
1696 for f in l:
1694 man[f] = i
1697 man[f] = i
1695 try:
1698 try:
1696 man.setflag(f, ff(f))
1699 man.setflag(f, ff(f))
1697 except OSError:
1700 except OSError:
1698 pass
1701 pass
1699
1702
1700 for f in status.deleted + status.removed:
1703 for f in status.deleted + status.removed:
1701 if f in man:
1704 if f in man:
1702 del man[f]
1705 del man[f]
1703
1706
1704 return man
1707 return man
1705
1708
1706 def _buildstatus(self, other, s, match, listignored, listclean,
1709 def _buildstatus(self, other, s, match, listignored, listclean,
1707 listunknown):
1710 listunknown):
1708 """build a status with respect to another context
1711 """build a status with respect to another context
1709
1712
1710 This includes logic for maintaining the fast path of status when
1713 This includes logic for maintaining the fast path of status when
1711 comparing the working directory against its parent, which is to skip
1714 comparing the working directory against its parent, which is to skip
1712 building a new manifest if self (working directory) is not comparing
1715 building a new manifest if self (working directory) is not comparing
1713 against its parent (repo['.']).
1716 against its parent (repo['.']).
1714 """
1717 """
1715 s = self._dirstatestatus(match, listignored, listclean, listunknown)
1718 s = self._dirstatestatus(match, listignored, listclean, listunknown)
1716 # Filter out symlinks that, in the case of FAT32 and NTFS filesystems,
1719 # Filter out symlinks that, in the case of FAT32 and NTFS filesystems,
1717 # might have accidentally ended up with the entire contents of the file
1720 # might have accidentally ended up with the entire contents of the file
1718 # they are supposed to be linking to.
1721 # they are supposed to be linking to.
1719 s.modified[:] = self._filtersuspectsymlink(s.modified)
1722 s.modified[:] = self._filtersuspectsymlink(s.modified)
1720 if other != self._repo['.']:
1723 if other != self._repo['.']:
1721 s = super(workingctx, self)._buildstatus(other, s, match,
1724 s = super(workingctx, self)._buildstatus(other, s, match,
1722 listignored, listclean,
1725 listignored, listclean,
1723 listunknown)
1726 listunknown)
1724 return s
1727 return s
1725
1728
1726 def _matchstatus(self, other, match):
1729 def _matchstatus(self, other, match):
1727 """override the match method with a filter for directory patterns
1730 """override the match method with a filter for directory patterns
1728
1731
1729 We use inheritance to customize the match.bad method only in cases of
1732 We use inheritance to customize the match.bad method only in cases of
1730 workingctx since it belongs only to the working directory when
1733 workingctx since it belongs only to the working directory when
1731 comparing against the parent changeset.
1734 comparing against the parent changeset.
1732
1735
1733 If we aren't comparing against the working directory's parent, then we
1736 If we aren't comparing against the working directory's parent, then we
1734 just use the default match object sent to us.
1737 just use the default match object sent to us.
1735 """
1738 """
1736 superself = super(workingctx, self)
1739 superself = super(workingctx, self)
1737 match = superself._matchstatus(other, match)
1740 match = superself._matchstatus(other, match)
1738 if other != self._repo['.']:
1741 if other != self._repo['.']:
1739 def bad(f, msg):
1742 def bad(f, msg):
1740 # 'f' may be a directory pattern from 'match.files()',
1743 # 'f' may be a directory pattern from 'match.files()',
1741 # so 'f not in ctx1' is not enough
1744 # so 'f not in ctx1' is not enough
1742 if f not in other and not other.hasdir(f):
1745 if f not in other and not other.hasdir(f):
1743 self._repo.ui.warn('%s: %s\n' %
1746 self._repo.ui.warn('%s: %s\n' %
1744 (self._repo.dirstate.pathto(f), msg))
1747 (self._repo.dirstate.pathto(f), msg))
1745 match.bad = bad
1748 match.bad = bad
1746 return match
1749 return match
1747
1750
1748 class committablefilectx(basefilectx):
1751 class committablefilectx(basefilectx):
1749 """A committablefilectx provides common functionality for a file context
1752 """A committablefilectx provides common functionality for a file context
1750 that wants the ability to commit, e.g. workingfilectx or memfilectx."""
1753 that wants the ability to commit, e.g. workingfilectx or memfilectx."""
1751 def __init__(self, repo, path, filelog=None, ctx=None):
1754 def __init__(self, repo, path, filelog=None, ctx=None):
1752 self._repo = repo
1755 self._repo = repo
1753 self._path = path
1756 self._path = path
1754 self._changeid = None
1757 self._changeid = None
1755 self._filerev = self._filenode = None
1758 self._filerev = self._filenode = None
1756
1759
1757 if filelog is not None:
1760 if filelog is not None:
1758 self._filelog = filelog
1761 self._filelog = filelog
1759 if ctx:
1762 if ctx:
1760 self._changectx = ctx
1763 self._changectx = ctx
1761
1764
1762 def __nonzero__(self):
1765 def __nonzero__(self):
1763 return True
1766 return True
1764
1767
1765 __bool__ = __nonzero__
1768 __bool__ = __nonzero__
1766
1769
1767 def linkrev(self):
1770 def linkrev(self):
1768 # linked to self._changectx no matter if file is modified or not
1771 # linked to self._changectx no matter if file is modified or not
1769 return self.rev()
1772 return self.rev()
1770
1773
1771 def parents(self):
1774 def parents(self):
1772 '''return parent filectxs, following copies if necessary'''
1775 '''return parent filectxs, following copies if necessary'''
1773 def filenode(ctx, path):
1776 def filenode(ctx, path):
1774 return ctx._manifest.get(path, nullid)
1777 return ctx._manifest.get(path, nullid)
1775
1778
1776 path = self._path
1779 path = self._path
1777 fl = self._filelog
1780 fl = self._filelog
1778 pcl = self._changectx._parents
1781 pcl = self._changectx._parents
1779 renamed = self.renamed()
1782 renamed = self.renamed()
1780
1783
1781 if renamed:
1784 if renamed:
1782 pl = [renamed + (None,)]
1785 pl = [renamed + (None,)]
1783 else:
1786 else:
1784 pl = [(path, filenode(pcl[0], path), fl)]
1787 pl = [(path, filenode(pcl[0], path), fl)]
1785
1788
1786 for pc in pcl[1:]:
1789 for pc in pcl[1:]:
1787 pl.append((path, filenode(pc, path), fl))
1790 pl.append((path, filenode(pc, path), fl))
1788
1791
1789 return [self._parentfilectx(p, fileid=n, filelog=l)
1792 return [self._parentfilectx(p, fileid=n, filelog=l)
1790 for p, n, l in pl if n != nullid]
1793 for p, n, l in pl if n != nullid]
1791
1794
1792 def children(self):
1795 def children(self):
1793 return []
1796 return []
1794
1797
1795 class workingfilectx(committablefilectx):
1798 class workingfilectx(committablefilectx):
1796 """A workingfilectx object makes access to data related to a particular
1799 """A workingfilectx object makes access to data related to a particular
1797 file in the working directory convenient."""
1800 file in the working directory convenient."""
1798 def __init__(self, repo, path, filelog=None, workingctx=None):
1801 def __init__(self, repo, path, filelog=None, workingctx=None):
1799 super(workingfilectx, self).__init__(repo, path, filelog, workingctx)
1802 super(workingfilectx, self).__init__(repo, path, filelog, workingctx)
1800
1803
1801 @propertycache
1804 @propertycache
1802 def _changectx(self):
1805 def _changectx(self):
1803 return workingctx(self._repo)
1806 return workingctx(self._repo)
1804
1807
1805 def data(self):
1808 def data(self):
1806 return self._repo.wread(self._path)
1809 return self._repo.wread(self._path)
1807 def renamed(self):
1810 def renamed(self):
1808 rp = self._repo.dirstate.copied(self._path)
1811 rp = self._repo.dirstate.copied(self._path)
1809 if not rp:
1812 if not rp:
1810 return None
1813 return None
1811 return rp, self._changectx._parents[0]._manifest.get(rp, nullid)
1814 return rp, self._changectx._parents[0]._manifest.get(rp, nullid)
1812
1815
1813 def size(self):
1816 def size(self):
1814 return self._repo.wvfs.lstat(self._path).st_size
1817 return self._repo.wvfs.lstat(self._path).st_size
1815 def date(self):
1818 def date(self):
1816 t, tz = self._changectx.date()
1819 t, tz = self._changectx.date()
1817 try:
1820 try:
1818 return (self._repo.wvfs.lstat(self._path).st_mtime, tz)
1821 return (self._repo.wvfs.lstat(self._path).st_mtime, tz)
1819 except OSError as err:
1822 except OSError as err:
1820 if err.errno != errno.ENOENT:
1823 if err.errno != errno.ENOENT:
1821 raise
1824 raise
1822 return (t, tz)
1825 return (t, tz)
1823
1826
1824 def cmp(self, fctx):
1827 def cmp(self, fctx):
1825 """compare with other file context
1828 """compare with other file context
1826
1829
1827 returns True if different than fctx.
1830 returns True if different than fctx.
1828 """
1831 """
1829 # fctx should be a filectx (not a workingfilectx)
1832 # fctx should be a filectx (not a workingfilectx)
1830 # invert comparison to reuse the same code path
1833 # invert comparison to reuse the same code path
1831 return fctx.cmp(self)
1834 return fctx.cmp(self)
1832
1835
1833 def remove(self, ignoremissing=False):
1836 def remove(self, ignoremissing=False):
1834 """wraps unlink for a repo's working directory"""
1837 """wraps unlink for a repo's working directory"""
1835 self._repo.wvfs.unlinkpath(self._path, ignoremissing=ignoremissing)
1838 self._repo.wvfs.unlinkpath(self._path, ignoremissing=ignoremissing)
1836
1839
1837 def write(self, data, flags):
1840 def write(self, data, flags):
1838 """wraps repo.wwrite"""
1841 """wraps repo.wwrite"""
1839 self._repo.wwrite(self._path, data, flags)
1842 self._repo.wwrite(self._path, data, flags)
1840
1843
1841 class workingcommitctx(workingctx):
1844 class workingcommitctx(workingctx):
1842 """A workingcommitctx object makes access to data related to
1845 """A workingcommitctx object makes access to data related to
1843 the revision being committed convenient.
1846 the revision being committed convenient.
1844
1847
1845 This hides changes in the working directory, if they aren't
1848 This hides changes in the working directory, if they aren't
1846 committed in this context.
1849 committed in this context.
1847 """
1850 """
1848 def __init__(self, repo, changes,
1851 def __init__(self, repo, changes,
1849 text="", user=None, date=None, extra=None):
1852 text="", user=None, date=None, extra=None):
1850 super(workingctx, self).__init__(repo, text, user, date, extra,
1853 super(workingctx, self).__init__(repo, text, user, date, extra,
1851 changes)
1854 changes)
1852
1855
1853 def _dirstatestatus(self, match=None, ignored=False, clean=False,
1856 def _dirstatestatus(self, match=None, ignored=False, clean=False,
1854 unknown=False):
1857 unknown=False):
1855 """Return matched files only in ``self._status``
1858 """Return matched files only in ``self._status``
1856
1859
1857 Uncommitted files appear "clean" via this context, even if
1860 Uncommitted files appear "clean" via this context, even if
1858 they aren't actually so in the working directory.
1861 they aren't actually so in the working directory.
1859 """
1862 """
1860 match = match or matchmod.always(self._repo.root, self._repo.getcwd())
1863 match = match or matchmod.always(self._repo.root, self._repo.getcwd())
1861 if clean:
1864 if clean:
1862 clean = [f for f in self._manifest if f not in self._changedset]
1865 clean = [f for f in self._manifest if f not in self._changedset]
1863 else:
1866 else:
1864 clean = []
1867 clean = []
1865 return scmutil.status([f for f in self._status.modified if match(f)],
1868 return scmutil.status([f for f in self._status.modified if match(f)],
1866 [f for f in self._status.added if match(f)],
1869 [f for f in self._status.added if match(f)],
1867 [f for f in self._status.removed if match(f)],
1870 [f for f in self._status.removed if match(f)],
1868 [], [], [], clean)
1871 [], [], [], clean)
1869
1872
1870 @propertycache
1873 @propertycache
1871 def _changedset(self):
1874 def _changedset(self):
1872 """Return the set of files changed in this context
1875 """Return the set of files changed in this context
1873 """
1876 """
1874 changed = set(self._status.modified)
1877 changed = set(self._status.modified)
1875 changed.update(self._status.added)
1878 changed.update(self._status.added)
1876 changed.update(self._status.removed)
1879 changed.update(self._status.removed)
1877 return changed
1880 return changed
1878
1881
1879 def makecachingfilectxfn(func):
1882 def makecachingfilectxfn(func):
1880 """Create a filectxfn that caches based on the path.
1883 """Create a filectxfn that caches based on the path.
1881
1884
1882 We can't use util.cachefunc because it uses all arguments as the cache
1885 We can't use util.cachefunc because it uses all arguments as the cache
1883 key and this creates a cycle since the arguments include the repo and
1886 key and this creates a cycle since the arguments include the repo and
1884 memctx.
1887 memctx.
1885 """
1888 """
1886 cache = {}
1889 cache = {}
1887
1890
1888 def getfilectx(repo, memctx, path):
1891 def getfilectx(repo, memctx, path):
1889 if path not in cache:
1892 if path not in cache:
1890 cache[path] = func(repo, memctx, path)
1893 cache[path] = func(repo, memctx, path)
1891 return cache[path]
1894 return cache[path]
1892
1895
1893 return getfilectx
1896 return getfilectx
1894
1897
1895 class memctx(committablectx):
1898 class memctx(committablectx):
1896 """Use memctx to perform in-memory commits via localrepo.commitctx().
1899 """Use memctx to perform in-memory commits via localrepo.commitctx().
1897
1900
1898 Revision information is supplied at initialization time while
1901 Revision information is supplied at initialization time while
1899 related files data and is made available through a callback
1902 related files data and is made available through a callback
1900 mechanism. 'repo' is the current localrepo, 'parents' is a
1903 mechanism. 'repo' is the current localrepo, 'parents' is a
1901 sequence of two parent revisions identifiers (pass None for every
1904 sequence of two parent revisions identifiers (pass None for every
1902 missing parent), 'text' is the commit message and 'files' lists
1905 missing parent), 'text' is the commit message and 'files' lists
1903 names of files touched by the revision (normalized and relative to
1906 names of files touched by the revision (normalized and relative to
1904 repository root).
1907 repository root).
1905
1908
1906 filectxfn(repo, memctx, path) is a callable receiving the
1909 filectxfn(repo, memctx, path) is a callable receiving the
1907 repository, the current memctx object and the normalized path of
1910 repository, the current memctx object and the normalized path of
1908 requested file, relative to repository root. It is fired by the
1911 requested file, relative to repository root. It is fired by the
1909 commit function for every file in 'files', but calls order is
1912 commit function for every file in 'files', but calls order is
1910 undefined. If the file is available in the revision being
1913 undefined. If the file is available in the revision being
1911 committed (updated or added), filectxfn returns a memfilectx
1914 committed (updated or added), filectxfn returns a memfilectx
1912 object. If the file was removed, filectxfn return None for recent
1915 object. If the file was removed, filectxfn return None for recent
1913 Mercurial. Moved files are represented by marking the source file
1916 Mercurial. Moved files are represented by marking the source file
1914 removed and the new file added with copy information (see
1917 removed and the new file added with copy information (see
1915 memfilectx).
1918 memfilectx).
1916
1919
1917 user receives the committer name and defaults to current
1920 user receives the committer name and defaults to current
1918 repository username, date is the commit date in any format
1921 repository username, date is the commit date in any format
1919 supported by util.parsedate() and defaults to current date, extra
1922 supported by util.parsedate() and defaults to current date, extra
1920 is a dictionary of metadata or is left empty.
1923 is a dictionary of metadata or is left empty.
1921 """
1924 """
1922
1925
1923 # Mercurial <= 3.1 expects the filectxfn to raise IOError for missing files.
1926 # Mercurial <= 3.1 expects the filectxfn to raise IOError for missing files.
1924 # Extensions that need to retain compatibility across Mercurial 3.1 can use
1927 # Extensions that need to retain compatibility across Mercurial 3.1 can use
1925 # this field to determine what to do in filectxfn.
1928 # this field to determine what to do in filectxfn.
1926 _returnnoneformissingfiles = True
1929 _returnnoneformissingfiles = True
1927
1930
1928 def __init__(self, repo, parents, text, files, filectxfn, user=None,
1931 def __init__(self, repo, parents, text, files, filectxfn, user=None,
1929 date=None, extra=None, editor=False):
1932 date=None, extra=None, editor=False):
1930 super(memctx, self).__init__(repo, text, user, date, extra)
1933 super(memctx, self).__init__(repo, text, user, date, extra)
1931 self._rev = None
1934 self._rev = None
1932 self._node = None
1935 self._node = None
1933 parents = [(p or nullid) for p in parents]
1936 parents = [(p or nullid) for p in parents]
1934 p1, p2 = parents
1937 p1, p2 = parents
1935 self._parents = [changectx(self._repo, p) for p in (p1, p2)]
1938 self._parents = [changectx(self._repo, p) for p in (p1, p2)]
1936 files = sorted(set(files))
1939 files = sorted(set(files))
1937 self._files = files
1940 self._files = files
1938 self.substate = {}
1941 self.substate = {}
1939
1942
1940 # if store is not callable, wrap it in a function
1943 # if store is not callable, wrap it in a function
1941 if not callable(filectxfn):
1944 if not callable(filectxfn):
1942 def getfilectx(repo, memctx, path):
1945 def getfilectx(repo, memctx, path):
1943 fctx = filectxfn[path]
1946 fctx = filectxfn[path]
1944 # this is weird but apparently we only keep track of one parent
1947 # this is weird but apparently we only keep track of one parent
1945 # (why not only store that instead of a tuple?)
1948 # (why not only store that instead of a tuple?)
1946 copied = fctx.renamed()
1949 copied = fctx.renamed()
1947 if copied:
1950 if copied:
1948 copied = copied[0]
1951 copied = copied[0]
1949 return memfilectx(repo, path, fctx.data(),
1952 return memfilectx(repo, path, fctx.data(),
1950 islink=fctx.islink(), isexec=fctx.isexec(),
1953 islink=fctx.islink(), isexec=fctx.isexec(),
1951 copied=copied, memctx=memctx)
1954 copied=copied, memctx=memctx)
1952 self._filectxfn = getfilectx
1955 self._filectxfn = getfilectx
1953 else:
1956 else:
1954 # memoizing increases performance for e.g. vcs convert scenarios.
1957 # memoizing increases performance for e.g. vcs convert scenarios.
1955 self._filectxfn = makecachingfilectxfn(filectxfn)
1958 self._filectxfn = makecachingfilectxfn(filectxfn)
1956
1959
1957 if extra:
1960 if extra:
1958 self._extra = extra.copy()
1961 self._extra = extra.copy()
1959 else:
1962 else:
1960 self._extra = {}
1963 self._extra = {}
1961
1964
1962 if self._extra.get('branch', '') == '':
1965 if self._extra.get('branch', '') == '':
1963 self._extra['branch'] = 'default'
1966 self._extra['branch'] = 'default'
1964
1967
1965 if editor:
1968 if editor:
1966 self._text = editor(self._repo, self, [])
1969 self._text = editor(self._repo, self, [])
1967 self._repo.savecommitmessage(self._text)
1970 self._repo.savecommitmessage(self._text)
1968
1971
1969 def filectx(self, path, filelog=None):
1972 def filectx(self, path, filelog=None):
1970 """get a file context from the working directory
1973 """get a file context from the working directory
1971
1974
1972 Returns None if file doesn't exist and should be removed."""
1975 Returns None if file doesn't exist and should be removed."""
1973 return self._filectxfn(self._repo, self, path)
1976 return self._filectxfn(self._repo, self, path)
1974
1977
1975 def commit(self):
1978 def commit(self):
1976 """commit context to the repo"""
1979 """commit context to the repo"""
1977 return self._repo.commitctx(self)
1980 return self._repo.commitctx(self)
1978
1981
1979 @propertycache
1982 @propertycache
1980 def _manifest(self):
1983 def _manifest(self):
1981 """generate a manifest based on the return values of filectxfn"""
1984 """generate a manifest based on the return values of filectxfn"""
1982
1985
1983 # keep this simple for now; just worry about p1
1986 # keep this simple for now; just worry about p1
1984 pctx = self._parents[0]
1987 pctx = self._parents[0]
1985 man = pctx.manifest().copy()
1988 man = pctx.manifest().copy()
1986
1989
1987 for f in self._status.modified:
1990 for f in self._status.modified:
1988 p1node = nullid
1991 p1node = nullid
1989 p2node = nullid
1992 p2node = nullid
1990 p = pctx[f].parents() # if file isn't in pctx, check p2?
1993 p = pctx[f].parents() # if file isn't in pctx, check p2?
1991 if len(p) > 0:
1994 if len(p) > 0:
1992 p1node = p[0].filenode()
1995 p1node = p[0].filenode()
1993 if len(p) > 1:
1996 if len(p) > 1:
1994 p2node = p[1].filenode()
1997 p2node = p[1].filenode()
1995 man[f] = revlog.hash(self[f].data(), p1node, p2node)
1998 man[f] = revlog.hash(self[f].data(), p1node, p2node)
1996
1999
1997 for f in self._status.added:
2000 for f in self._status.added:
1998 man[f] = revlog.hash(self[f].data(), nullid, nullid)
2001 man[f] = revlog.hash(self[f].data(), nullid, nullid)
1999
2002
2000 for f in self._status.removed:
2003 for f in self._status.removed:
2001 if f in man:
2004 if f in man:
2002 del man[f]
2005 del man[f]
2003
2006
2004 return man
2007 return man
2005
2008
2006 @propertycache
2009 @propertycache
2007 def _status(self):
2010 def _status(self):
2008 """Calculate exact status from ``files`` specified at construction
2011 """Calculate exact status from ``files`` specified at construction
2009 """
2012 """
2010 man1 = self.p1().manifest()
2013 man1 = self.p1().manifest()
2011 p2 = self._parents[1]
2014 p2 = self._parents[1]
2012 # "1 < len(self._parents)" can't be used for checking
2015 # "1 < len(self._parents)" can't be used for checking
2013 # existence of the 2nd parent, because "memctx._parents" is
2016 # existence of the 2nd parent, because "memctx._parents" is
2014 # explicitly initialized by the list, of which length is 2.
2017 # explicitly initialized by the list, of which length is 2.
2015 if p2.node() != nullid:
2018 if p2.node() != nullid:
2016 man2 = p2.manifest()
2019 man2 = p2.manifest()
2017 managing = lambda f: f in man1 or f in man2
2020 managing = lambda f: f in man1 or f in man2
2018 else:
2021 else:
2019 managing = lambda f: f in man1
2022 managing = lambda f: f in man1
2020
2023
2021 modified, added, removed = [], [], []
2024 modified, added, removed = [], [], []
2022 for f in self._files:
2025 for f in self._files:
2023 if not managing(f):
2026 if not managing(f):
2024 added.append(f)
2027 added.append(f)
2025 elif self[f]:
2028 elif self[f]:
2026 modified.append(f)
2029 modified.append(f)
2027 else:
2030 else:
2028 removed.append(f)
2031 removed.append(f)
2029
2032
2030 return scmutil.status(modified, added, removed, [], [], [], [])
2033 return scmutil.status(modified, added, removed, [], [], [], [])
2031
2034
2032 class memfilectx(committablefilectx):
2035 class memfilectx(committablefilectx):
2033 """memfilectx represents an in-memory file to commit.
2036 """memfilectx represents an in-memory file to commit.
2034
2037
2035 See memctx and committablefilectx for more details.
2038 See memctx and committablefilectx for more details.
2036 """
2039 """
2037 def __init__(self, repo, path, data, islink=False,
2040 def __init__(self, repo, path, data, islink=False,
2038 isexec=False, copied=None, memctx=None):
2041 isexec=False, copied=None, memctx=None):
2039 """
2042 """
2040 path is the normalized file path relative to repository root.
2043 path is the normalized file path relative to repository root.
2041 data is the file content as a string.
2044 data is the file content as a string.
2042 islink is True if the file is a symbolic link.
2045 islink is True if the file is a symbolic link.
2043 isexec is True if the file is executable.
2046 isexec is True if the file is executable.
2044 copied is the source file path if current file was copied in the
2047 copied is the source file path if current file was copied in the
2045 revision being committed, or None."""
2048 revision being committed, or None."""
2046 super(memfilectx, self).__init__(repo, path, None, memctx)
2049 super(memfilectx, self).__init__(repo, path, None, memctx)
2047 self._data = data
2050 self._data = data
2048 self._flags = (islink and 'l' or '') + (isexec and 'x' or '')
2051 self._flags = (islink and 'l' or '') + (isexec and 'x' or '')
2049 self._copied = None
2052 self._copied = None
2050 if copied:
2053 if copied:
2051 self._copied = (copied, nullid)
2054 self._copied = (copied, nullid)
2052
2055
2053 def data(self):
2056 def data(self):
2054 return self._data
2057 return self._data
2055 def size(self):
2058 def size(self):
2056 return len(self.data())
2059 return len(self.data())
2057 def flags(self):
2060 def flags(self):
2058 return self._flags
2061 return self._flags
2059 def renamed(self):
2062 def renamed(self):
2060 return self._copied
2063 return self._copied
2061
2064
2062 def remove(self, ignoremissing=False):
2065 def remove(self, ignoremissing=False):
2063 """wraps unlink for a repo's working directory"""
2066 """wraps unlink for a repo's working directory"""
2064 # need to figure out what to do here
2067 # need to figure out what to do here
2065 del self._changectx[self._path]
2068 del self._changectx[self._path]
2066
2069
2067 def write(self, data, flags):
2070 def write(self, data, flags):
2068 """wraps repo.wwrite"""
2071 """wraps repo.wwrite"""
2069 self._data = data
2072 self._data = data
2070
2073
2071 class metadataonlyctx(committablectx):
2074 class metadataonlyctx(committablectx):
2072 """Like memctx but it's reusing the manifest of different commit.
2075 """Like memctx but it's reusing the manifest of different commit.
2073 Intended to be used by lightweight operations that are creating
2076 Intended to be used by lightweight operations that are creating
2074 metadata-only changes.
2077 metadata-only changes.
2075
2078
2076 Revision information is supplied at initialization time. 'repo' is the
2079 Revision information is supplied at initialization time. 'repo' is the
2077 current localrepo, 'ctx' is original revision which manifest we're reuisng
2080 current localrepo, 'ctx' is original revision which manifest we're reuisng
2078 'parents' is a sequence of two parent revisions identifiers (pass None for
2081 'parents' is a sequence of two parent revisions identifiers (pass None for
2079 every missing parent), 'text' is the commit.
2082 every missing parent), 'text' is the commit.
2080
2083
2081 user receives the committer name and defaults to current repository
2084 user receives the committer name and defaults to current repository
2082 username, date is the commit date in any format supported by
2085 username, date is the commit date in any format supported by
2083 util.parsedate() and defaults to current date, extra is a dictionary of
2086 util.parsedate() and defaults to current date, extra is a dictionary of
2084 metadata or is left empty.
2087 metadata or is left empty.
2085 """
2088 """
2086 def __new__(cls, repo, originalctx, *args, **kwargs):
2089 def __new__(cls, repo, originalctx, *args, **kwargs):
2087 return super(metadataonlyctx, cls).__new__(cls, repo)
2090 return super(metadataonlyctx, cls).__new__(cls, repo)
2088
2091
2089 def __init__(self, repo, originalctx, parents, text, user=None, date=None,
2092 def __init__(self, repo, originalctx, parents, text, user=None, date=None,
2090 extra=None, editor=False):
2093 extra=None, editor=False):
2091 super(metadataonlyctx, self).__init__(repo, text, user, date, extra)
2094 super(metadataonlyctx, self).__init__(repo, text, user, date, extra)
2092 self._rev = None
2095 self._rev = None
2093 self._node = None
2096 self._node = None
2094 self._originalctx = originalctx
2097 self._originalctx = originalctx
2095 self._manifestnode = originalctx.manifestnode()
2098 self._manifestnode = originalctx.manifestnode()
2096 parents = [(p or nullid) for p in parents]
2099 parents = [(p or nullid) for p in parents]
2097 p1, p2 = self._parents = [changectx(self._repo, p) for p in parents]
2100 p1, p2 = self._parents = [changectx(self._repo, p) for p in parents]
2098
2101
2099 # sanity check to ensure that the reused manifest parents are
2102 # sanity check to ensure that the reused manifest parents are
2100 # manifests of our commit parents
2103 # manifests of our commit parents
2101 mp1, mp2 = self.manifestctx().parents
2104 mp1, mp2 = self.manifestctx().parents
2102 if p1 != nullid and p1.manifestnode() != mp1:
2105 if p1 != nullid and p1.manifestnode() != mp1:
2103 raise RuntimeError('can\'t reuse the manifest: '
2106 raise RuntimeError('can\'t reuse the manifest: '
2104 'its p1 doesn\'t match the new ctx p1')
2107 'its p1 doesn\'t match the new ctx p1')
2105 if p2 != nullid and p2.manifestnode() != mp2:
2108 if p2 != nullid and p2.manifestnode() != mp2:
2106 raise RuntimeError('can\'t reuse the manifest: '
2109 raise RuntimeError('can\'t reuse the manifest: '
2107 'its p2 doesn\'t match the new ctx p2')
2110 'its p2 doesn\'t match the new ctx p2')
2108
2111
2109 self._files = originalctx.files()
2112 self._files = originalctx.files()
2110 self.substate = {}
2113 self.substate = {}
2111
2114
2112 if extra:
2115 if extra:
2113 self._extra = extra.copy()
2116 self._extra = extra.copy()
2114 else:
2117 else:
2115 self._extra = {}
2118 self._extra = {}
2116
2119
2117 if self._extra.get('branch', '') == '':
2120 if self._extra.get('branch', '') == '':
2118 self._extra['branch'] = 'default'
2121 self._extra['branch'] = 'default'
2119
2122
2120 if editor:
2123 if editor:
2121 self._text = editor(self._repo, self, [])
2124 self._text = editor(self._repo, self, [])
2122 self._repo.savecommitmessage(self._text)
2125 self._repo.savecommitmessage(self._text)
2123
2126
2124 def manifestnode(self):
2127 def manifestnode(self):
2125 return self._manifestnode
2128 return self._manifestnode
2126
2129
2127 @propertycache
2130 @propertycache
2128 def _manifestctx(self):
2131 def _manifestctx(self):
2129 return self._repo.manifestlog[self._manifestnode]
2132 return self._repo.manifestlog[self._manifestnode]
2130
2133
2131 def filectx(self, path, filelog=None):
2134 def filectx(self, path, filelog=None):
2132 return self._originalctx.filectx(path, filelog=filelog)
2135 return self._originalctx.filectx(path, filelog=filelog)
2133
2136
2134 def commit(self):
2137 def commit(self):
2135 """commit context to the repo"""
2138 """commit context to the repo"""
2136 return self._repo.commitctx(self)
2139 return self._repo.commitctx(self)
2137
2140
2138 @property
2141 @property
2139 def _manifest(self):
2142 def _manifest(self):
2140 return self._originalctx.manifest()
2143 return self._originalctx.manifest()
2141
2144
2142 @propertycache
2145 @propertycache
2143 def _status(self):
2146 def _status(self):
2144 """Calculate exact status from ``files`` specified in the ``origctx``
2147 """Calculate exact status from ``files`` specified in the ``origctx``
2145 and parents manifests.
2148 and parents manifests.
2146 """
2149 """
2147 man1 = self.p1().manifest()
2150 man1 = self.p1().manifest()
2148 p2 = self._parents[1]
2151 p2 = self._parents[1]
2149 # "1 < len(self._parents)" can't be used for checking
2152 # "1 < len(self._parents)" can't be used for checking
2150 # existence of the 2nd parent, because "metadataonlyctx._parents" is
2153 # existence of the 2nd parent, because "metadataonlyctx._parents" is
2151 # explicitly initialized by the list, of which length is 2.
2154 # explicitly initialized by the list, of which length is 2.
2152 if p2.node() != nullid:
2155 if p2.node() != nullid:
2153 man2 = p2.manifest()
2156 man2 = p2.manifest()
2154 managing = lambda f: f in man1 or f in man2
2157 managing = lambda f: f in man1 or f in man2
2155 else:
2158 else:
2156 managing = lambda f: f in man1
2159 managing = lambda f: f in man1
2157
2160
2158 modified, added, removed = [], [], []
2161 modified, added, removed = [], [], []
2159 for f in self._files:
2162 for f in self._files:
2160 if not managing(f):
2163 if not managing(f):
2161 added.append(f)
2164 added.append(f)
2162 elif self[f]:
2165 elif self[f]:
2163 modified.append(f)
2166 modified.append(f)
2164 else:
2167 else:
2165 removed.append(f)
2168 removed.append(f)
2166
2169
2167 return scmutil.status(modified, added, removed, [], [], [], [])
2170 return scmutil.status(modified, added, removed, [], [], [], [])
@@ -1,829 +1,831 b''
1 $ HGMERGE=true; export HGMERGE
1 $ HGMERGE=true; export HGMERGE
2
2
3 init
3 init
4
4
5 $ hg init repo
5 $ hg init repo
6 $ cd repo
6 $ cd repo
7
7
8 commit
8 commit
9
9
10 $ echo 'a' > a
10 $ echo 'a' > a
11 $ hg ci -A -m test -u nobody -d '1 0'
11 $ hg ci -A -m test -u nobody -d '1 0'
12 adding a
12 adding a
13
13
14 annotate -c
14 annotate -c
15
15
16 $ hg annotate -c a
16 $ hg annotate -c a
17 8435f90966e4: a
17 8435f90966e4: a
18
18
19 annotate -cl
19 annotate -cl
20
20
21 $ hg annotate -cl a
21 $ hg annotate -cl a
22 8435f90966e4:1: a
22 8435f90966e4:1: a
23
23
24 annotate -d
24 annotate -d
25
25
26 $ hg annotate -d a
26 $ hg annotate -d a
27 Thu Jan 01 00:00:01 1970 +0000: a
27 Thu Jan 01 00:00:01 1970 +0000: a
28
28
29 annotate -n
29 annotate -n
30
30
31 $ hg annotate -n a
31 $ hg annotate -n a
32 0: a
32 0: a
33
33
34 annotate -nl
34 annotate -nl
35
35
36 $ hg annotate -nl a
36 $ hg annotate -nl a
37 0:1: a
37 0:1: a
38
38
39 annotate -u
39 annotate -u
40
40
41 $ hg annotate -u a
41 $ hg annotate -u a
42 nobody: a
42 nobody: a
43
43
44 annotate -cdnu
44 annotate -cdnu
45
45
46 $ hg annotate -cdnu a
46 $ hg annotate -cdnu a
47 nobody 0 8435f90966e4 Thu Jan 01 00:00:01 1970 +0000: a
47 nobody 0 8435f90966e4 Thu Jan 01 00:00:01 1970 +0000: a
48
48
49 annotate -cdnul
49 annotate -cdnul
50
50
51 $ hg annotate -cdnul a
51 $ hg annotate -cdnul a
52 nobody 0 8435f90966e4 Thu Jan 01 00:00:01 1970 +0000:1: a
52 nobody 0 8435f90966e4 Thu Jan 01 00:00:01 1970 +0000:1: a
53
53
54 annotate (JSON)
54 annotate (JSON)
55
55
56 $ hg annotate -Tjson a
56 $ hg annotate -Tjson a
57 [
57 [
58 {
58 {
59 "line": "a\n",
59 "line": "a\n",
60 "rev": 0
60 "rev": 0
61 }
61 }
62 ]
62 ]
63
63
64 $ hg annotate -Tjson -cdfnul a
64 $ hg annotate -Tjson -cdfnul a
65 [
65 [
66 {
66 {
67 "date": [1.0, 0],
67 "date": [1.0, 0],
68 "file": "a",
68 "file": "a",
69 "line": "a\n",
69 "line": "a\n",
70 "line_number": 1,
70 "line_number": 1,
71 "node": "8435f90966e442695d2ded29fdade2bac5ad8065",
71 "node": "8435f90966e442695d2ded29fdade2bac5ad8065",
72 "rev": 0,
72 "rev": 0,
73 "user": "nobody"
73 "user": "nobody"
74 }
74 }
75 ]
75 ]
76
76
77 $ cat <<EOF >>a
77 $ cat <<EOF >>a
78 > a
78 > a
79 > a
79 > a
80 > EOF
80 > EOF
81 $ hg ci -ma1 -d '1 0'
81 $ hg ci -ma1 -d '1 0'
82 $ hg cp a b
82 $ hg cp a b
83 $ hg ci -mb -d '1 0'
83 $ hg ci -mb -d '1 0'
84 $ cat <<EOF >> b
84 $ cat <<EOF >> b
85 > b4
85 > b4
86 > b5
86 > b5
87 > b6
87 > b6
88 > EOF
88 > EOF
89 $ hg ci -mb2 -d '2 0'
89 $ hg ci -mb2 -d '2 0'
90
90
91 annotate -n b
91 annotate -n b
92
92
93 $ hg annotate -n b
93 $ hg annotate -n b
94 0: a
94 0: a
95 1: a
95 1: a
96 1: a
96 1: a
97 3: b4
97 3: b4
98 3: b5
98 3: b5
99 3: b6
99 3: b6
100
100
101 annotate --no-follow b
101 annotate --no-follow b
102
102
103 $ hg annotate --no-follow b
103 $ hg annotate --no-follow b
104 2: a
104 2: a
105 2: a
105 2: a
106 2: a
106 2: a
107 3: b4
107 3: b4
108 3: b5
108 3: b5
109 3: b6
109 3: b6
110
110
111 annotate -nl b
111 annotate -nl b
112
112
113 $ hg annotate -nl b
113 $ hg annotate -nl b
114 0:1: a
114 0:1: a
115 1:2: a
115 1:2: a
116 1:3: a
116 1:3: a
117 3:4: b4
117 3:4: b4
118 3:5: b5
118 3:5: b5
119 3:6: b6
119 3:6: b6
120
120
121 annotate -nf b
121 annotate -nf b
122
122
123 $ hg annotate -nf b
123 $ hg annotate -nf b
124 0 a: a
124 0 a: a
125 1 a: a
125 1 a: a
126 1 a: a
126 1 a: a
127 3 b: b4
127 3 b: b4
128 3 b: b5
128 3 b: b5
129 3 b: b6
129 3 b: b6
130
130
131 annotate -nlf b
131 annotate -nlf b
132
132
133 $ hg annotate -nlf b
133 $ hg annotate -nlf b
134 0 a:1: a
134 0 a:1: a
135 1 a:2: a
135 1 a:2: a
136 1 a:3: a
136 1 a:3: a
137 3 b:4: b4
137 3 b:4: b4
138 3 b:5: b5
138 3 b:5: b5
139 3 b:6: b6
139 3 b:6: b6
140
140
141 $ hg up -C 2
141 $ hg up -C 2
142 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
142 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
143 $ cat <<EOF >> b
143 $ cat <<EOF >> b
144 > b4
144 > b4
145 > c
145 > c
146 > b5
146 > b5
147 > EOF
147 > EOF
148 $ hg ci -mb2.1 -d '2 0'
148 $ hg ci -mb2.1 -d '2 0'
149 created new head
149 created new head
150 $ hg merge
150 $ hg merge
151 merging b
151 merging b
152 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
152 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
153 (branch merge, don't forget to commit)
153 (branch merge, don't forget to commit)
154 $ hg ci -mmergeb -d '3 0'
154 $ hg ci -mmergeb -d '3 0'
155
155
156 annotate after merge
156 annotate after merge
157
157
158 $ hg annotate -nf b
158 $ hg annotate -nf b
159 0 a: a
159 0 a: a
160 1 a: a
160 1 a: a
161 1 a: a
161 1 a: a
162 3 b: b4
162 3 b: b4
163 4 b: c
163 4 b: c
164 3 b: b5
164 3 b: b5
165
165
166 annotate after merge with -l
166 annotate after merge with -l
167
167
168 $ hg annotate -nlf b
168 $ hg annotate -nlf b
169 0 a:1: a
169 0 a:1: a
170 1 a:2: a
170 1 a:2: a
171 1 a:3: a
171 1 a:3: a
172 3 b:4: b4
172 3 b:4: b4
173 4 b:5: c
173 4 b:5: c
174 3 b:5: b5
174 3 b:5: b5
175
175
176 $ hg up -C 1
176 $ hg up -C 1
177 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
177 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
178 $ hg cp a b
178 $ hg cp a b
179 $ cat <<EOF > b
179 $ cat <<EOF > b
180 > a
180 > a
181 > z
181 > z
182 > a
182 > a
183 > EOF
183 > EOF
184 $ hg ci -mc -d '3 0'
184 $ hg ci -mc -d '3 0'
185 created new head
185 created new head
186 $ hg merge
186 $ hg merge
187 merging b
187 merging b
188 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
188 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
189 (branch merge, don't forget to commit)
189 (branch merge, don't forget to commit)
190 $ cat <<EOF >> b
190 $ cat <<EOF >> b
191 > b4
191 > b4
192 > c
192 > c
193 > b5
193 > b5
194 > EOF
194 > EOF
195 $ echo d >> b
195 $ echo d >> b
196 $ hg ci -mmerge2 -d '4 0'
196 $ hg ci -mmerge2 -d '4 0'
197
197
198 annotate after rename merge
198 annotate after rename merge
199
199
200 $ hg annotate -nf b
200 $ hg annotate -nf b
201 0 a: a
201 0 a: a
202 6 b: z
202 6 b: z
203 1 a: a
203 1 a: a
204 3 b: b4
204 3 b: b4
205 4 b: c
205 4 b: c
206 3 b: b5
206 3 b: b5
207 7 b: d
207 7 b: d
208
208
209 annotate after rename merge with -l
209 annotate after rename merge with -l
210
210
211 $ hg annotate -nlf b
211 $ hg annotate -nlf b
212 0 a:1: a
212 0 a:1: a
213 6 b:2: z
213 6 b:2: z
214 1 a:3: a
214 1 a:3: a
215 3 b:4: b4
215 3 b:4: b4
216 4 b:5: c
216 4 b:5: c
217 3 b:5: b5
217 3 b:5: b5
218 7 b:7: d
218 7 b:7: d
219
219
220 Issue2807: alignment of line numbers with -l
220 Issue2807: alignment of line numbers with -l
221
221
222 $ echo more >> b
222 $ echo more >> b
223 $ hg ci -mmore -d '5 0'
223 $ hg ci -mmore -d '5 0'
224 $ echo more >> b
224 $ echo more >> b
225 $ hg ci -mmore -d '6 0'
225 $ hg ci -mmore -d '6 0'
226 $ echo more >> b
226 $ echo more >> b
227 $ hg ci -mmore -d '7 0'
227 $ hg ci -mmore -d '7 0'
228 $ hg annotate -nlf b
228 $ hg annotate -nlf b
229 0 a: 1: a
229 0 a: 1: a
230 6 b: 2: z
230 6 b: 2: z
231 1 a: 3: a
231 1 a: 3: a
232 3 b: 4: b4
232 3 b: 4: b4
233 4 b: 5: c
233 4 b: 5: c
234 3 b: 5: b5
234 3 b: 5: b5
235 7 b: 7: d
235 7 b: 7: d
236 8 b: 8: more
236 8 b: 8: more
237 9 b: 9: more
237 9 b: 9: more
238 10 b:10: more
238 10 b:10: more
239
239
240 linkrev vs rev
240 linkrev vs rev
241
241
242 $ hg annotate -r tip -n a
242 $ hg annotate -r tip -n a
243 0: a
243 0: a
244 1: a
244 1: a
245 1: a
245 1: a
246
246
247 linkrev vs rev with -l
247 linkrev vs rev with -l
248
248
249 $ hg annotate -r tip -nl a
249 $ hg annotate -r tip -nl a
250 0:1: a
250 0:1: a
251 1:2: a
251 1:2: a
252 1:3: a
252 1:3: a
253
253
254 Issue589: "undelete" sequence leads to crash
254 Issue589: "undelete" sequence leads to crash
255
255
256 annotate was crashing when trying to --follow something
256 annotate was crashing when trying to --follow something
257
257
258 like A -> B -> A
258 like A -> B -> A
259
259
260 generate ABA rename configuration
260 generate ABA rename configuration
261
261
262 $ echo foo > foo
262 $ echo foo > foo
263 $ hg add foo
263 $ hg add foo
264 $ hg ci -m addfoo
264 $ hg ci -m addfoo
265 $ hg rename foo bar
265 $ hg rename foo bar
266 $ hg ci -m renamefoo
266 $ hg ci -m renamefoo
267 $ hg rename bar foo
267 $ hg rename bar foo
268 $ hg ci -m renamebar
268 $ hg ci -m renamebar
269
269
270 annotate after ABA with follow
270 annotate after ABA with follow
271
271
272 $ hg annotate --follow foo
272 $ hg annotate --follow foo
273 foo: foo
273 foo: foo
274
274
275 missing file
275 missing file
276
276
277 $ hg ann nosuchfile
277 $ hg ann nosuchfile
278 abort: nosuchfile: no such file in rev e9e6b4fa872f
278 abort: nosuchfile: no such file in rev e9e6b4fa872f
279 [255]
279 [255]
280
280
281 annotate file without '\n' on last line
281 annotate file without '\n' on last line
282
282
283 $ printf "" > c
283 $ printf "" > c
284 $ hg ci -A -m test -u nobody -d '1 0'
284 $ hg ci -A -m test -u nobody -d '1 0'
285 adding c
285 adding c
286 $ hg annotate c
286 $ hg annotate c
287 $ printf "a\nb" > c
287 $ printf "a\nb" > c
288 $ hg ci -m test
288 $ hg ci -m test
289 $ hg annotate c
289 $ hg annotate c
290 [0-9]+: a (re)
290 [0-9]+: a (re)
291 [0-9]+: b (re)
291 [0-9]+: b (re)
292
292
293 Issue3841: check annotation of the file of which filelog includes
293 Issue3841: check annotation of the file of which filelog includes
294 merging between the revision and its ancestor
294 merging between the revision and its ancestor
295
295
296 to reproduce the situation with recent Mercurial, this script uses (1)
296 to reproduce the situation with recent Mercurial, this script uses (1)
297 "hg debugsetparents" to merge without ancestor check by "hg merge",
297 "hg debugsetparents" to merge without ancestor check by "hg merge",
298 and (2) the extension to allow filelog merging between the revision
298 and (2) the extension to allow filelog merging between the revision
299 and its ancestor by overriding "repo._filecommit".
299 and its ancestor by overriding "repo._filecommit".
300
300
301 $ cat > ../legacyrepo.py <<EOF
301 $ cat > ../legacyrepo.py <<EOF
302 > from mercurial import node, error
302 > from mercurial import node, error
303 > def reposetup(ui, repo):
303 > def reposetup(ui, repo):
304 > class legacyrepo(repo.__class__):
304 > class legacyrepo(repo.__class__):
305 > def _filecommit(self, fctx, manifest1, manifest2,
305 > def _filecommit(self, fctx, manifest1, manifest2,
306 > linkrev, tr, changelist):
306 > linkrev, tr, changelist):
307 > fname = fctx.path()
307 > fname = fctx.path()
308 > text = fctx.data()
308 > text = fctx.data()
309 > flog = self.file(fname)
309 > flog = self.file(fname)
310 > fparent1 = manifest1.get(fname, node.nullid)
310 > fparent1 = manifest1.get(fname, node.nullid)
311 > fparent2 = manifest2.get(fname, node.nullid)
311 > fparent2 = manifest2.get(fname, node.nullid)
312 > meta = {}
312 > meta = {}
313 > copy = fctx.renamed()
313 > copy = fctx.renamed()
314 > if copy and copy[0] != fname:
314 > if copy and copy[0] != fname:
315 > raise error.Abort('copying is not supported')
315 > raise error.Abort('copying is not supported')
316 > if fparent2 != node.nullid:
316 > if fparent2 != node.nullid:
317 > changelist.append(fname)
317 > changelist.append(fname)
318 > return flog.add(text, meta, tr, linkrev,
318 > return flog.add(text, meta, tr, linkrev,
319 > fparent1, fparent2)
319 > fparent1, fparent2)
320 > raise error.Abort('only merging is supported')
320 > raise error.Abort('only merging is supported')
321 > repo.__class__ = legacyrepo
321 > repo.__class__ = legacyrepo
322 > EOF
322 > EOF
323
323
324 $ cat > baz <<EOF
324 $ cat > baz <<EOF
325 > 1
325 > 1
326 > 2
326 > 2
327 > 3
327 > 3
328 > 4
328 > 4
329 > 5
329 > 5
330 > EOF
330 > EOF
331 $ hg add baz
331 $ hg add baz
332 $ hg commit -m "baz:0"
332 $ hg commit -m "baz:0"
333
333
334 $ cat > baz <<EOF
334 $ cat > baz <<EOF
335 > 1 baz:1
335 > 1 baz:1
336 > 2
336 > 2
337 > 3
337 > 3
338 > 4
338 > 4
339 > 5
339 > 5
340 > EOF
340 > EOF
341 $ hg commit -m "baz:1"
341 $ hg commit -m "baz:1"
342
342
343 $ cat > baz <<EOF
343 $ cat > baz <<EOF
344 > 1 baz:1
344 > 1 baz:1
345 > 2 baz:2
345 > 2 baz:2
346 > 3
346 > 3
347 > 4
347 > 4
348 > 5
348 > 5
349 > EOF
349 > EOF
350 $ hg debugsetparents 17 17
350 $ hg debugsetparents 17 17
351 $ hg --config extensions.legacyrepo=../legacyrepo.py commit -m "baz:2"
351 $ hg --config extensions.legacyrepo=../legacyrepo.py commit -m "baz:2"
352 $ hg debugindexdot .hg/store/data/baz.i
352 $ hg debugindexdot .hg/store/data/baz.i
353 digraph G {
353 digraph G {
354 -1 -> 0
354 -1 -> 0
355 0 -> 1
355 0 -> 1
356 1 -> 2
356 1 -> 2
357 1 -> 2
357 1 -> 2
358 }
358 }
359 $ hg annotate baz
359 $ hg annotate baz
360 17: 1 baz:1
360 17: 1 baz:1
361 18: 2 baz:2
361 18: 2 baz:2
362 16: 3
362 16: 3
363 16: 4
363 16: 4
364 16: 5
364 16: 5
365
365
366 $ cat > baz <<EOF
366 $ cat > baz <<EOF
367 > 1 baz:1
367 > 1 baz:1
368 > 2 baz:2
368 > 2 baz:2
369 > 3 baz:3
369 > 3 baz:3
370 > 4
370 > 4
371 > 5
371 > 5
372 > EOF
372 > EOF
373 $ hg commit -m "baz:3"
373 $ hg commit -m "baz:3"
374
374
375 $ cat > baz <<EOF
375 $ cat > baz <<EOF
376 > 1 baz:1
376 > 1 baz:1
377 > 2 baz:2
377 > 2 baz:2
378 > 3 baz:3
378 > 3 baz:3
379 > 4 baz:4
379 > 4 baz:4
380 > 5
380 > 5
381 > EOF
381 > EOF
382 $ hg debugsetparents 19 18
382 $ hg debugsetparents 19 18
383 $ hg --config extensions.legacyrepo=../legacyrepo.py commit -m "baz:4"
383 $ hg --config extensions.legacyrepo=../legacyrepo.py commit -m "baz:4"
384 $ hg debugindexdot .hg/store/data/baz.i
384 $ hg debugindexdot .hg/store/data/baz.i
385 digraph G {
385 digraph G {
386 -1 -> 0
386 -1 -> 0
387 0 -> 1
387 0 -> 1
388 1 -> 2
388 1 -> 2
389 1 -> 2
389 1 -> 2
390 2 -> 3
390 2 -> 3
391 3 -> 4
391 3 -> 4
392 2 -> 4
392 2 -> 4
393 }
393 }
394 $ hg annotate baz
394 $ hg annotate baz
395 17: 1 baz:1
395 17: 1 baz:1
396 18: 2 baz:2
396 18: 2 baz:2
397 19: 3 baz:3
397 19: 3 baz:3
398 20: 4 baz:4
398 20: 4 baz:4
399 16: 5
399 16: 5
400
400
401 annotate clean file
401 annotate clean file
402
402
403 $ hg annotate -ncr "wdir()" foo
403 $ hg annotate -ncr "wdir()" foo
404 11 472b18db256d : foo
404 11 472b18db256d : foo
405
405
406 annotate modified file
406 annotate modified file
407
407
408 $ echo foofoo >> foo
408 $ echo foofoo >> foo
409 $ hg annotate -r "wdir()" foo
409 $ hg annotate -r "wdir()" foo
410 11 : foo
410 11 : foo
411 20+: foofoo
411 20+: foofoo
412
412
413 $ hg annotate -cr "wdir()" foo
413 $ hg annotate -cr "wdir()" foo
414 472b18db256d : foo
414 472b18db256d : foo
415 b6bedd5477e7+: foofoo
415 b6bedd5477e7+: foofoo
416
416
417 $ hg annotate -ncr "wdir()" foo
417 $ hg annotate -ncr "wdir()" foo
418 11 472b18db256d : foo
418 11 472b18db256d : foo
419 20 b6bedd5477e7+: foofoo
419 20 b6bedd5477e7+: foofoo
420
420
421 $ hg annotate --debug -ncr "wdir()" foo
421 $ hg annotate --debug -ncr "wdir()" foo
422 11 472b18db256d1e8282064eab4bfdaf48cbfe83cd : foo
422 11 472b18db256d1e8282064eab4bfdaf48cbfe83cd : foo
423 20 b6bedd5477e797f25e568a6402d4697f3f895a72+: foofoo
423 20 b6bedd5477e797f25e568a6402d4697f3f895a72+: foofoo
424
424
425 $ hg annotate -udr "wdir()" foo
425 $ hg annotate -udr "wdir()" foo
426 test Thu Jan 01 00:00:00 1970 +0000: foo
426 test Thu Jan 01 00:00:00 1970 +0000: foo
427 test [A-Za-z0-9:+ ]+: foofoo (re)
427 test [A-Za-z0-9:+ ]+: foofoo (re)
428
428
429 $ hg annotate -ncr "wdir()" -Tjson foo
429 $ hg annotate -ncr "wdir()" -Tjson foo
430 [
430 [
431 {
431 {
432 "line": "foo\n",
432 "line": "foo\n",
433 "node": "472b18db256d1e8282064eab4bfdaf48cbfe83cd",
433 "node": "472b18db256d1e8282064eab4bfdaf48cbfe83cd",
434 "rev": 11
434 "rev": 11
435 },
435 },
436 {
436 {
437 "line": "foofoo\n",
437 "line": "foofoo\n",
438 "node": null,
438 "node": null,
439 "rev": null
439 "rev": null
440 }
440 }
441 ]
441 ]
442
442
443 annotate added file
443 annotate added file
444
444
445 $ echo bar > bar
445 $ echo bar > bar
446 $ hg add bar
446 $ hg add bar
447 $ hg annotate -ncr "wdir()" bar
447 $ hg annotate -ncr "wdir()" bar
448 20 b6bedd5477e7+: bar
448 20 b6bedd5477e7+: bar
449
449
450 annotate renamed file
450 annotate renamed file
451
451
452 $ hg rename foo renamefoo2
452 $ hg rename foo renamefoo2
453 $ hg annotate -ncr "wdir()" renamefoo2
453 $ hg annotate -ncr "wdir()" renamefoo2
454 11 472b18db256d : foo
454 11 472b18db256d : foo
455 20 b6bedd5477e7+: foofoo
455 20 b6bedd5477e7+: foofoo
456
456
457 annotate missing file
457 annotate missing file
458
458
459 $ rm baz
459 $ rm baz
460 #if windows
460 #if windows
461 $ hg annotate -ncr "wdir()" baz
461 $ hg annotate -ncr "wdir()" baz
462 abort: $TESTTMP\repo\baz: The system cannot find the file specified
462 abort: $TESTTMP\repo\baz: The system cannot find the file specified
463 [255]
463 [255]
464 #else
464 #else
465 $ hg annotate -ncr "wdir()" baz
465 $ hg annotate -ncr "wdir()" baz
466 abort: No such file or directory: $TESTTMP/repo/baz
466 abort: No such file or directory: $TESTTMP/repo/baz
467 [255]
467 [255]
468 #endif
468 #endif
469
469
470 annotate removed file
470 annotate removed file
471
471
472 $ hg rm baz
472 $ hg rm baz
473 #if windows
473 #if windows
474 $ hg annotate -ncr "wdir()" baz
474 $ hg annotate -ncr "wdir()" baz
475 abort: $TESTTMP\repo\baz: The system cannot find the file specified
475 abort: $TESTTMP\repo\baz: The system cannot find the file specified
476 [255]
476 [255]
477 #else
477 #else
478 $ hg annotate -ncr "wdir()" baz
478 $ hg annotate -ncr "wdir()" baz
479 abort: No such file or directory: $TESTTMP/repo/baz
479 abort: No such file or directory: $TESTTMP/repo/baz
480 [255]
480 [255]
481 #endif
481 #endif
482
482
483 $ hg revert --all --no-backup --quiet
483 $ hg revert --all --no-backup --quiet
484 $ hg id -n
484 $ hg id -n
485 20
485 20
486
486
487 Test followlines() revset; we usually check both followlines(pat, range) and
487 Test followlines() revset; we usually check both followlines(pat, range) and
488 followlines(pat, range, descend=True) to make sure both give the same result
488 followlines(pat, range, descend=True) to make sure both give the same result
489 when they should.
489 when they should.
490
490
491 $ echo a >> foo
492 $ hg ci -m 'foo: add a'
491 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 3:5)'
493 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 3:5)'
492 16: baz:0
494 16: baz:0
493 19: baz:3
495 19: baz:3
494 20: baz:4
496 20: baz:4
495 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 3:5, startrev=20)'
497 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 3:5, startrev=20)'
496 16: baz:0
498 16: baz:0
497 19: baz:3
499 19: baz:3
498 20: baz:4
500 20: baz:4
499 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 3:5, startrev=19)'
501 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 3:5, startrev=19)'
500 16: baz:0
502 16: baz:0
501 19: baz:3
503 19: baz:3
502 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 3:5, startrev=19, descend=True)'
504 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 3:5, startrev=19, descend=True)'
503 19: baz:3
505 19: baz:3
504 20: baz:4
506 20: baz:4
505 $ printf "0\n0\n" | cat - baz > baz1
507 $ printf "0\n0\n" | cat - baz > baz1
506 $ mv baz1 baz
508 $ mv baz1 baz
507 $ hg ci -m 'added two lines with 0'
509 $ hg ci -m 'added two lines with 0'
508 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 5:7)'
510 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 5:7)'
509 16: baz:0
511 16: baz:0
510 19: baz:3
512 19: baz:3
511 20: baz:4
513 20: baz:4
512 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 3:5, descend=true, startrev=19)'
514 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 3:5, descend=true, startrev=19)'
513 19: baz:3
515 19: baz:3
514 20: baz:4
516 20: baz:4
515 $ echo 6 >> baz
517 $ echo 6 >> baz
516 $ hg ci -m 'added line 8'
518 $ hg ci -m 'added line 8'
517 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 5:7)'
519 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 5:7)'
518 16: baz:0
520 16: baz:0
519 19: baz:3
521 19: baz:3
520 20: baz:4
522 20: baz:4
521 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 3:5, startrev=19, descend=1)'
523 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 3:5, startrev=19, descend=1)'
522 19: baz:3
524 19: baz:3
523 20: baz:4
525 20: baz:4
524 $ sed 's/3/3+/' baz > baz.new
526 $ sed 's/3/3+/' baz > baz.new
525 $ mv baz.new baz
527 $ mv baz.new baz
526 $ hg ci -m 'baz:3->3+'
528 $ hg ci -m 'baz:3->3+'
527 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 5:7, descend=0)'
529 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 5:7, descend=0)'
528 16: baz:0
530 16: baz:0
529 19: baz:3
531 19: baz:3
530 20: baz:4
532 20: baz:4
531 23: baz:3->3+
533 24: baz:3->3+
532 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 3:5, startrev=17, descend=True)'
534 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 3:5, startrev=17, descend=True)'
533 19: baz:3
535 19: baz:3
534 20: baz:4
536 20: baz:4
535 23: baz:3->3+
537 24: baz:3->3+
536 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 1:2, descend=false)'
538 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 1:2, descend=false)'
537 21: added two lines with 0
539 22: added two lines with 0
538
540
539 file patterns are okay
541 file patterns are okay
540 $ hg log -T '{rev}: {desc}\n' -r 'followlines("path:baz", 1:2)'
542 $ hg log -T '{rev}: {desc}\n' -r 'followlines("path:baz", 1:2)'
541 21: added two lines with 0
543 22: added two lines with 0
542
544
543 renames are followed
545 renames are followed
544 $ hg mv baz qux
546 $ hg mv baz qux
545 $ sed 's/4/4+/' qux > qux.new
547 $ sed 's/4/4+/' qux > qux.new
546 $ mv qux.new qux
548 $ mv qux.new qux
547 $ hg ci -m 'qux:4->4+'
549 $ hg ci -m 'qux:4->4+'
548 $ hg log -T '{rev}: {desc}\n' -r 'followlines(qux, 5:7)'
550 $ hg log -T '{rev}: {desc}\n' -r 'followlines(qux, 5:7)'
549 16: baz:0
551 16: baz:0
550 19: baz:3
552 19: baz:3
551 20: baz:4
553 20: baz:4
552 23: baz:3->3+
554 24: baz:3->3+
553 24: qux:4->4+
555 25: qux:4->4+
554
556
555 but are missed when following children
557 but are missed when following children
556 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 5:7, startrev=22, descend=True)'
558 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 5:7, startrev=22, descend=True)'
557 23: baz:3->3+
559 24: baz:3->3+
558
560
559 merge
561 merge
560 $ hg up 23 --quiet
562 $ hg up 24 --quiet
561 $ echo 7 >> baz
563 $ echo 7 >> baz
562 $ hg ci -m 'one more line, out of line range'
564 $ hg ci -m 'one more line, out of line range'
563 created new head
565 created new head
564 $ sed 's/3+/3-/' baz > baz.new
566 $ sed 's/3+/3-/' baz > baz.new
565 $ mv baz.new baz
567 $ mv baz.new baz
566 $ hg ci -m 'baz:3+->3-'
568 $ hg ci -m 'baz:3+->3-'
567 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 5:7)'
569 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 5:7)'
568 16: baz:0
570 16: baz:0
569 19: baz:3
571 19: baz:3
570 20: baz:4
572 20: baz:4
571 23: baz:3->3+
573 24: baz:3->3+
572 26: baz:3+->3-
574 27: baz:3+->3-
573 $ hg merge 24
575 $ hg merge 25
574 merging baz and qux to qux
576 merging baz and qux to qux
575 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
577 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
576 (branch merge, don't forget to commit)
578 (branch merge, don't forget to commit)
577 $ hg ci -m merge
579 $ hg ci -m merge
578 $ hg log -T '{rev}: {desc}\n' -r 'followlines(qux, 5:7)'
580 $ hg log -T '{rev}: {desc}\n' -r 'followlines(qux, 5:7)'
579 16: baz:0
581 16: baz:0
580 19: baz:3
582 19: baz:3
581 20: baz:4
583 20: baz:4
582 23: baz:3->3+
584 24: baz:3->3+
583 24: qux:4->4+
585 25: qux:4->4+
584 26: baz:3+->3-
586 27: baz:3+->3-
585 27: merge
587 28: merge
586 $ hg up 24 --quiet
588 $ hg up 25 --quiet
587 $ hg merge 26
589 $ hg merge 27
588 merging qux and baz to qux
590 merging qux and baz to qux
589 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
591 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
590 (branch merge, don't forget to commit)
592 (branch merge, don't forget to commit)
591 $ hg ci -m 'merge from other side'
593 $ hg ci -m 'merge from other side'
592 created new head
594 created new head
593 $ hg log -T '{rev}: {desc}\n' -r 'followlines(qux, 5:7)'
595 $ hg log -T '{rev}: {desc}\n' -r 'followlines(qux, 5:7)'
594 16: baz:0
596 16: baz:0
595 19: baz:3
597 19: baz:3
596 20: baz:4
598 20: baz:4
597 23: baz:3->3+
599 24: baz:3->3+
598 24: qux:4->4+
600 25: qux:4->4+
599 26: baz:3+->3-
601 27: baz:3+->3-
600 28: merge from other side
602 29: merge from other side
601 $ hg up 23 --quiet
603 $ hg up 24 --quiet
602
604
603 we are missing the branch with rename when following children
605 we are missing the branch with rename when following children
604 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 5:7, startrev=25, descend=True)'
606 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 5:7, startrev=26, descend=True)'
605 26: baz:3+->3-
607 27: baz:3+->3-
606
608
607 we follow all branches in descending direction
609 we follow all branches in descending direction
608 $ hg up 22 --quiet
610 $ hg up 23 --quiet
609 $ sed 's/3/+3/' baz > baz.new
611 $ sed 's/3/+3/' baz > baz.new
610 $ mv baz.new baz
612 $ mv baz.new baz
611 $ hg ci -m 'baz:3->+3'
613 $ hg ci -m 'baz:3->+3'
612 created new head
614 created new head
613 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 2:5, startrev=16, descend=True)' --graph
615 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 2:5, startrev=16, descend=True)' --graph
614 @ 29: baz:3->+3
616 @ 30: baz:3->+3
615 :
617 :
616 : o 26: baz:3+->3-
618 : o 27: baz:3+->3-
617 : :
619 : :
618 : o 23: baz:3->3+
620 : o 24: baz:3->3+
619 :/
621 :/
620 o 20: baz:4
622 o 20: baz:4
621 |\
623 |\
622 | o 19: baz:3
624 | o 19: baz:3
623 |/
625 |/
624 o 18: baz:2
626 o 18: baz:2
625 :
627 :
626 o 16: baz:0
628 o 16: baz:0
627 |
629 |
628 ~
630 ~
629
631
630 check error cases
632 check error cases
631 $ hg up 23 --quiet
633 $ hg up 24 --quiet
632 $ hg log -r 'followlines()'
634 $ hg log -r 'followlines()'
633 hg: parse error: followlines takes at least 1 positional arguments
635 hg: parse error: followlines takes at least 1 positional arguments
634 [255]
636 [255]
635 $ hg log -r 'followlines(baz)'
637 $ hg log -r 'followlines(baz)'
636 hg: parse error: followlines requires a line range
638 hg: parse error: followlines requires a line range
637 [255]
639 [255]
638 $ hg log -r 'followlines(baz, 1)'
640 $ hg log -r 'followlines(baz, 1)'
639 hg: parse error: followlines expects a line range
641 hg: parse error: followlines expects a line range
640 [255]
642 [255]
641 $ hg log -r 'followlines(baz, 1:2, startrev=desc("b"))'
643 $ hg log -r 'followlines(baz, 1:2, startrev=desc("b"))'
642 hg: parse error: followlines expects exactly one revision
644 hg: parse error: followlines expects exactly one revision
643 [255]
645 [255]
644 $ hg log -r 'followlines("glob:*", 1:2)'
646 $ hg log -r 'followlines("glob:*", 1:2)'
645 hg: parse error: followlines expects exactly one file
647 hg: parse error: followlines expects exactly one file
646 [255]
648 [255]
647 $ hg log -r 'followlines(baz, 1:)'
649 $ hg log -r 'followlines(baz, 1:)'
648 hg: parse error: line range bounds must be integers
650 hg: parse error: line range bounds must be integers
649 [255]
651 [255]
650 $ hg log -r 'followlines(baz, :1)'
652 $ hg log -r 'followlines(baz, :1)'
651 hg: parse error: line range bounds must be integers
653 hg: parse error: line range bounds must be integers
652 [255]
654 [255]
653 $ hg log -r 'followlines(baz, x:4)'
655 $ hg log -r 'followlines(baz, x:4)'
654 hg: parse error: line range bounds must be integers
656 hg: parse error: line range bounds must be integers
655 [255]
657 [255]
656 $ hg log -r 'followlines(baz, 5:4)'
658 $ hg log -r 'followlines(baz, 5:4)'
657 hg: parse error: line range must be positive
659 hg: parse error: line range must be positive
658 [255]
660 [255]
659 $ hg log -r 'followlines(baz, 0:4)'
661 $ hg log -r 'followlines(baz, 0:4)'
660 hg: parse error: fromline must be strictly positive
662 hg: parse error: fromline must be strictly positive
661 [255]
663 [255]
662 $ hg log -r 'followlines(baz, 2:40)'
664 $ hg log -r 'followlines(baz, 2:40)'
663 abort: line range exceeds file size
665 abort: line range exceeds file size
664 [255]
666 [255]
665 $ hg log -r 'followlines(baz, 2:4, startrev=20, descend=[1])'
667 $ hg log -r 'followlines(baz, 2:4, startrev=20, descend=[1])'
666 hg: parse error at 43: syntax error in revset 'followlines(baz, 2:4, startrev=20, descend=[1])'
668 hg: parse error at 43: syntax error in revset 'followlines(baz, 2:4, startrev=20, descend=[1])'
667 [255]
669 [255]
668 $ hg log -r 'followlines(baz, 2:4, startrev=20, descend=a)'
670 $ hg log -r 'followlines(baz, 2:4, startrev=20, descend=a)'
669 hg: parse error: 'descend' argument must be a boolean
671 hg: parse error: 'descend' argument must be a boolean
670 [255]
672 [255]
671
673
672 Test annotate with whitespace options
674 Test annotate with whitespace options
673
675
674 $ cd ..
676 $ cd ..
675 $ hg init repo-ws
677 $ hg init repo-ws
676 $ cd repo-ws
678 $ cd repo-ws
677 $ cat > a <<EOF
679 $ cat > a <<EOF
678 > aa
680 > aa
679 >
681 >
680 > b b
682 > b b
681 > EOF
683 > EOF
682 $ hg ci -Am "adda"
684 $ hg ci -Am "adda"
683 adding a
685 adding a
684 $ sed 's/EOL$//g' > a <<EOF
686 $ sed 's/EOL$//g' > a <<EOF
685 > a a
687 > a a
686 >
688 >
687 > EOL
689 > EOL
688 > b b
690 > b b
689 > EOF
691 > EOF
690 $ hg ci -m "changea"
692 $ hg ci -m "changea"
691
693
692 Annotate with no option
694 Annotate with no option
693
695
694 $ hg annotate a
696 $ hg annotate a
695 1: a a
697 1: a a
696 0:
698 0:
697 1:
699 1:
698 1: b b
700 1: b b
699
701
700 Annotate with --ignore-space-change
702 Annotate with --ignore-space-change
701
703
702 $ hg annotate --ignore-space-change a
704 $ hg annotate --ignore-space-change a
703 1: a a
705 1: a a
704 1:
706 1:
705 0:
707 0:
706 0: b b
708 0: b b
707
709
708 Annotate with --ignore-all-space
710 Annotate with --ignore-all-space
709
711
710 $ hg annotate --ignore-all-space a
712 $ hg annotate --ignore-all-space a
711 0: a a
713 0: a a
712 0:
714 0:
713 1:
715 1:
714 0: b b
716 0: b b
715
717
716 Annotate with --ignore-blank-lines (similar to no options case)
718 Annotate with --ignore-blank-lines (similar to no options case)
717
719
718 $ hg annotate --ignore-blank-lines a
720 $ hg annotate --ignore-blank-lines a
719 1: a a
721 1: a a
720 0:
722 0:
721 1:
723 1:
722 1: b b
724 1: b b
723
725
724 $ cd ..
726 $ cd ..
725
727
726 Annotate with linkrev pointing to another branch
728 Annotate with linkrev pointing to another branch
727 ------------------------------------------------
729 ------------------------------------------------
728
730
729 create history with a filerev whose linkrev points to another branch
731 create history with a filerev whose linkrev points to another branch
730
732
731 $ hg init branchedlinkrev
733 $ hg init branchedlinkrev
732 $ cd branchedlinkrev
734 $ cd branchedlinkrev
733 $ echo A > a
735 $ echo A > a
734 $ hg commit -Am 'contentA'
736 $ hg commit -Am 'contentA'
735 adding a
737 adding a
736 $ echo B >> a
738 $ echo B >> a
737 $ hg commit -m 'contentB'
739 $ hg commit -m 'contentB'
738 $ hg up --rev 'desc(contentA)'
740 $ hg up --rev 'desc(contentA)'
739 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
741 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
740 $ echo unrelated > unrelated
742 $ echo unrelated > unrelated
741 $ hg commit -Am 'unrelated'
743 $ hg commit -Am 'unrelated'
742 adding unrelated
744 adding unrelated
743 created new head
745 created new head
744 $ hg graft -r 'desc(contentB)'
746 $ hg graft -r 'desc(contentB)'
745 grafting 1:fd27c222e3e6 "contentB"
747 grafting 1:fd27c222e3e6 "contentB"
746 $ echo C >> a
748 $ echo C >> a
747 $ hg commit -m 'contentC'
749 $ hg commit -m 'contentC'
748 $ echo W >> a
750 $ echo W >> a
749 $ hg log -G
751 $ hg log -G
750 @ changeset: 4:072f1e8df249
752 @ changeset: 4:072f1e8df249
751 | tag: tip
753 | tag: tip
752 | user: test
754 | user: test
753 | date: Thu Jan 01 00:00:00 1970 +0000
755 | date: Thu Jan 01 00:00:00 1970 +0000
754 | summary: contentC
756 | summary: contentC
755 |
757 |
756 o changeset: 3:ff38df03cc4b
758 o changeset: 3:ff38df03cc4b
757 | user: test
759 | user: test
758 | date: Thu Jan 01 00:00:00 1970 +0000
760 | date: Thu Jan 01 00:00:00 1970 +0000
759 | summary: contentB
761 | summary: contentB
760 |
762 |
761 o changeset: 2:62aaf3f6fc06
763 o changeset: 2:62aaf3f6fc06
762 | parent: 0:f0932f74827e
764 | parent: 0:f0932f74827e
763 | user: test
765 | user: test
764 | date: Thu Jan 01 00:00:00 1970 +0000
766 | date: Thu Jan 01 00:00:00 1970 +0000
765 | summary: unrelated
767 | summary: unrelated
766 |
768 |
767 | o changeset: 1:fd27c222e3e6
769 | o changeset: 1:fd27c222e3e6
768 |/ user: test
770 |/ user: test
769 | date: Thu Jan 01 00:00:00 1970 +0000
771 | date: Thu Jan 01 00:00:00 1970 +0000
770 | summary: contentB
772 | summary: contentB
771 |
773 |
772 o changeset: 0:f0932f74827e
774 o changeset: 0:f0932f74827e
773 user: test
775 user: test
774 date: Thu Jan 01 00:00:00 1970 +0000
776 date: Thu Jan 01 00:00:00 1970 +0000
775 summary: contentA
777 summary: contentA
776
778
777
779
778 Annotate should list ancestor of starting revision only
780 Annotate should list ancestor of starting revision only
779
781
780 $ hg annotate a
782 $ hg annotate a
781 0: A
783 0: A
782 3: B
784 3: B
783 4: C
785 4: C
784
786
785 $ hg annotate a -r 'wdir()'
787 $ hg annotate a -r 'wdir()'
786 0 : A
788 0 : A
787 3 : B
789 3 : B
788 4 : C
790 4 : C
789 4+: W
791 4+: W
790
792
791 Even when the starting revision is the linkrev-shadowed one:
793 Even when the starting revision is the linkrev-shadowed one:
792
794
793 $ hg annotate a -r 3
795 $ hg annotate a -r 3
794 0: A
796 0: A
795 3: B
797 3: B
796
798
797 $ cd ..
799 $ cd ..
798
800
799 Issue5360: Deleted chunk in p1 of a merge changeset
801 Issue5360: Deleted chunk in p1 of a merge changeset
800
802
801 $ hg init repo-5360
803 $ hg init repo-5360
802 $ cd repo-5360
804 $ cd repo-5360
803 $ echo 1 > a
805 $ echo 1 > a
804 $ hg commit -A a -m 1
806 $ hg commit -A a -m 1
805 $ echo 2 >> a
807 $ echo 2 >> a
806 $ hg commit -m 2
808 $ hg commit -m 2
807 $ echo a > a
809 $ echo a > a
808 $ hg commit -m a
810 $ hg commit -m a
809 $ hg update '.^' -q
811 $ hg update '.^' -q
810 $ echo 3 >> a
812 $ echo 3 >> a
811 $ hg commit -m 3 -q
813 $ hg commit -m 3 -q
812 $ hg merge 2 -q
814 $ hg merge 2 -q
813 $ cat > a << EOF
815 $ cat > a << EOF
814 > b
816 > b
815 > 1
817 > 1
816 > 2
818 > 2
817 > 3
819 > 3
818 > a
820 > a
819 > EOF
821 > EOF
820 $ hg resolve --mark -q
822 $ hg resolve --mark -q
821 $ hg commit -m m
823 $ hg commit -m m
822 $ hg annotate a
824 $ hg annotate a
823 4: b
825 4: b
824 0: 1
826 0: 1
825 1: 2
827 1: 2
826 3: 3
828 3: 3
827 2: a
829 2: a
828
830
829 $ cd ..
831 $ cd ..
@@ -1,1837 +1,1837 b''
1 #require serve
1 #require serve
2
2
3 $ hg init test
3 $ hg init test
4 $ cd test
4 $ cd test
5 $ echo b > b
5 $ echo b > b
6 $ hg ci -Am "b"
6 $ hg ci -Am "b"
7 adding b
7 adding b
8 $ echo a > a
8 $ echo a > a
9 $ hg ci -Am "first a"
9 $ hg ci -Am "first a"
10 adding a
10 adding a
11 $ hg tag -r 1 a-tag
11 $ hg tag -r 1 a-tag
12 $ hg bookmark -r 1 a-bookmark
12 $ hg bookmark -r 1 a-bookmark
13 $ hg rm a
13 $ hg rm a
14 $ hg ci -m "del a"
14 $ hg ci -m "del a"
15 $ hg branch a-branch
15 $ hg branch a-branch
16 marked working directory as branch a-branch
16 marked working directory as branch a-branch
17 (branches are permanent and global, did you want a bookmark?)
17 (branches are permanent and global, did you want a bookmark?)
18 $ echo b > a
18 $ echo b > a
19 $ hg ci -Am "second a"
19 $ hg ci -Am "second a"
20 adding a
20 adding a
21 $ hg rm a
21 $ hg rm a
22 $ hg ci -m "del2 a"
22 $ hg ci -m "del2 a"
23 $ hg mv b c
23 $ hg mv b c
24 $ hg ci -m "mv b"
24 $ hg ci -m "mv b"
25 $ echo c >> c
25 $ echo c >> c
26 $ hg ci -m "change c"
26 $ hg ci -m "change c"
27 $ hg log -p
27 $ hg log -p
28 changeset: 7:46c1a66bd8fc
28 changeset: 7:46c1a66bd8fc
29 branch: a-branch
29 branch: a-branch
30 tag: tip
30 tag: tip
31 user: test
31 user: test
32 date: Thu Jan 01 00:00:00 1970 +0000
32 date: Thu Jan 01 00:00:00 1970 +0000
33 summary: change c
33 summary: change c
34
34
35 diff -r c9637d3cc8ef -r 46c1a66bd8fc c
35 diff -r c9637d3cc8ef -r 46c1a66bd8fc c
36 --- a/c Thu Jan 01 00:00:00 1970 +0000
36 --- a/c Thu Jan 01 00:00:00 1970 +0000
37 +++ b/c Thu Jan 01 00:00:00 1970 +0000
37 +++ b/c Thu Jan 01 00:00:00 1970 +0000
38 @@ -1,1 +1,2 @@
38 @@ -1,1 +1,2 @@
39 b
39 b
40 +c
40 +c
41
41
42 changeset: 6:c9637d3cc8ef
42 changeset: 6:c9637d3cc8ef
43 branch: a-branch
43 branch: a-branch
44 user: test
44 user: test
45 date: Thu Jan 01 00:00:00 1970 +0000
45 date: Thu Jan 01 00:00:00 1970 +0000
46 summary: mv b
46 summary: mv b
47
47
48 diff -r 958bd88be4eb -r c9637d3cc8ef b
48 diff -r 958bd88be4eb -r c9637d3cc8ef b
49 --- a/b Thu Jan 01 00:00:00 1970 +0000
49 --- a/b Thu Jan 01 00:00:00 1970 +0000
50 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
50 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
51 @@ -1,1 +0,0 @@
51 @@ -1,1 +0,0 @@
52 -b
52 -b
53 diff -r 958bd88be4eb -r c9637d3cc8ef c
53 diff -r 958bd88be4eb -r c9637d3cc8ef c
54 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
54 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
55 +++ b/c Thu Jan 01 00:00:00 1970 +0000
55 +++ b/c Thu Jan 01 00:00:00 1970 +0000
56 @@ -0,0 +1,1 @@
56 @@ -0,0 +1,1 @@
57 +b
57 +b
58
58
59 changeset: 5:958bd88be4eb
59 changeset: 5:958bd88be4eb
60 branch: a-branch
60 branch: a-branch
61 user: test
61 user: test
62 date: Thu Jan 01 00:00:00 1970 +0000
62 date: Thu Jan 01 00:00:00 1970 +0000
63 summary: del2 a
63 summary: del2 a
64
64
65 diff -r 3f41bc784e7e -r 958bd88be4eb a
65 diff -r 3f41bc784e7e -r 958bd88be4eb a
66 --- a/a Thu Jan 01 00:00:00 1970 +0000
66 --- a/a Thu Jan 01 00:00:00 1970 +0000
67 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
67 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
68 @@ -1,1 +0,0 @@
68 @@ -1,1 +0,0 @@
69 -b
69 -b
70
70
71 changeset: 4:3f41bc784e7e
71 changeset: 4:3f41bc784e7e
72 branch: a-branch
72 branch: a-branch
73 user: test
73 user: test
74 date: Thu Jan 01 00:00:00 1970 +0000
74 date: Thu Jan 01 00:00:00 1970 +0000
75 summary: second a
75 summary: second a
76
76
77 diff -r 292258f86fdf -r 3f41bc784e7e a
77 diff -r 292258f86fdf -r 3f41bc784e7e a
78 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
78 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
79 +++ b/a Thu Jan 01 00:00:00 1970 +0000
79 +++ b/a Thu Jan 01 00:00:00 1970 +0000
80 @@ -0,0 +1,1 @@
80 @@ -0,0 +1,1 @@
81 +b
81 +b
82
82
83 changeset: 3:292258f86fdf
83 changeset: 3:292258f86fdf
84 user: test
84 user: test
85 date: Thu Jan 01 00:00:00 1970 +0000
85 date: Thu Jan 01 00:00:00 1970 +0000
86 summary: del a
86 summary: del a
87
87
88 diff -r 94c9dd5ca9b4 -r 292258f86fdf a
88 diff -r 94c9dd5ca9b4 -r 292258f86fdf a
89 --- a/a Thu Jan 01 00:00:00 1970 +0000
89 --- a/a Thu Jan 01 00:00:00 1970 +0000
90 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
90 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
91 @@ -1,1 +0,0 @@
91 @@ -1,1 +0,0 @@
92 -a
92 -a
93
93
94 changeset: 2:94c9dd5ca9b4
94 changeset: 2:94c9dd5ca9b4
95 user: test
95 user: test
96 date: Thu Jan 01 00:00:00 1970 +0000
96 date: Thu Jan 01 00:00:00 1970 +0000
97 summary: Added tag a-tag for changeset 5ed941583260
97 summary: Added tag a-tag for changeset 5ed941583260
98
98
99 diff -r 5ed941583260 -r 94c9dd5ca9b4 .hgtags
99 diff -r 5ed941583260 -r 94c9dd5ca9b4 .hgtags
100 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
100 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
101 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
101 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
102 @@ -0,0 +1,1 @@
102 @@ -0,0 +1,1 @@
103 +5ed941583260248620985524192fdc382ef57c36 a-tag
103 +5ed941583260248620985524192fdc382ef57c36 a-tag
104
104
105 changeset: 1:5ed941583260
105 changeset: 1:5ed941583260
106 bookmark: a-bookmark
106 bookmark: a-bookmark
107 tag: a-tag
107 tag: a-tag
108 user: test
108 user: test
109 date: Thu Jan 01 00:00:00 1970 +0000
109 date: Thu Jan 01 00:00:00 1970 +0000
110 summary: first a
110 summary: first a
111
111
112 diff -r 6563da9dcf87 -r 5ed941583260 a
112 diff -r 6563da9dcf87 -r 5ed941583260 a
113 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
113 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
114 +++ b/a Thu Jan 01 00:00:00 1970 +0000
114 +++ b/a Thu Jan 01 00:00:00 1970 +0000
115 @@ -0,0 +1,1 @@
115 @@ -0,0 +1,1 @@
116 +a
116 +a
117
117
118 changeset: 0:6563da9dcf87
118 changeset: 0:6563da9dcf87
119 user: test
119 user: test
120 date: Thu Jan 01 00:00:00 1970 +0000
120 date: Thu Jan 01 00:00:00 1970 +0000
121 summary: b
121 summary: b
122
122
123 diff -r 000000000000 -r 6563da9dcf87 b
123 diff -r 000000000000 -r 6563da9dcf87 b
124 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
124 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
125 +++ b/b Thu Jan 01 00:00:00 1970 +0000
125 +++ b/b Thu Jan 01 00:00:00 1970 +0000
126 @@ -0,0 +1,1 @@
126 @@ -0,0 +1,1 @@
127 +b
127 +b
128
128
129 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -E errors.log
129 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -E errors.log
130 $ cat hg.pid >> $DAEMON_PIDS
130 $ cat hg.pid >> $DAEMON_PIDS
131
131
132 tip - two revisions
132 tip - two revisions
133
133
134 $ (get-with-headers.py localhost:$HGPORT 'log/tip/a')
134 $ (get-with-headers.py localhost:$HGPORT 'log/tip/a')
135 200 Script output follows
135 200 Script output follows
136
136
137 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
137 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
138 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
138 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
139 <head>
139 <head>
140 <link rel="icon" href="/static/hgicon.png" type="image/png" />
140 <link rel="icon" href="/static/hgicon.png" type="image/png" />
141 <meta name="robots" content="index, nofollow" />
141 <meta name="robots" content="index, nofollow" />
142 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
142 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
143 <script type="text/javascript" src="/static/mercurial.js"></script>
143 <script type="text/javascript" src="/static/mercurial.js"></script>
144
144
145 <title>test: a history</title>
145 <title>test: a history</title>
146 <link rel="alternate" type="application/atom+xml"
146 <link rel="alternate" type="application/atom+xml"
147 href="/atom-log/tip/a" title="Atom feed for test:a" />
147 href="/atom-log/tip/a" title="Atom feed for test:a" />
148 <link rel="alternate" type="application/rss+xml"
148 <link rel="alternate" type="application/rss+xml"
149 href="/rss-log/tip/a" title="RSS feed for test:a" />
149 href="/rss-log/tip/a" title="RSS feed for test:a" />
150 </head>
150 </head>
151 <body>
151 <body>
152
152
153 <div class="container">
153 <div class="container">
154 <div class="menu">
154 <div class="menu">
155 <div class="logo">
155 <div class="logo">
156 <a href="https://mercurial-scm.org/">
156 <a href="https://mercurial-scm.org/">
157 <img src="/static/hglogo.png" alt="mercurial" /></a>
157 <img src="/static/hglogo.png" alt="mercurial" /></a>
158 </div>
158 </div>
159 <ul>
159 <ul>
160 <li><a href="/shortlog/tip">log</a></li>
160 <li><a href="/shortlog/tip">log</a></li>
161 <li><a href="/graph/tip">graph</a></li>
161 <li><a href="/graph/tip">graph</a></li>
162 <li><a href="/tags">tags</a></li>
162 <li><a href="/tags">tags</a></li>
163 <li><a href="/bookmarks">bookmarks</a></li>
163 <li><a href="/bookmarks">bookmarks</a></li>
164 <li><a href="/branches">branches</a></li>
164 <li><a href="/branches">branches</a></li>
165 </ul>
165 </ul>
166 <ul>
166 <ul>
167 <li><a href="/rev/tip">changeset</a></li>
167 <li><a href="/rev/tip">changeset</a></li>
168 <li><a href="/file/tip">browse</a></li>
168 <li><a href="/file/tip">browse</a></li>
169 </ul>
169 </ul>
170 <ul>
170 <ul>
171 <li><a href="/file/tip/a">file</a></li>
171 <li><a href="/file/tip/a">file</a></li>
172 <li><a href="/diff/tip/a">diff</a></li>
172 <li><a href="/diff/tip/a">diff</a></li>
173 <li><a href="/comparison/tip/a">comparison</a></li>
173 <li><a href="/comparison/tip/a">comparison</a></li>
174 <li><a href="/annotate/tip/a">annotate</a></li>
174 <li><a href="/annotate/tip/a">annotate</a></li>
175 <li class="active">file log</li>
175 <li class="active">file log</li>
176 <li><a href="/raw-file/tip/a">raw</a></li>
176 <li><a href="/raw-file/tip/a">raw</a></li>
177 </ul>
177 </ul>
178 <ul>
178 <ul>
179 <li><a href="/help">help</a></li>
179 <li><a href="/help">help</a></li>
180 </ul>
180 </ul>
181 <div class="atom-logo">
181 <div class="atom-logo">
182 <a href="/atom-log/tip/a" title="subscribe to atom feed">
182 <a href="/atom-log/tip/a" title="subscribe to atom feed">
183 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="atom feed" />
183 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="atom feed" />
184 </a>
184 </a>
185 </div>
185 </div>
186 </div>
186 </div>
187
187
188 <div class="main">
188 <div class="main">
189 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
189 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
190 <h3>
190 <h3>
191 log a @ 4:<a href="/rev/3f41bc784e7e">3f41bc784e7e</a>
191 log a @ 4:<a href="/rev/3f41bc784e7e">3f41bc784e7e</a>
192 <span class="branchname">a-branch</span>
192 <span class="branchname">a-branch</span>
193
193
194 </h3>
194 </h3>
195
195
196 <form class="search" action="/log">
196 <form class="search" action="/log">
197
197
198 <p><input name="rev" id="search1" type="text" size="30" /></p>
198 <p><input name="rev" id="search1" type="text" size="30" /></p>
199 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
199 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
200 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
200 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
201 </form>
201 </form>
202
202
203 <div class="navigate">
203 <div class="navigate">
204 <a href="/log/tip/a?revcount=30">less</a>
204 <a href="/log/tip/a?revcount=30">less</a>
205 <a href="/log/tip/a?revcount=120">more</a>
205 <a href="/log/tip/a?revcount=120">more</a>
206 | <a href="/log/5ed941583260/a">(0)</a> <a href="/log/tip/a">tip</a> </div>
206 | <a href="/log/5ed941583260/a">(0)</a> <a href="/log/tip/a">tip</a> </div>
207
207
208 <table class="bigtable">
208 <table class="bigtable">
209 <thead>
209 <thead>
210 <tr>
210 <tr>
211 <th class="age">age</th>
211 <th class="age">age</th>
212 <th class="author">author</th>
212 <th class="author">author</th>
213 <th class="description">description</th>
213 <th class="description">description</th>
214 </tr>
214 </tr>
215 </thead>
215 </thead>
216 <tbody class="stripes2">
216 <tbody class="stripes2">
217 <tr>
217 <tr>
218 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
218 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
219 <td class="author">test</td>
219 <td class="author">test</td>
220 <td class="description">
220 <td class="description">
221 <a href="/rev/3f41bc784e7e">second a</a>
221 <a href="/rev/3f41bc784e7e">second a</a>
222 <span class="branchname">a-branch</span>
222 <span class="branchname">a-branch</span>
223 </td>
223 </td>
224 </tr>
224 </tr>
225
225
226 <tr>
226 <tr>
227 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
227 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
228 <td class="author">test</td>
228 <td class="author">test</td>
229 <td class="description">
229 <td class="description">
230 <a href="/rev/5ed941583260">first a</a>
230 <a href="/rev/5ed941583260">first a</a>
231 <span class="tag">a-tag</span> <span class="tag">a-bookmark</span>
231 <span class="tag">a-tag</span> <span class="tag">a-bookmark</span>
232 </td>
232 </td>
233 </tr>
233 </tr>
234
234
235
235
236 </tbody>
236 </tbody>
237 </table>
237 </table>
238
238
239 <div class="navigate">
239 <div class="navigate">
240 <a href="/log/tip/a?revcount=30">less</a>
240 <a href="/log/tip/a?revcount=30">less</a>
241 <a href="/log/tip/a?revcount=120">more</a>
241 <a href="/log/tip/a?revcount=120">more</a>
242 | <a href="/log/5ed941583260/a">(0)</a> <a href="/log/tip/a">tip</a>
242 | <a href="/log/5ed941583260/a">(0)</a> <a href="/log/tip/a">tip</a>
243 </div>
243 </div>
244
244
245 </div>
245 </div>
246 </div>
246 </div>
247
247
248
248
249
249
250 </body>
250 </body>
251 </html>
251 </html>
252
252
253
253
254 second version - two revisions
254 second version - two revisions
255
255
256 $ (get-with-headers.py localhost:$HGPORT 'log/4/a')
256 $ (get-with-headers.py localhost:$HGPORT 'log/4/a')
257 200 Script output follows
257 200 Script output follows
258
258
259 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
259 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
260 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
260 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
261 <head>
261 <head>
262 <link rel="icon" href="/static/hgicon.png" type="image/png" />
262 <link rel="icon" href="/static/hgicon.png" type="image/png" />
263 <meta name="robots" content="index, nofollow" />
263 <meta name="robots" content="index, nofollow" />
264 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
264 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
265 <script type="text/javascript" src="/static/mercurial.js"></script>
265 <script type="text/javascript" src="/static/mercurial.js"></script>
266
266
267 <title>test: a history</title>
267 <title>test: a history</title>
268 <link rel="alternate" type="application/atom+xml"
268 <link rel="alternate" type="application/atom+xml"
269 href="/atom-log/tip/a" title="Atom feed for test:a" />
269 href="/atom-log/tip/a" title="Atom feed for test:a" />
270 <link rel="alternate" type="application/rss+xml"
270 <link rel="alternate" type="application/rss+xml"
271 href="/rss-log/tip/a" title="RSS feed for test:a" />
271 href="/rss-log/tip/a" title="RSS feed for test:a" />
272 </head>
272 </head>
273 <body>
273 <body>
274
274
275 <div class="container">
275 <div class="container">
276 <div class="menu">
276 <div class="menu">
277 <div class="logo">
277 <div class="logo">
278 <a href="https://mercurial-scm.org/">
278 <a href="https://mercurial-scm.org/">
279 <img src="/static/hglogo.png" alt="mercurial" /></a>
279 <img src="/static/hglogo.png" alt="mercurial" /></a>
280 </div>
280 </div>
281 <ul>
281 <ul>
282 <li><a href="/shortlog/4">log</a></li>
282 <li><a href="/shortlog/4">log</a></li>
283 <li><a href="/graph/4">graph</a></li>
283 <li><a href="/graph/4">graph</a></li>
284 <li><a href="/tags">tags</a></li>
284 <li><a href="/tags">tags</a></li>
285 <li><a href="/bookmarks">bookmarks</a></li>
285 <li><a href="/bookmarks">bookmarks</a></li>
286 <li><a href="/branches">branches</a></li>
286 <li><a href="/branches">branches</a></li>
287 </ul>
287 </ul>
288 <ul>
288 <ul>
289 <li><a href="/rev/4">changeset</a></li>
289 <li><a href="/rev/4">changeset</a></li>
290 <li><a href="/file/4">browse</a></li>
290 <li><a href="/file/4">browse</a></li>
291 </ul>
291 </ul>
292 <ul>
292 <ul>
293 <li><a href="/file/4/a">file</a></li>
293 <li><a href="/file/4/a">file</a></li>
294 <li><a href="/diff/4/a">diff</a></li>
294 <li><a href="/diff/4/a">diff</a></li>
295 <li><a href="/comparison/4/a">comparison</a></li>
295 <li><a href="/comparison/4/a">comparison</a></li>
296 <li><a href="/annotate/4/a">annotate</a></li>
296 <li><a href="/annotate/4/a">annotate</a></li>
297 <li class="active">file log</li>
297 <li class="active">file log</li>
298 <li><a href="/raw-file/4/a">raw</a></li>
298 <li><a href="/raw-file/4/a">raw</a></li>
299 </ul>
299 </ul>
300 <ul>
300 <ul>
301 <li><a href="/help">help</a></li>
301 <li><a href="/help">help</a></li>
302 </ul>
302 </ul>
303 <div class="atom-logo">
303 <div class="atom-logo">
304 <a href="/atom-log/tip/a" title="subscribe to atom feed">
304 <a href="/atom-log/tip/a" title="subscribe to atom feed">
305 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="atom feed" />
305 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="atom feed" />
306 </a>
306 </a>
307 </div>
307 </div>
308 </div>
308 </div>
309
309
310 <div class="main">
310 <div class="main">
311 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
311 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
312 <h3>
312 <h3>
313 log a @ 4:<a href="/rev/3f41bc784e7e">3f41bc784e7e</a>
313 log a @ 4:<a href="/rev/3f41bc784e7e">3f41bc784e7e</a>
314 <span class="branchname">a-branch</span>
314 <span class="branchname">a-branch</span>
315
315
316 </h3>
316 </h3>
317
317
318 <form class="search" action="/log">
318 <form class="search" action="/log">
319
319
320 <p><input name="rev" id="search1" type="text" size="30" /></p>
320 <p><input name="rev" id="search1" type="text" size="30" /></p>
321 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
321 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
322 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
322 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
323 </form>
323 </form>
324
324
325 <div class="navigate">
325 <div class="navigate">
326 <a href="/log/4/a?revcount=30">less</a>
326 <a href="/log/4/a?revcount=30">less</a>
327 <a href="/log/4/a?revcount=120">more</a>
327 <a href="/log/4/a?revcount=120">more</a>
328 | <a href="/log/5ed941583260/a">(0)</a> <a href="/log/tip/a">tip</a> </div>
328 | <a href="/log/5ed941583260/a">(0)</a> <a href="/log/tip/a">tip</a> </div>
329
329
330 <table class="bigtable">
330 <table class="bigtable">
331 <thead>
331 <thead>
332 <tr>
332 <tr>
333 <th class="age">age</th>
333 <th class="age">age</th>
334 <th class="author">author</th>
334 <th class="author">author</th>
335 <th class="description">description</th>
335 <th class="description">description</th>
336 </tr>
336 </tr>
337 </thead>
337 </thead>
338 <tbody class="stripes2">
338 <tbody class="stripes2">
339 <tr>
339 <tr>
340 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
340 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
341 <td class="author">test</td>
341 <td class="author">test</td>
342 <td class="description">
342 <td class="description">
343 <a href="/rev/3f41bc784e7e">second a</a>
343 <a href="/rev/3f41bc784e7e">second a</a>
344 <span class="branchname">a-branch</span>
344 <span class="branchname">a-branch</span>
345 </td>
345 </td>
346 </tr>
346 </tr>
347
347
348 <tr>
348 <tr>
349 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
349 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
350 <td class="author">test</td>
350 <td class="author">test</td>
351 <td class="description">
351 <td class="description">
352 <a href="/rev/5ed941583260">first a</a>
352 <a href="/rev/5ed941583260">first a</a>
353 <span class="tag">a-tag</span> <span class="tag">a-bookmark</span>
353 <span class="tag">a-tag</span> <span class="tag">a-bookmark</span>
354 </td>
354 </td>
355 </tr>
355 </tr>
356
356
357
357
358 </tbody>
358 </tbody>
359 </table>
359 </table>
360
360
361 <div class="navigate">
361 <div class="navigate">
362 <a href="/log/4/a?revcount=30">less</a>
362 <a href="/log/4/a?revcount=30">less</a>
363 <a href="/log/4/a?revcount=120">more</a>
363 <a href="/log/4/a?revcount=120">more</a>
364 | <a href="/log/5ed941583260/a">(0)</a> <a href="/log/tip/a">tip</a>
364 | <a href="/log/5ed941583260/a">(0)</a> <a href="/log/tip/a">tip</a>
365 </div>
365 </div>
366
366
367 </div>
367 </div>
368 </div>
368 </div>
369
369
370
370
371
371
372 </body>
372 </body>
373 </html>
373 </html>
374
374
375
375
376 first deleted - one revision
376 first deleted - one revision
377
377
378 $ (get-with-headers.py localhost:$HGPORT 'log/3/a')
378 $ (get-with-headers.py localhost:$HGPORT 'log/3/a')
379 200 Script output follows
379 200 Script output follows
380
380
381 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
381 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
382 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
382 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
383 <head>
383 <head>
384 <link rel="icon" href="/static/hgicon.png" type="image/png" />
384 <link rel="icon" href="/static/hgicon.png" type="image/png" />
385 <meta name="robots" content="index, nofollow" />
385 <meta name="robots" content="index, nofollow" />
386 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
386 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
387 <script type="text/javascript" src="/static/mercurial.js"></script>
387 <script type="text/javascript" src="/static/mercurial.js"></script>
388
388
389 <title>test: a history</title>
389 <title>test: a history</title>
390 <link rel="alternate" type="application/atom+xml"
390 <link rel="alternate" type="application/atom+xml"
391 href="/atom-log/tip/a" title="Atom feed for test:a" />
391 href="/atom-log/tip/a" title="Atom feed for test:a" />
392 <link rel="alternate" type="application/rss+xml"
392 <link rel="alternate" type="application/rss+xml"
393 href="/rss-log/tip/a" title="RSS feed for test:a" />
393 href="/rss-log/tip/a" title="RSS feed for test:a" />
394 </head>
394 </head>
395 <body>
395 <body>
396
396
397 <div class="container">
397 <div class="container">
398 <div class="menu">
398 <div class="menu">
399 <div class="logo">
399 <div class="logo">
400 <a href="https://mercurial-scm.org/">
400 <a href="https://mercurial-scm.org/">
401 <img src="/static/hglogo.png" alt="mercurial" /></a>
401 <img src="/static/hglogo.png" alt="mercurial" /></a>
402 </div>
402 </div>
403 <ul>
403 <ul>
404 <li><a href="/shortlog/3">log</a></li>
404 <li><a href="/shortlog/3">log</a></li>
405 <li><a href="/graph/3">graph</a></li>
405 <li><a href="/graph/3">graph</a></li>
406 <li><a href="/tags">tags</a></li>
406 <li><a href="/tags">tags</a></li>
407 <li><a href="/bookmarks">bookmarks</a></li>
407 <li><a href="/bookmarks">bookmarks</a></li>
408 <li><a href="/branches">branches</a></li>
408 <li><a href="/branches">branches</a></li>
409 </ul>
409 </ul>
410 <ul>
410 <ul>
411 <li><a href="/rev/3">changeset</a></li>
411 <li><a href="/rev/3">changeset</a></li>
412 <li><a href="/file/3">browse</a></li>
412 <li><a href="/file/3">browse</a></li>
413 </ul>
413 </ul>
414 <ul>
414 <ul>
415 <li><a href="/file/3/a">file</a></li>
415 <li><a href="/file/3/a">file</a></li>
416 <li><a href="/diff/3/a">diff</a></li>
416 <li><a href="/diff/3/a">diff</a></li>
417 <li><a href="/comparison/3/a">comparison</a></li>
417 <li><a href="/comparison/3/a">comparison</a></li>
418 <li><a href="/annotate/3/a">annotate</a></li>
418 <li><a href="/annotate/3/a">annotate</a></li>
419 <li class="active">file log</li>
419 <li class="active">file log</li>
420 <li><a href="/raw-file/3/a">raw</a></li>
420 <li><a href="/raw-file/3/a">raw</a></li>
421 </ul>
421 </ul>
422 <ul>
422 <ul>
423 <li><a href="/help">help</a></li>
423 <li><a href="/help">help</a></li>
424 </ul>
424 </ul>
425 <div class="atom-logo">
425 <div class="atom-logo">
426 <a href="/atom-log/tip/a" title="subscribe to atom feed">
426 <a href="/atom-log/tip/a" title="subscribe to atom feed">
427 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="atom feed" />
427 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="atom feed" />
428 </a>
428 </a>
429 </div>
429 </div>
430 </div>
430 </div>
431
431
432 <div class="main">
432 <div class="main">
433 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
433 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
434 <h3>
434 <h3>
435 log a @ 1:<a href="/rev/5ed941583260">5ed941583260</a>
435 log a @ 1:<a href="/rev/5ed941583260">5ed941583260</a>
436 <span class="tag">a-tag</span> <span class="tag">a-bookmark</span>
436 <span class="tag">a-tag</span> <span class="tag">a-bookmark</span>
437
437
438 </h3>
438 </h3>
439
439
440 <form class="search" action="/log">
440 <form class="search" action="/log">
441
441
442 <p><input name="rev" id="search1" type="text" size="30" /></p>
442 <p><input name="rev" id="search1" type="text" size="30" /></p>
443 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
443 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
444 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
444 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
445 </form>
445 </form>
446
446
447 <div class="navigate">
447 <div class="navigate">
448 <a href="/log/3/a?revcount=30">less</a>
448 <a href="/log/3/a?revcount=30">less</a>
449 <a href="/log/3/a?revcount=120">more</a>
449 <a href="/log/3/a?revcount=120">more</a>
450 | <a href="/log/5ed941583260/a">(0)</a> <a href="/log/tip/a">tip</a> </div>
450 | <a href="/log/5ed941583260/a">(0)</a> <a href="/log/tip/a">tip</a> </div>
451
451
452 <table class="bigtable">
452 <table class="bigtable">
453 <thead>
453 <thead>
454 <tr>
454 <tr>
455 <th class="age">age</th>
455 <th class="age">age</th>
456 <th class="author">author</th>
456 <th class="author">author</th>
457 <th class="description">description</th>
457 <th class="description">description</th>
458 </tr>
458 </tr>
459 </thead>
459 </thead>
460 <tbody class="stripes2">
460 <tbody class="stripes2">
461 <tr>
461 <tr>
462 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
462 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
463 <td class="author">test</td>
463 <td class="author">test</td>
464 <td class="description">
464 <td class="description">
465 <a href="/rev/5ed941583260">first a</a>
465 <a href="/rev/5ed941583260">first a</a>
466 <span class="tag">a-tag</span> <span class="tag">a-bookmark</span>
466 <span class="tag">a-tag</span> <span class="tag">a-bookmark</span>
467 </td>
467 </td>
468 </tr>
468 </tr>
469
469
470
470
471 </tbody>
471 </tbody>
472 </table>
472 </table>
473
473
474 <div class="navigate">
474 <div class="navigate">
475 <a href="/log/3/a?revcount=30">less</a>
475 <a href="/log/3/a?revcount=30">less</a>
476 <a href="/log/3/a?revcount=120">more</a>
476 <a href="/log/3/a?revcount=120">more</a>
477 | <a href="/log/5ed941583260/a">(0)</a> <a href="/log/tip/a">tip</a>
477 | <a href="/log/5ed941583260/a">(0)</a> <a href="/log/tip/a">tip</a>
478 </div>
478 </div>
479
479
480 </div>
480 </div>
481 </div>
481 </div>
482
482
483
483
484
484
485 </body>
485 </body>
486 </html>
486 </html>
487
487
488
488
489 first version - one revision
489 first version - one revision
490
490
491 $ (get-with-headers.py localhost:$HGPORT 'log/1/a')
491 $ (get-with-headers.py localhost:$HGPORT 'log/1/a')
492 200 Script output follows
492 200 Script output follows
493
493
494 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
494 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
495 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
495 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
496 <head>
496 <head>
497 <link rel="icon" href="/static/hgicon.png" type="image/png" />
497 <link rel="icon" href="/static/hgicon.png" type="image/png" />
498 <meta name="robots" content="index, nofollow" />
498 <meta name="robots" content="index, nofollow" />
499 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
499 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
500 <script type="text/javascript" src="/static/mercurial.js"></script>
500 <script type="text/javascript" src="/static/mercurial.js"></script>
501
501
502 <title>test: a history</title>
502 <title>test: a history</title>
503 <link rel="alternate" type="application/atom+xml"
503 <link rel="alternate" type="application/atom+xml"
504 href="/atom-log/tip/a" title="Atom feed for test:a" />
504 href="/atom-log/tip/a" title="Atom feed for test:a" />
505 <link rel="alternate" type="application/rss+xml"
505 <link rel="alternate" type="application/rss+xml"
506 href="/rss-log/tip/a" title="RSS feed for test:a" />
506 href="/rss-log/tip/a" title="RSS feed for test:a" />
507 </head>
507 </head>
508 <body>
508 <body>
509
509
510 <div class="container">
510 <div class="container">
511 <div class="menu">
511 <div class="menu">
512 <div class="logo">
512 <div class="logo">
513 <a href="https://mercurial-scm.org/">
513 <a href="https://mercurial-scm.org/">
514 <img src="/static/hglogo.png" alt="mercurial" /></a>
514 <img src="/static/hglogo.png" alt="mercurial" /></a>
515 </div>
515 </div>
516 <ul>
516 <ul>
517 <li><a href="/shortlog/1">log</a></li>
517 <li><a href="/shortlog/1">log</a></li>
518 <li><a href="/graph/1">graph</a></li>
518 <li><a href="/graph/1">graph</a></li>
519 <li><a href="/tags">tags</a></li>
519 <li><a href="/tags">tags</a></li>
520 <li><a href="/bookmarks">bookmarks</a></li>
520 <li><a href="/bookmarks">bookmarks</a></li>
521 <li><a href="/branches">branches</a></li>
521 <li><a href="/branches">branches</a></li>
522 </ul>
522 </ul>
523 <ul>
523 <ul>
524 <li><a href="/rev/1">changeset</a></li>
524 <li><a href="/rev/1">changeset</a></li>
525 <li><a href="/file/1">browse</a></li>
525 <li><a href="/file/1">browse</a></li>
526 </ul>
526 </ul>
527 <ul>
527 <ul>
528 <li><a href="/file/1/a">file</a></li>
528 <li><a href="/file/1/a">file</a></li>
529 <li><a href="/diff/1/a">diff</a></li>
529 <li><a href="/diff/1/a">diff</a></li>
530 <li><a href="/comparison/1/a">comparison</a></li>
530 <li><a href="/comparison/1/a">comparison</a></li>
531 <li><a href="/annotate/1/a">annotate</a></li>
531 <li><a href="/annotate/1/a">annotate</a></li>
532 <li class="active">file log</li>
532 <li class="active">file log</li>
533 <li><a href="/raw-file/1/a">raw</a></li>
533 <li><a href="/raw-file/1/a">raw</a></li>
534 </ul>
534 </ul>
535 <ul>
535 <ul>
536 <li><a href="/help">help</a></li>
536 <li><a href="/help">help</a></li>
537 </ul>
537 </ul>
538 <div class="atom-logo">
538 <div class="atom-logo">
539 <a href="/atom-log/tip/a" title="subscribe to atom feed">
539 <a href="/atom-log/tip/a" title="subscribe to atom feed">
540 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="atom feed" />
540 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="atom feed" />
541 </a>
541 </a>
542 </div>
542 </div>
543 </div>
543 </div>
544
544
545 <div class="main">
545 <div class="main">
546 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
546 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
547 <h3>
547 <h3>
548 log a @ 1:<a href="/rev/5ed941583260">5ed941583260</a>
548 log a @ 1:<a href="/rev/5ed941583260">5ed941583260</a>
549 <span class="tag">a-tag</span> <span class="tag">a-bookmark</span>
549 <span class="tag">a-tag</span> <span class="tag">a-bookmark</span>
550
550
551 </h3>
551 </h3>
552
552
553 <form class="search" action="/log">
553 <form class="search" action="/log">
554
554
555 <p><input name="rev" id="search1" type="text" size="30" /></p>
555 <p><input name="rev" id="search1" type="text" size="30" /></p>
556 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
556 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
557 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
557 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
558 </form>
558 </form>
559
559
560 <div class="navigate">
560 <div class="navigate">
561 <a href="/log/1/a?revcount=30">less</a>
561 <a href="/log/1/a?revcount=30">less</a>
562 <a href="/log/1/a?revcount=120">more</a>
562 <a href="/log/1/a?revcount=120">more</a>
563 | <a href="/log/5ed941583260/a">(0)</a> <a href="/log/tip/a">tip</a> </div>
563 | <a href="/log/5ed941583260/a">(0)</a> <a href="/log/tip/a">tip</a> </div>
564
564
565 <table class="bigtable">
565 <table class="bigtable">
566 <thead>
566 <thead>
567 <tr>
567 <tr>
568 <th class="age">age</th>
568 <th class="age">age</th>
569 <th class="author">author</th>
569 <th class="author">author</th>
570 <th class="description">description</th>
570 <th class="description">description</th>
571 </tr>
571 </tr>
572 </thead>
572 </thead>
573 <tbody class="stripes2">
573 <tbody class="stripes2">
574 <tr>
574 <tr>
575 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
575 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
576 <td class="author">test</td>
576 <td class="author">test</td>
577 <td class="description">
577 <td class="description">
578 <a href="/rev/5ed941583260">first a</a>
578 <a href="/rev/5ed941583260">first a</a>
579 <span class="tag">a-tag</span> <span class="tag">a-bookmark</span>
579 <span class="tag">a-tag</span> <span class="tag">a-bookmark</span>
580 </td>
580 </td>
581 </tr>
581 </tr>
582
582
583
583
584 </tbody>
584 </tbody>
585 </table>
585 </table>
586
586
587 <div class="navigate">
587 <div class="navigate">
588 <a href="/log/1/a?revcount=30">less</a>
588 <a href="/log/1/a?revcount=30">less</a>
589 <a href="/log/1/a?revcount=120">more</a>
589 <a href="/log/1/a?revcount=120">more</a>
590 | <a href="/log/5ed941583260/a">(0)</a> <a href="/log/tip/a">tip</a>
590 | <a href="/log/5ed941583260/a">(0)</a> <a href="/log/tip/a">tip</a>
591 </div>
591 </div>
592
592
593 </div>
593 </div>
594 </div>
594 </div>
595
595
596
596
597
597
598 </body>
598 </body>
599 </html>
599 </html>
600
600
601
601
602 before addition - error
602 before addition - error
603
603
604 $ (get-with-headers.py localhost:$HGPORT 'log/0/a')
604 $ (get-with-headers.py localhost:$HGPORT 'log/0/a')
605 404 Not Found
605 404 Not Found
606
606
607 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
607 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
608 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
608 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
609 <head>
609 <head>
610 <link rel="icon" href="/static/hgicon.png" type="image/png" />
610 <link rel="icon" href="/static/hgicon.png" type="image/png" />
611 <meta name="robots" content="index, nofollow" />
611 <meta name="robots" content="index, nofollow" />
612 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
612 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
613 <script type="text/javascript" src="/static/mercurial.js"></script>
613 <script type="text/javascript" src="/static/mercurial.js"></script>
614
614
615 <title>test: error</title>
615 <title>test: error</title>
616 </head>
616 </head>
617 <body>
617 <body>
618
618
619 <div class="container">
619 <div class="container">
620 <div class="menu">
620 <div class="menu">
621 <div class="logo">
621 <div class="logo">
622 <a href="https://mercurial-scm.org/">
622 <a href="https://mercurial-scm.org/">
623 <img src="/static/hglogo.png" width=75 height=90 border=0 alt="mercurial" /></a>
623 <img src="/static/hglogo.png" width=75 height=90 border=0 alt="mercurial" /></a>
624 </div>
624 </div>
625 <ul>
625 <ul>
626 <li><a href="/shortlog">log</a></li>
626 <li><a href="/shortlog">log</a></li>
627 <li><a href="/graph">graph</a></li>
627 <li><a href="/graph">graph</a></li>
628 <li><a href="/tags">tags</a></li>
628 <li><a href="/tags">tags</a></li>
629 <li><a href="/bookmarks">bookmarks</a></li>
629 <li><a href="/bookmarks">bookmarks</a></li>
630 <li><a href="/branches">branches</a></li>
630 <li><a href="/branches">branches</a></li>
631 </ul>
631 </ul>
632 <ul>
632 <ul>
633 <li><a href="/help">help</a></li>
633 <li><a href="/help">help</a></li>
634 </ul>
634 </ul>
635 </div>
635 </div>
636
636
637 <div class="main">
637 <div class="main">
638
638
639 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
639 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
640 <h3>error</h3>
640 <h3>error</h3>
641
641
642 <form class="search" action="/log">
642 <form class="search" action="/log">
643
643
644 <p><input name="rev" id="search1" type="text" size="30"></p>
644 <p><input name="rev" id="search1" type="text" size="30"></p>
645 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
645 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
646 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
646 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
647 </form>
647 </form>
648
648
649 <div class="description">
649 <div class="description">
650 <p>
650 <p>
651 An error occurred while processing your request:
651 An error occurred while processing your request:
652 </p>
652 </p>
653 <p>
653 <p>
654 a@6563da9dcf87: not found in manifest
654 a@6563da9dcf87: not found in manifest
655 </p>
655 </p>
656 </div>
656 </div>
657 </div>
657 </div>
658 </div>
658 </div>
659
659
660
660
661
661
662 </body>
662 </body>
663 </html>
663 </html>
664
664
665 [1]
665 [1]
666
666
667 $ hg log -r 'followlines(c, 1:2, startrev=tip) and follow(c)'
667 $ hg log -r 'followlines(c, 1:2, startrev=tip) and follow(c)'
668 changeset: 0:6563da9dcf87
668 changeset: 0:6563da9dcf87
669 user: test
669 user: test
670 date: Thu Jan 01 00:00:00 1970 +0000
670 date: Thu Jan 01 00:00:00 1970 +0000
671 summary: b
671 summary: b
672
672
673 changeset: 7:46c1a66bd8fc
673 changeset: 7:46c1a66bd8fc
674 branch: a-branch
674 branch: a-branch
675 tag: tip
675 tag: tip
676 user: test
676 user: test
677 date: Thu Jan 01 00:00:00 1970 +0000
677 date: Thu Jan 01 00:00:00 1970 +0000
678 summary: change c
678 summary: change c
679
679
680 $ (get-with-headers.py localhost:$HGPORT 'log/tip/c?linerange=1:2')
680 $ (get-with-headers.py localhost:$HGPORT 'log/tip/c?linerange=1:2')
681 200 Script output follows
681 200 Script output follows
682
682
683 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
683 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
684 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
684 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
685 <head>
685 <head>
686 <link rel="icon" href="/static/hgicon.png" type="image/png" />
686 <link rel="icon" href="/static/hgicon.png" type="image/png" />
687 <meta name="robots" content="index, nofollow" />
687 <meta name="robots" content="index, nofollow" />
688 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
688 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
689 <script type="text/javascript" src="/static/mercurial.js"></script>
689 <script type="text/javascript" src="/static/mercurial.js"></script>
690
690
691 <title>test: c history</title>
691 <title>test: c history</title>
692 <link rel="alternate" type="application/atom+xml"
692 <link rel="alternate" type="application/atom+xml"
693 href="/atom-log/tip/c" title="Atom feed for test:c" />
693 href="/atom-log/tip/c" title="Atom feed for test:c" />
694 <link rel="alternate" type="application/rss+xml"
694 <link rel="alternate" type="application/rss+xml"
695 href="/rss-log/tip/c" title="RSS feed for test:c" />
695 href="/rss-log/tip/c" title="RSS feed for test:c" />
696 </head>
696 </head>
697 <body>
697 <body>
698
698
699 <div class="container">
699 <div class="container">
700 <div class="menu">
700 <div class="menu">
701 <div class="logo">
701 <div class="logo">
702 <a href="https://mercurial-scm.org/">
702 <a href="https://mercurial-scm.org/">
703 <img src="/static/hglogo.png" alt="mercurial" /></a>
703 <img src="/static/hglogo.png" alt="mercurial" /></a>
704 </div>
704 </div>
705 <ul>
705 <ul>
706 <li><a href="/shortlog/tip">log</a></li>
706 <li><a href="/shortlog/tip">log</a></li>
707 <li><a href="/graph/tip">graph</a></li>
707 <li><a href="/graph/tip">graph</a></li>
708 <li><a href="/tags">tags</a></li>
708 <li><a href="/tags">tags</a></li>
709 <li><a href="/bookmarks">bookmarks</a></li>
709 <li><a href="/bookmarks">bookmarks</a></li>
710 <li><a href="/branches">branches</a></li>
710 <li><a href="/branches">branches</a></li>
711 </ul>
711 </ul>
712 <ul>
712 <ul>
713 <li><a href="/rev/tip">changeset</a></li>
713 <li><a href="/rev/tip">changeset</a></li>
714 <li><a href="/file/tip">browse</a></li>
714 <li><a href="/file/tip">browse</a></li>
715 </ul>
715 </ul>
716 <ul>
716 <ul>
717 <li><a href="/file/tip/c">file</a></li>
717 <li><a href="/file/tip/c">file</a></li>
718 <li><a href="/diff/tip/c">diff</a></li>
718 <li><a href="/diff/tip/c">diff</a></li>
719 <li><a href="/comparison/tip/c">comparison</a></li>
719 <li><a href="/comparison/tip/c">comparison</a></li>
720 <li><a href="/annotate/tip/c">annotate</a></li>
720 <li><a href="/annotate/tip/c">annotate</a></li>
721 <li class="active">file log</li>
721 <li class="active">file log</li>
722 <li><a href="/raw-file/tip/c">raw</a></li>
722 <li><a href="/raw-file/tip/c">raw</a></li>
723 </ul>
723 </ul>
724 <ul>
724 <ul>
725 <li><a href="/help">help</a></li>
725 <li><a href="/help">help</a></li>
726 </ul>
726 </ul>
727 <div class="atom-logo">
727 <div class="atom-logo">
728 <a href="/atom-log/tip/c" title="subscribe to atom feed">
728 <a href="/atom-log/tip/c" title="subscribe to atom feed">
729 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="atom feed" />
729 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="atom feed" />
730 </a>
730 </a>
731 </div>
731 </div>
732 </div>
732 </div>
733
733
734 <div class="main">
734 <div class="main">
735 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
735 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
736 <h3>
736 <h3>
737 log c @ 7:<a href="/rev/46c1a66bd8fc">46c1a66bd8fc</a>
737 log c @ 7:<a href="/rev/46c1a66bd8fc">46c1a66bd8fc</a>
738 <span class="branchname">a-branch</span> <span class="tag">tip</span>
738 <span class="branchname">a-branch</span> <span class="tag">tip</span>
739 (following lines 1:2 <a href="/log/tip/c">back to filelog</a>)
739 (following lines 1:2 <a href="/log/tip/c">back to filelog</a>)
740 </h3>
740 </h3>
741
741
742 <form class="search" action="/log">
742 <form class="search" action="/log">
743
743
744 <p><input name="rev" id="search1" type="text" size="30" /></p>
744 <p><input name="rev" id="search1" type="text" size="30" /></p>
745 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
745 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
746 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
746 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
747 </form>
747 </form>
748
748
749 <div class="navigate">
749 <div class="navigate">
750 <a href="/log/tip/c?linerange=1%3A2&revcount=30">less</a>
750 <a href="/log/tip/c?linerange=1%3A2&revcount=30">less</a>
751 <a href="/log/tip/c?linerange=1%3A2&revcount=120">more</a>
751 <a href="/log/tip/c?linerange=1%3A2&revcount=120">more</a>
752 | </div>
752 | </div>
753
753
754 <table class="bigtable">
754 <table class="bigtable">
755 <thead>
755 <thead>
756 <tr>
756 <tr>
757 <th class="age">age</th>
757 <th class="age">age</th>
758 <th class="author">author</th>
758 <th class="author">author</th>
759 <th class="description">description</th>
759 <th class="description">description</th>
760 </tr>
760 </tr>
761 </thead>
761 </thead>
762 <tbody class="stripes2">
762 <tbody class="stripes2">
763 <tr>
763 <tr>
764 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
764 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
765 <td class="author">test</td>
765 <td class="author">test</td>
766 <td class="description">
766 <td class="description">
767 <a href="/rev/46c1a66bd8fc">change c</a>
767 <a href="/rev/46c1a66bd8fc">change c</a>
768 <span class="branchhead">a-branch</span> <span class="tag">tip</span>
768 <span class="branchhead">a-branch</span> <span class="tag">tip</span>
769 </td>
769 </td>
770 </tr>
770 </tr>
771
771
772 <tr>
772 <tr>
773 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
773 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
774 <td class="author">test</td>
774 <td class="author">test</td>
775 <td class="description">
775 <td class="description">
776 <a href="/rev/6563da9dcf87">b</a>
776 <a href="/rev/6563da9dcf87">b</a>
777
777
778 </td>
778 </td>
779 </tr>
779 </tr>
780
780
781
781
782 </tbody>
782 </tbody>
783 </table>
783 </table>
784
784
785 <div class="navigate">
785 <div class="navigate">
786 <a href="/log/tip/c?linerange=1%3A2&revcount=30">less</a>
786 <a href="/log/tip/c?linerange=1%3A2&revcount=30">less</a>
787 <a href="/log/tip/c?linerange=1%3A2&revcount=120">more</a>
787 <a href="/log/tip/c?linerange=1%3A2&revcount=120">more</a>
788 |
788 |
789 </div>
789 </div>
790
790
791 </div>
791 </div>
792 </div>
792 </div>
793
793
794
794
795
795
796 </body>
796 </body>
797 </html>
797 </html>
798
798
799 $ (get-with-headers.py localhost:$HGPORT 'log/tip/c?linerange=1%3A2&revcount=1')
799 $ (get-with-headers.py localhost:$HGPORT 'log/tip/c?linerange=1%3A2&revcount=1')
800 200 Script output follows
800 200 Script output follows
801
801
802 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
802 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
803 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
803 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
804 <head>
804 <head>
805 <link rel="icon" href="/static/hgicon.png" type="image/png" />
805 <link rel="icon" href="/static/hgicon.png" type="image/png" />
806 <meta name="robots" content="index, nofollow" />
806 <meta name="robots" content="index, nofollow" />
807 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
807 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
808 <script type="text/javascript" src="/static/mercurial.js"></script>
808 <script type="text/javascript" src="/static/mercurial.js"></script>
809
809
810 <title>test: c history</title>
810 <title>test: c history</title>
811 <link rel="alternate" type="application/atom+xml"
811 <link rel="alternate" type="application/atom+xml"
812 href="/atom-log/tip/c" title="Atom feed for test:c" />
812 href="/atom-log/tip/c" title="Atom feed for test:c" />
813 <link rel="alternate" type="application/rss+xml"
813 <link rel="alternate" type="application/rss+xml"
814 href="/rss-log/tip/c" title="RSS feed for test:c" />
814 href="/rss-log/tip/c" title="RSS feed for test:c" />
815 </head>
815 </head>
816 <body>
816 <body>
817
817
818 <div class="container">
818 <div class="container">
819 <div class="menu">
819 <div class="menu">
820 <div class="logo">
820 <div class="logo">
821 <a href="https://mercurial-scm.org/">
821 <a href="https://mercurial-scm.org/">
822 <img src="/static/hglogo.png" alt="mercurial" /></a>
822 <img src="/static/hglogo.png" alt="mercurial" /></a>
823 </div>
823 </div>
824 <ul>
824 <ul>
825 <li><a href="/shortlog/tip?revcount=1">log</a></li>
825 <li><a href="/shortlog/tip?revcount=1">log</a></li>
826 <li><a href="/graph/tip?revcount=1">graph</a></li>
826 <li><a href="/graph/tip?revcount=1">graph</a></li>
827 <li><a href="/tags?revcount=1">tags</a></li>
827 <li><a href="/tags?revcount=1">tags</a></li>
828 <li><a href="/bookmarks?revcount=1">bookmarks</a></li>
828 <li><a href="/bookmarks?revcount=1">bookmarks</a></li>
829 <li><a href="/branches?revcount=1">branches</a></li>
829 <li><a href="/branches?revcount=1">branches</a></li>
830 </ul>
830 </ul>
831 <ul>
831 <ul>
832 <li><a href="/rev/tip?revcount=1">changeset</a></li>
832 <li><a href="/rev/tip?revcount=1">changeset</a></li>
833 <li><a href="/file/tip?revcount=1">browse</a></li>
833 <li><a href="/file/tip?revcount=1">browse</a></li>
834 </ul>
834 </ul>
835 <ul>
835 <ul>
836 <li><a href="/file/tip/c?revcount=1">file</a></li>
836 <li><a href="/file/tip/c?revcount=1">file</a></li>
837 <li><a href="/diff/tip/c?revcount=1">diff</a></li>
837 <li><a href="/diff/tip/c?revcount=1">diff</a></li>
838 <li><a href="/comparison/tip/c?revcount=1">comparison</a></li>
838 <li><a href="/comparison/tip/c?revcount=1">comparison</a></li>
839 <li><a href="/annotate/tip/c?revcount=1">annotate</a></li>
839 <li><a href="/annotate/tip/c?revcount=1">annotate</a></li>
840 <li class="active">file log</li>
840 <li class="active">file log</li>
841 <li><a href="/raw-file/tip/c">raw</a></li>
841 <li><a href="/raw-file/tip/c">raw</a></li>
842 </ul>
842 </ul>
843 <ul>
843 <ul>
844 <li><a href="/help?revcount=1">help</a></li>
844 <li><a href="/help?revcount=1">help</a></li>
845 </ul>
845 </ul>
846 <div class="atom-logo">
846 <div class="atom-logo">
847 <a href="/atom-log/tip/c" title="subscribe to atom feed">
847 <a href="/atom-log/tip/c" title="subscribe to atom feed">
848 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="atom feed" />
848 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="atom feed" />
849 </a>
849 </a>
850 </div>
850 </div>
851 </div>
851 </div>
852
852
853 <div class="main">
853 <div class="main">
854 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
854 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
855 <h3>
855 <h3>
856 log c @ 7:<a href="/rev/46c1a66bd8fc?revcount=1">46c1a66bd8fc</a>
856 log c @ 7:<a href="/rev/46c1a66bd8fc?revcount=1">46c1a66bd8fc</a>
857 <span class="branchname">a-branch</span> <span class="tag">tip</span>
857 <span class="branchname">a-branch</span> <span class="tag">tip</span>
858 (following lines 1:2 <a href="/log/tip/c?revcount=1">back to filelog</a>)
858 (following lines 1:2 <a href="/log/tip/c?revcount=1">back to filelog</a>)
859 </h3>
859 </h3>
860
860
861 <form class="search" action="/log">
861 <form class="search" action="/log">
862 <input type="hidden" name="revcount" value="1" />
862 <input type="hidden" name="revcount" value="1" />
863 <p><input name="rev" id="search1" type="text" size="30" /></p>
863 <p><input name="rev" id="search1" type="text" size="30" /></p>
864 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
864 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
865 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
865 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
866 </form>
866 </form>
867
867
868 <div class="navigate">
868 <div class="navigate">
869 <a href="/log/tip/c?linerange=1%3A2&revcount=1">less</a>
869 <a href="/log/tip/c?linerange=1%3A2&revcount=1">less</a>
870 <a href="/log/tip/c?linerange=1%3A2&revcount=2">more</a>
870 <a href="/log/tip/c?linerange=1%3A2&revcount=2">more</a>
871 | </div>
871 | </div>
872
872
873 <table class="bigtable">
873 <table class="bigtable">
874 <thead>
874 <thead>
875 <tr>
875 <tr>
876 <th class="age">age</th>
876 <th class="age">age</th>
877 <th class="author">author</th>
877 <th class="author">author</th>
878 <th class="description">description</th>
878 <th class="description">description</th>
879 </tr>
879 </tr>
880 </thead>
880 </thead>
881 <tbody class="stripes2">
881 <tbody class="stripes2">
882 <tr>
882 <tr>
883 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
883 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
884 <td class="author">test</td>
884 <td class="author">test</td>
885 <td class="description">
885 <td class="description">
886 <a href="/rev/46c1a66bd8fc?revcount=1">change c</a>
886 <a href="/rev/46c1a66bd8fc?revcount=1">change c</a>
887 <span class="branchhead">a-branch</span> <span class="tag">tip</span>
887 <span class="branchhead">a-branch</span> <span class="tag">tip</span>
888 </td>
888 </td>
889 </tr>
889 </tr>
890
890
891
891
892 </tbody>
892 </tbody>
893 </table>
893 </table>
894
894
895 <div class="navigate">
895 <div class="navigate">
896 <a href="/log/tip/c?linerange=1%3A2&revcount=1">less</a>
896 <a href="/log/tip/c?linerange=1%3A2&revcount=1">less</a>
897 <a href="/log/tip/c?linerange=1%3A2&revcount=2">more</a>
897 <a href="/log/tip/c?linerange=1%3A2&revcount=2">more</a>
898 |
898 |
899 </div>
899 </div>
900
900
901 </div>
901 </div>
902 </div>
902 </div>
903
903
904
904
905
905
906 </body>
906 </body>
907 </html>
907 </html>
908
908
909 $ (get-with-headers.py localhost:$HGPORT 'log/3/a?linerange=1' --headeronly)
909 $ (get-with-headers.py localhost:$HGPORT 'log/3/a?linerange=1' --headeronly)
910 400 invalid linerange parameter
910 400 invalid linerange parameter
911 [1]
911 [1]
912 $ (get-with-headers.py localhost:$HGPORT 'log/3/a?linerange=1:a' --headeronly)
912 $ (get-with-headers.py localhost:$HGPORT 'log/3/a?linerange=1:a' --headeronly)
913 400 invalid linerange parameter
913 400 invalid linerange parameter
914 [1]
914 [1]
915 $ (get-with-headers.py localhost:$HGPORT 'log/3/a?linerange=1:2&linerange=3:4' --headeronly)
915 $ (get-with-headers.py localhost:$HGPORT 'log/3/a?linerange=1:2&linerange=3:4' --headeronly)
916 400 redundant linerange parameter
916 400 redundant linerange parameter
917 [1]
917 [1]
918 $ (get-with-headers.py localhost:$HGPORT 'log/3/a?linerange=3:2' --headeronly)
918 $ (get-with-headers.py localhost:$HGPORT 'log/3/a?linerange=3:2' --headeronly)
919 400 line range must be positive
919 400 line range must be positive
920 [1]
920 [1]
921 $ (get-with-headers.py localhost:$HGPORT 'log/3/a?linerange=0:1' --headeronly)
921 $ (get-with-headers.py localhost:$HGPORT 'log/3/a?linerange=0:1' --headeronly)
922 400 fromline must be strictly positive
922 400 fromline must be strictly positive
923 [1]
923 [1]
924
924
925 should show base link, use spartan because it shows it
925 should show base link, use spartan because it shows it
926
926
927 $ (get-with-headers.py localhost:$HGPORT 'log/tip/c?style=spartan')
927 $ (get-with-headers.py localhost:$HGPORT 'log/tip/c?style=spartan')
928 200 Script output follows
928 200 Script output follows
929
929
930 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
930 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
931 <html>
931 <html>
932 <head>
932 <head>
933 <link rel="icon" href="/static/hgicon.png" type="image/png">
933 <link rel="icon" href="/static/hgicon.png" type="image/png">
934 <meta name="robots" content="index, nofollow" />
934 <meta name="robots" content="index, nofollow" />
935 <link rel="stylesheet" href="/static/style.css" type="text/css" />
935 <link rel="stylesheet" href="/static/style.css" type="text/css" />
936 <script type="text/javascript" src="/static/mercurial.js"></script>
936 <script type="text/javascript" src="/static/mercurial.js"></script>
937
937
938 <title>test: c history</title>
938 <title>test: c history</title>
939 <link rel="alternate" type="application/atom+xml"
939 <link rel="alternate" type="application/atom+xml"
940 href="/atom-log/tip/c" title="Atom feed for test:c">
940 href="/atom-log/tip/c" title="Atom feed for test:c">
941 <link rel="alternate" type="application/rss+xml"
941 <link rel="alternate" type="application/rss+xml"
942 href="/rss-log/tip/c" title="RSS feed for test:c">
942 href="/rss-log/tip/c" title="RSS feed for test:c">
943 </head>
943 </head>
944 <body>
944 <body>
945
945
946 <div class="buttons">
946 <div class="buttons">
947 <a href="/log?style=spartan">changelog</a>
947 <a href="/log?style=spartan">changelog</a>
948 <a href="/shortlog?style=spartan">shortlog</a>
948 <a href="/shortlog?style=spartan">shortlog</a>
949 <a href="/graph?style=spartan">graph</a>
949 <a href="/graph?style=spartan">graph</a>
950 <a href="/tags?style=spartan">tags</a>
950 <a href="/tags?style=spartan">tags</a>
951 <a href="/branches?style=spartan">branches</a>
951 <a href="/branches?style=spartan">branches</a>
952 <a href="/file/tip/c?style=spartan">file</a>
952 <a href="/file/tip/c?style=spartan">file</a>
953 <a href="/annotate/tip/c?style=spartan">annotate</a>
953 <a href="/annotate/tip/c?style=spartan">annotate</a>
954 <a href="/help?style=spartan">help</a>
954 <a href="/help?style=spartan">help</a>
955 <a type="application/rss+xml" href="/rss-log/tip/c">rss</a>
955 <a type="application/rss+xml" href="/rss-log/tip/c">rss</a>
956 <a type="application/atom+xml" href="/atom-log/tip/c" title="Atom feed for test:c">atom</a>
956 <a type="application/atom+xml" href="/atom-log/tip/c" title="Atom feed for test:c">atom</a>
957 </div>
957 </div>
958
958
959 <h2><a href="/">Mercurial</a> / c revision history</h2>
959 <h2><a href="/">Mercurial</a> / c revision history</h2>
960
960
961 <p>navigate: <small class="navigate"><a href="/log/c9637d3cc8ef/c?style=spartan">(0)</a> <a href="/log/tip/c?style=spartan">tip</a> </small></p>
961 <p>navigate: <small class="navigate"><a href="/log/c9637d3cc8ef/c?style=spartan">(0)</a> <a href="/log/tip/c?style=spartan">tip</a> </small></p>
962
962
963 <table class="logEntry parity0">
963 <table class="logEntry parity0">
964 <tr>
964 <tr>
965 <th class="label"><span class="age">Thu, 01 Jan 1970 00:00:00 +0000</span>:</th>
965 <th class="label"><span class="age">Thu, 01 Jan 1970 00:00:00 +0000</span>:</th>
966 <th class="firstline"><a href="/rev/46c1a66bd8fc?style=spartan">change c</a></th>
966 <th class="firstline"><a href="/rev/46c1a66bd8fc?style=spartan">change c</a></th>
967 </tr>
967 </tr>
968 <tr>
968 <tr>
969 <th class="revision">revision 1:</th>
969 <th class="revision">revision 1:</th>
970 <td class="node">
970 <td class="node">
971 <a href="/file/46c1a66bd8fc/c?style=spartan">46c1a66bd8fc</a>
971 <a href="/file/46c1a66bd8fc/c?style=spartan">46c1a66bd8fc</a>
972 <a href="/diff/46c1a66bd8fc/c?style=spartan">(diff)</a>
972 <a href="/diff/46c1a66bd8fc/c?style=spartan">(diff)</a>
973 <a href="/annotate/46c1a66bd8fc/c?style=spartan">(annotate)</a>
973 <a href="/annotate/46c1a66bd8fc/c?style=spartan">(annotate)</a>
974 </td>
974 </td>
975 </tr>
975 </tr>
976
976
977 <tr>
977 <tr>
978 <th class="author">author:</th>
978 <th class="author">author:</th>
979 <td class="author">&#116;&#101;&#115;&#116;</td>
979 <td class="author">&#116;&#101;&#115;&#116;</td>
980 </tr>
980 </tr>
981 <tr>
981 <tr>
982 <th class="date">date:</th>
982 <th class="date">date:</th>
983 <td class="date">Thu, 01 Jan 1970 00:00:00 +0000</td>
983 <td class="date">Thu, 01 Jan 1970 00:00:00 +0000</td>
984 </tr>
984 </tr>
985 </table>
985 </table>
986
986
987
987
988 <table class="logEntry parity1">
988 <table class="logEntry parity1">
989 <tr>
989 <tr>
990 <th class="label"><span class="age">Thu, 01 Jan 1970 00:00:00 +0000</span>:</th>
990 <th class="label"><span class="age">Thu, 01 Jan 1970 00:00:00 +0000</span>:</th>
991 <th class="firstline"><a href="/rev/c9637d3cc8ef?style=spartan">mv b</a></th>
991 <th class="firstline"><a href="/rev/c9637d3cc8ef?style=spartan">mv b</a></th>
992 </tr>
992 </tr>
993 <tr>
993 <tr>
994 <th class="revision">revision 0:</th>
994 <th class="revision">revision 0:</th>
995 <td class="node">
995 <td class="node">
996 <a href="/file/c9637d3cc8ef/c?style=spartan">c9637d3cc8ef</a>
996 <a href="/file/c9637d3cc8ef/c?style=spartan">c9637d3cc8ef</a>
997 <a href="/diff/c9637d3cc8ef/c?style=spartan">(diff)</a>
997 <a href="/diff/c9637d3cc8ef/c?style=spartan">(diff)</a>
998 <a href="/annotate/c9637d3cc8ef/c?style=spartan">(annotate)</a>
998 <a href="/annotate/c9637d3cc8ef/c?style=spartan">(annotate)</a>
999 </td>
999 </td>
1000 </tr>
1000 </tr>
1001
1001
1002 <tr>
1002 <tr>
1003 <th>base:</th>
1003 <th>base:</th>
1004 <td>
1004 <td>
1005 <a href="/file/1e88685f5dde/b?style=spartan">
1005 <a href="/file/1e88685f5dde/b?style=spartan">
1006 b@1e88685f5dde
1006 b@1e88685f5dde
1007 </a>
1007 </a>
1008 </td>
1008 </td>
1009 </tr>
1009 </tr>
1010 <tr>
1010 <tr>
1011 <th class="author">author:</th>
1011 <th class="author">author:</th>
1012 <td class="author">&#116;&#101;&#115;&#116;</td>
1012 <td class="author">&#116;&#101;&#115;&#116;</td>
1013 </tr>
1013 </tr>
1014 <tr>
1014 <tr>
1015 <th class="date">date:</th>
1015 <th class="date">date:</th>
1016 <td class="date">Thu, 01 Jan 1970 00:00:00 +0000</td>
1016 <td class="date">Thu, 01 Jan 1970 00:00:00 +0000</td>
1017 </tr>
1017 </tr>
1018 </table>
1018 </table>
1019
1019
1020
1020
1021
1021
1022
1022
1023
1023
1024 <div class="logo">
1024 <div class="logo">
1025 <a href="https://mercurial-scm.org/">
1025 <a href="https://mercurial-scm.org/">
1026 <img src="/static/hglogo.png" width=75 height=90 border=0 alt="mercurial"></a>
1026 <img src="/static/hglogo.png" width=75 height=90 border=0 alt="mercurial"></a>
1027 </div>
1027 </div>
1028
1028
1029 </body>
1029 </body>
1030 </html>
1030 </html>
1031
1031
1032
1032
1033 filelog with patch
1033 filelog with patch
1034
1034
1035 $ (get-with-headers.py localhost:$HGPORT 'log/4/a?patch=1')
1035 $ (get-with-headers.py localhost:$HGPORT 'log/4/a?patch=1')
1036 200 Script output follows
1036 200 Script output follows
1037
1037
1038 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
1038 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
1039 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
1039 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
1040 <head>
1040 <head>
1041 <link rel="icon" href="/static/hgicon.png" type="image/png" />
1041 <link rel="icon" href="/static/hgicon.png" type="image/png" />
1042 <meta name="robots" content="index, nofollow" />
1042 <meta name="robots" content="index, nofollow" />
1043 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
1043 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
1044 <script type="text/javascript" src="/static/mercurial.js"></script>
1044 <script type="text/javascript" src="/static/mercurial.js"></script>
1045
1045
1046 <title>test: a history</title>
1046 <title>test: a history</title>
1047 <link rel="alternate" type="application/atom+xml"
1047 <link rel="alternate" type="application/atom+xml"
1048 href="/atom-log/tip/a" title="Atom feed for test:a" />
1048 href="/atom-log/tip/a" title="Atom feed for test:a" />
1049 <link rel="alternate" type="application/rss+xml"
1049 <link rel="alternate" type="application/rss+xml"
1050 href="/rss-log/tip/a" title="RSS feed for test:a" />
1050 href="/rss-log/tip/a" title="RSS feed for test:a" />
1051 </head>
1051 </head>
1052 <body>
1052 <body>
1053
1053
1054 <div class="container">
1054 <div class="container">
1055 <div class="menu">
1055 <div class="menu">
1056 <div class="logo">
1056 <div class="logo">
1057 <a href="https://mercurial-scm.org/">
1057 <a href="https://mercurial-scm.org/">
1058 <img src="/static/hglogo.png" alt="mercurial" /></a>
1058 <img src="/static/hglogo.png" alt="mercurial" /></a>
1059 </div>
1059 </div>
1060 <ul>
1060 <ul>
1061 <li><a href="/shortlog/4">log</a></li>
1061 <li><a href="/shortlog/4">log</a></li>
1062 <li><a href="/graph/4">graph</a></li>
1062 <li><a href="/graph/4">graph</a></li>
1063 <li><a href="/tags">tags</a></li>
1063 <li><a href="/tags">tags</a></li>
1064 <li><a href="/bookmarks">bookmarks</a></li>
1064 <li><a href="/bookmarks">bookmarks</a></li>
1065 <li><a href="/branches">branches</a></li>
1065 <li><a href="/branches">branches</a></li>
1066 </ul>
1066 </ul>
1067 <ul>
1067 <ul>
1068 <li><a href="/rev/4">changeset</a></li>
1068 <li><a href="/rev/4">changeset</a></li>
1069 <li><a href="/file/4">browse</a></li>
1069 <li><a href="/file/4">browse</a></li>
1070 </ul>
1070 </ul>
1071 <ul>
1071 <ul>
1072 <li><a href="/file/4/a">file</a></li>
1072 <li><a href="/file/4/a">file</a></li>
1073 <li><a href="/diff/4/a">diff</a></li>
1073 <li><a href="/diff/4/a">diff</a></li>
1074 <li><a href="/comparison/4/a">comparison</a></li>
1074 <li><a href="/comparison/4/a">comparison</a></li>
1075 <li><a href="/annotate/4/a">annotate</a></li>
1075 <li><a href="/annotate/4/a">annotate</a></li>
1076 <li class="active">file log</li>
1076 <li class="active">file log</li>
1077 <li><a href="/raw-file/4/a">raw</a></li>
1077 <li><a href="/raw-file/4/a">raw</a></li>
1078 </ul>
1078 </ul>
1079 <ul>
1079 <ul>
1080 <li><a href="/help">help</a></li>
1080 <li><a href="/help">help</a></li>
1081 </ul>
1081 </ul>
1082 <div class="atom-logo">
1082 <div class="atom-logo">
1083 <a href="/atom-log/tip/a" title="subscribe to atom feed">
1083 <a href="/atom-log/tip/a" title="subscribe to atom feed">
1084 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="atom feed" />
1084 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="atom feed" />
1085 </a>
1085 </a>
1086 </div>
1086 </div>
1087 </div>
1087 </div>
1088
1088
1089 <div class="main">
1089 <div class="main">
1090 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
1090 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
1091 <h3>
1091 <h3>
1092 log a @ 4:<a href="/rev/3f41bc784e7e">3f41bc784e7e</a>
1092 log a @ 4:<a href="/rev/3f41bc784e7e">3f41bc784e7e</a>
1093 <span class="branchname">a-branch</span>
1093 <span class="branchname">a-branch</span>
1094
1094
1095 </h3>
1095 </h3>
1096
1096
1097 <form class="search" action="/log">
1097 <form class="search" action="/log">
1098
1098
1099 <p><input name="rev" id="search1" type="text" size="30" /></p>
1099 <p><input name="rev" id="search1" type="text" size="30" /></p>
1100 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
1100 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
1101 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
1101 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
1102 </form>
1102 </form>
1103
1103
1104 <div class="navigate">
1104 <div class="navigate">
1105 <a href="/log/4/a?patch=1&revcount=30">less</a>
1105 <a href="/log/4/a?patch=1&revcount=30">less</a>
1106 <a href="/log/4/a?patch=1&revcount=120">more</a>
1106 <a href="/log/4/a?patch=1&revcount=120">more</a>
1107 | <a href="/log/5ed941583260/a">(0)</a> <a href="/log/tip/a">tip</a> </div>
1107 | <a href="/log/5ed941583260/a">(0)</a> <a href="/log/tip/a">tip</a> </div>
1108
1108
1109 <table class="bigtable">
1109 <table class="bigtable">
1110 <thead>
1110 <thead>
1111 <tr>
1111 <tr>
1112 <th class="age">age</th>
1112 <th class="age">age</th>
1113 <th class="author">author</th>
1113 <th class="author">author</th>
1114 <th class="description">description</th>
1114 <th class="description">description</th>
1115 </tr>
1115 </tr>
1116 </thead>
1116 </thead>
1117 <tbody class="stripes2">
1117 <tbody class="stripes2">
1118 <tr>
1118 <tr>
1119 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
1119 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
1120 <td class="author">test</td>
1120 <td class="author">test</td>
1121 <td class="description">
1121 <td class="description">
1122 <a href="/rev/3f41bc784e7e">second a</a>
1122 <a href="/rev/3f41bc784e7e">second a</a>
1123 <span class="branchname">a-branch</span>
1123 <span class="branchname">a-branch</span>
1124 </td>
1124 </td>
1125 </tr>
1125 </tr>
1126 <tr><td colspan="3"><div class="bottomline inc-lineno"><pre class="sourcelines wrap">
1126 <tr><td colspan="3"><div class="bottomline inc-lineno"><pre class="sourcelines wrap">
1127 <span id="3f41bc784e7e-l1.1" class="minusline">--- /dev/null Thu Jan 01 00:00:00 1970 +0000</span><a href="#3f41bc784e7e-l1.1"></a>
1127 <span id="3f41bc784e7e-l1.1" class="minusline">--- /dev/null Thu Jan 01 00:00:00 1970 +0000</span><a href="#3f41bc784e7e-l1.1"></a>
1128 <span id="3f41bc784e7e-l1.2" class="plusline">+++ b/a Thu Jan 01 00:00:00 1970 +0000</span><a href="#3f41bc784e7e-l1.2"></a>
1128 <span id="3f41bc784e7e-l1.2" class="plusline">+++ b/a Thu Jan 01 00:00:00 1970 +0000</span><a href="#3f41bc784e7e-l1.2"></a>
1129 <span id="3f41bc784e7e-l1.3" class="atline">@@ -0,0 +1,1 @@</span><a href="#3f41bc784e7e-l1.3"></a>
1129 <span id="3f41bc784e7e-l1.3" class="atline">@@ -0,0 +1,1 @@</span><a href="#3f41bc784e7e-l1.3"></a>
1130 <span id="3f41bc784e7e-l1.4" class="plusline">+b</span><a href="#3f41bc784e7e-l1.4"></a></pre></div></td></tr>
1130 <span id="3f41bc784e7e-l1.4" class="plusline">+b</span><a href="#3f41bc784e7e-l1.4"></a></pre></div></td></tr>
1131 <tr>
1131 <tr>
1132 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
1132 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
1133 <td class="author">test</td>
1133 <td class="author">test</td>
1134 <td class="description">
1134 <td class="description">
1135 <a href="/rev/5ed941583260">first a</a>
1135 <a href="/rev/5ed941583260">first a</a>
1136 <span class="tag">a-tag</span> <span class="tag">a-bookmark</span>
1136 <span class="tag">a-tag</span> <span class="tag">a-bookmark</span>
1137 </td>
1137 </td>
1138 </tr>
1138 </tr>
1139 <tr><td colspan="3"><div class="bottomline inc-lineno"><pre class="sourcelines wrap">
1139 <tr><td colspan="3"><div class="bottomline inc-lineno"><pre class="sourcelines wrap">
1140 <span id="5ed941583260-l1.1" class="minusline">--- /dev/null Thu Jan 01 00:00:00 1970 +0000</span><a href="#5ed941583260-l1.1"></a>
1140 <span id="5ed941583260-l1.1" class="minusline">--- /dev/null Thu Jan 01 00:00:00 1970 +0000</span><a href="#5ed941583260-l1.1"></a>
1141 <span id="5ed941583260-l1.2" class="plusline">+++ b/a Thu Jan 01 00:00:00 1970 +0000</span><a href="#5ed941583260-l1.2"></a>
1141 <span id="5ed941583260-l1.2" class="plusline">+++ b/a Thu Jan 01 00:00:00 1970 +0000</span><a href="#5ed941583260-l1.2"></a>
1142 <span id="5ed941583260-l1.3" class="atline">@@ -0,0 +1,1 @@</span><a href="#5ed941583260-l1.3"></a>
1142 <span id="5ed941583260-l1.3" class="atline">@@ -0,0 +1,1 @@</span><a href="#5ed941583260-l1.3"></a>
1143 <span id="5ed941583260-l1.4" class="plusline">+a</span><a href="#5ed941583260-l1.4"></a></pre></div></td></tr>
1143 <span id="5ed941583260-l1.4" class="plusline">+a</span><a href="#5ed941583260-l1.4"></a></pre></div></td></tr>
1144
1144
1145 </tbody>
1145 </tbody>
1146 </table>
1146 </table>
1147
1147
1148 <div class="navigate">
1148 <div class="navigate">
1149 <a href="/log/4/a?patch=1&revcount=30">less</a>
1149 <a href="/log/4/a?patch=1&revcount=30">less</a>
1150 <a href="/log/4/a?patch=1&revcount=120">more</a>
1150 <a href="/log/4/a?patch=1&revcount=120">more</a>
1151 | <a href="/log/5ed941583260/a">(0)</a> <a href="/log/tip/a">tip</a>
1151 | <a href="/log/5ed941583260/a">(0)</a> <a href="/log/tip/a">tip</a>
1152 </div>
1152 </div>
1153
1153
1154 </div>
1154 </div>
1155 </div>
1155 </div>
1156
1156
1157
1157
1158
1158
1159 </body>
1159 </body>
1160 </html>
1160 </html>
1161
1161
1162 filelog with 'linerange' and 'patch'
1162 filelog with 'linerange' and 'patch'
1163
1163
1164 $ cat c
1164 $ cat c
1165 b
1165 b
1166 c
1166 c
1167 $ cat <<EOF > c
1167 $ cat <<EOF > c
1168 > 0
1168 > 0
1169 > 0
1169 > 0
1170 > b
1170 > b
1171 > c+
1171 > c+
1172 >
1172 >
1173 > a
1173 > a
1174 > a
1174 > a
1175 >
1175 >
1176 > d
1176 > d
1177 > e
1177 > e
1178 > f
1178 > f
1179 > EOF
1179 > EOF
1180 $ hg ci -m 'make c bigger and touch its beginning' c
1180 $ hg ci -m 'make c bigger and touch its beginning' c
1181 $ cat <<EOF > c
1181 $ cat <<EOF > c
1182 > 0
1182 > 0
1183 > 0
1183 > 0
1184 > b
1184 > b
1185 > c+
1185 > c+
1186 >
1186 >
1187 > a
1187 > a
1188 > a
1188 > a
1189 >
1189 >
1190 > d
1190 > d
1191 > e+
1191 > e+
1192 > f
1192 > f
1193 > EOF
1193 > EOF
1194 $ hg ci -m 'just touch end of c' c
1194 $ hg ci -m 'just touch end of c' c
1195 $ cat <<EOF > c
1195 $ cat <<EOF > c
1196 > 0
1196 > 0
1197 > 0
1197 > 0
1198 > b
1198 > b
1199 > c++
1199 > c++
1200 >
1200 >
1201 > a
1201 > a
1202 > a
1202 > a
1203 >
1203 >
1204 > d
1204 > d
1205 > e+
1205 > e+
1206 > f
1206 > f
1207 > EOF
1207 > EOF
1208 $ hg ci -m 'touch beginning of c' c
1208 $ hg ci -m 'touch beginning of c' c
1209 $ cat <<EOF > c
1209 $ cat <<EOF > c
1210 > 0
1210 > 0
1211 > 0
1211 > 0
1212 > b-
1212 > b-
1213 > c++
1213 > c++
1214 >
1214 >
1215 > a
1215 > a
1216 > a
1216 > a
1217 >
1217 >
1218 > d
1218 > d
1219 > e+
1219 > e+
1220 > f+
1220 > f+
1221 > EOF
1221 > EOF
1222 $ hg ci -m 'touching beginning and end of c' c
1222 $ hg ci -m 'touching beginning and end of c' c
1223 $ echo c > cc
1224 $ hg ci -Am 'tip does not touch c' cc
1223 $ hg log -r 'followlines(c, 3:4, startrev=tip) and follow(c)' -p
1225 $ hg log -r 'followlines(c, 3:4, startrev=tip) and follow(c)' -p
1224 changeset: 0:6563da9dcf87
1226 changeset: 0:6563da9dcf87
1225 user: test
1227 user: test
1226 date: Thu Jan 01 00:00:00 1970 +0000
1228 date: Thu Jan 01 00:00:00 1970 +0000
1227 summary: b
1229 summary: b
1228
1230
1229 diff -r 000000000000 -r 6563da9dcf87 b
1231 diff -r 000000000000 -r 6563da9dcf87 b
1230 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1232 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1231 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1233 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1232 @@ -0,0 +1,1 @@
1234 @@ -0,0 +1,1 @@
1233 +b
1235 +b
1234
1236
1235 changeset: 7:46c1a66bd8fc
1237 changeset: 7:46c1a66bd8fc
1236 branch: a-branch
1238 branch: a-branch
1237 user: test
1239 user: test
1238 date: Thu Jan 01 00:00:00 1970 +0000
1240 date: Thu Jan 01 00:00:00 1970 +0000
1239 summary: change c
1241 summary: change c
1240
1242
1241 diff -r c9637d3cc8ef -r 46c1a66bd8fc c
1243 diff -r c9637d3cc8ef -r 46c1a66bd8fc c
1242 --- a/c Thu Jan 01 00:00:00 1970 +0000
1244 --- a/c Thu Jan 01 00:00:00 1970 +0000
1243 +++ b/c Thu Jan 01 00:00:00 1970 +0000
1245 +++ b/c Thu Jan 01 00:00:00 1970 +0000
1244 @@ -1,1 +1,2 @@
1246 @@ -1,1 +1,2 @@
1245 b
1247 b
1246 +c
1248 +c
1247
1249
1248 changeset: 8:5c6574614c37
1250 changeset: 8:5c6574614c37
1249 branch: a-branch
1251 branch: a-branch
1250 user: test
1252 user: test
1251 date: Thu Jan 01 00:00:00 1970 +0000
1253 date: Thu Jan 01 00:00:00 1970 +0000
1252 summary: make c bigger and touch its beginning
1254 summary: make c bigger and touch its beginning
1253
1255
1254 diff -r 46c1a66bd8fc -r 5c6574614c37 c
1256 diff -r 46c1a66bd8fc -r 5c6574614c37 c
1255 --- a/c Thu Jan 01 00:00:00 1970 +0000
1257 --- a/c Thu Jan 01 00:00:00 1970 +0000
1256 +++ b/c Thu Jan 01 00:00:00 1970 +0000
1258 +++ b/c Thu Jan 01 00:00:00 1970 +0000
1257 @@ -1,2 +1,11 @@
1259 @@ -1,2 +1,11 @@
1258 +0
1260 +0
1259 +0
1261 +0
1260 b
1262 b
1261 -c
1263 -c
1262 +c+
1264 +c+
1263 +
1265 +
1264 +a
1266 +a
1265 +a
1267 +a
1266 +
1268 +
1267 +d
1269 +d
1268 +e
1270 +e
1269 +f
1271 +f
1270
1272
1271 changeset: 10:e95928d60479
1273 changeset: 10:e95928d60479
1272 branch: a-branch
1274 branch: a-branch
1273 user: test
1275 user: test
1274 date: Thu Jan 01 00:00:00 1970 +0000
1276 date: Thu Jan 01 00:00:00 1970 +0000
1275 summary: touch beginning of c
1277 summary: touch beginning of c
1276
1278
1277 diff -r e1d3e9c5a23f -r e95928d60479 c
1279 diff -r e1d3e9c5a23f -r e95928d60479 c
1278 --- a/c Thu Jan 01 00:00:00 1970 +0000
1280 --- a/c Thu Jan 01 00:00:00 1970 +0000
1279 +++ b/c Thu Jan 01 00:00:00 1970 +0000
1281 +++ b/c Thu Jan 01 00:00:00 1970 +0000
1280 @@ -1,7 +1,7 @@
1282 @@ -1,7 +1,7 @@
1281 0
1283 0
1282 0
1284 0
1283 b
1285 b
1284 -c+
1286 -c+
1285 +c++
1287 +c++
1286
1288
1287 a
1289 a
1288 a
1290 a
1289
1291
1290 changeset: 11:fb9bc322513a
1292 changeset: 11:fb9bc322513a
1291 branch: a-branch
1293 branch: a-branch
1292 tag: tip
1293 user: test
1294 user: test
1294 date: Thu Jan 01 00:00:00 1970 +0000
1295 date: Thu Jan 01 00:00:00 1970 +0000
1295 summary: touching beginning and end of c
1296 summary: touching beginning and end of c
1296
1297
1297 diff -r e95928d60479 -r fb9bc322513a c
1298 diff -r e95928d60479 -r fb9bc322513a c
1298 --- a/c Thu Jan 01 00:00:00 1970 +0000
1299 --- a/c Thu Jan 01 00:00:00 1970 +0000
1299 +++ b/c Thu Jan 01 00:00:00 1970 +0000
1300 +++ b/c Thu Jan 01 00:00:00 1970 +0000
1300 @@ -1,6 +1,6 @@
1301 @@ -1,6 +1,6 @@
1301 0
1302 0
1302 0
1303 0
1303 -b
1304 -b
1304 +b-
1305 +b-
1305 c++
1306 c++
1306
1307
1307 a
1308 a
1308 @@ -8,4 +8,4 @@
1309 @@ -8,4 +8,4 @@
1309
1310
1310 d
1311 d
1311 e+
1312 e+
1312 -f
1313 -f
1313 +f+
1314 +f+
1314
1315
1315 $ (get-with-headers.py localhost:$HGPORT 'log/tip/c?linerange=3:4&patch=')
1316 $ (get-with-headers.py localhost:$HGPORT 'log/tip/c?linerange=3:4&patch=')
1316 200 Script output follows
1317 200 Script output follows
1317
1318
1318 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
1319 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
1319 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
1320 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
1320 <head>
1321 <head>
1321 <link rel="icon" href="/static/hgicon.png" type="image/png" />
1322 <link rel="icon" href="/static/hgicon.png" type="image/png" />
1322 <meta name="robots" content="index, nofollow" />
1323 <meta name="robots" content="index, nofollow" />
1323 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
1324 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
1324 <script type="text/javascript" src="/static/mercurial.js"></script>
1325 <script type="text/javascript" src="/static/mercurial.js"></script>
1325
1326
1326 <title>test: c history</title>
1327 <title>test: c history</title>
1327 <link rel="alternate" type="application/atom+xml"
1328 <link rel="alternate" type="application/atom+xml"
1328 href="/atom-log/tip/c" title="Atom feed for test:c" />
1329 href="/atom-log/tip/c" title="Atom feed for test:c" />
1329 <link rel="alternate" type="application/rss+xml"
1330 <link rel="alternate" type="application/rss+xml"
1330 href="/rss-log/tip/c" title="RSS feed for test:c" />
1331 href="/rss-log/tip/c" title="RSS feed for test:c" />
1331 </head>
1332 </head>
1332 <body>
1333 <body>
1333
1334
1334 <div class="container">
1335 <div class="container">
1335 <div class="menu">
1336 <div class="menu">
1336 <div class="logo">
1337 <div class="logo">
1337 <a href="https://mercurial-scm.org/">
1338 <a href="https://mercurial-scm.org/">
1338 <img src="/static/hglogo.png" alt="mercurial" /></a>
1339 <img src="/static/hglogo.png" alt="mercurial" /></a>
1339 </div>
1340 </div>
1340 <ul>
1341 <ul>
1341 <li><a href="/shortlog/tip">log</a></li>
1342 <li><a href="/shortlog/tip">log</a></li>
1342 <li><a href="/graph/tip">graph</a></li>
1343 <li><a href="/graph/tip">graph</a></li>
1343 <li><a href="/tags">tags</a></li>
1344 <li><a href="/tags">tags</a></li>
1344 <li><a href="/bookmarks">bookmarks</a></li>
1345 <li><a href="/bookmarks">bookmarks</a></li>
1345 <li><a href="/branches">branches</a></li>
1346 <li><a href="/branches">branches</a></li>
1346 </ul>
1347 </ul>
1347 <ul>
1348 <ul>
1348 <li><a href="/rev/tip">changeset</a></li>
1349 <li><a href="/rev/tip">changeset</a></li>
1349 <li><a href="/file/tip">browse</a></li>
1350 <li><a href="/file/tip">browse</a></li>
1350 </ul>
1351 </ul>
1351 <ul>
1352 <ul>
1352 <li><a href="/file/tip/c">file</a></li>
1353 <li><a href="/file/tip/c">file</a></li>
1353 <li><a href="/diff/tip/c">diff</a></li>
1354 <li><a href="/diff/tip/c">diff</a></li>
1354 <li><a href="/comparison/tip/c">comparison</a></li>
1355 <li><a href="/comparison/tip/c">comparison</a></li>
1355 <li><a href="/annotate/tip/c">annotate</a></li>
1356 <li><a href="/annotate/tip/c">annotate</a></li>
1356 <li class="active">file log</li>
1357 <li class="active">file log</li>
1357 <li><a href="/raw-file/tip/c">raw</a></li>
1358 <li><a href="/raw-file/tip/c">raw</a></li>
1358 </ul>
1359 </ul>
1359 <ul>
1360 <ul>
1360 <li><a href="/help">help</a></li>
1361 <li><a href="/help">help</a></li>
1361 </ul>
1362 </ul>
1362 <div class="atom-logo">
1363 <div class="atom-logo">
1363 <a href="/atom-log/tip/c" title="subscribe to atom feed">
1364 <a href="/atom-log/tip/c" title="subscribe to atom feed">
1364 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="atom feed" />
1365 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="atom feed" />
1365 </a>
1366 </a>
1366 </div>
1367 </div>
1367 </div>
1368 </div>
1368
1369
1369 <div class="main">
1370 <div class="main">
1370 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
1371 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
1371 <h3>
1372 <h3>
1372 log c @ 11:<a href="/rev/fb9bc322513a">fb9bc322513a</a>
1373 log c @ 12:<a href="/rev/6e4182052f7b">6e4182052f7b</a>
1373 <span class="branchname">a-branch</span> <span class="tag">tip</span>
1374 <span class="branchname">a-branch</span> <span class="tag">tip</span>
1374 (following lines 3:4 <a href="/log/tip/c">back to filelog</a>)
1375 (following lines 3:4 <a href="/log/tip/c">back to filelog</a>)
1375 </h3>
1376 </h3>
1376
1377
1377 <form class="search" action="/log">
1378 <form class="search" action="/log">
1378
1379
1379 <p><input name="rev" id="search1" type="text" size="30" /></p>
1380 <p><input name="rev" id="search1" type="text" size="30" /></p>
1380 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
1381 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
1381 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
1382 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
1382 </form>
1383 </form>
1383
1384
1384 <div class="navigate">
1385 <div class="navigate">
1385 <a href="/log/tip/c?linerange=3%3A4&patch=&revcount=30">less</a>
1386 <a href="/log/tip/c?linerange=3%3A4&patch=&revcount=30">less</a>
1386 <a href="/log/tip/c?linerange=3%3A4&patch=&revcount=120">more</a>
1387 <a href="/log/tip/c?linerange=3%3A4&patch=&revcount=120">more</a>
1387 | </div>
1388 | </div>
1388
1389
1389 <table class="bigtable">
1390 <table class="bigtable">
1390 <thead>
1391 <thead>
1391 <tr>
1392 <tr>
1392 <th class="age">age</th>
1393 <th class="age">age</th>
1393 <th class="author">author</th>
1394 <th class="author">author</th>
1394 <th class="description">description</th>
1395 <th class="description">description</th>
1395 </tr>
1396 </tr>
1396 </thead>
1397 </thead>
1397 <tbody class="stripes2">
1398 <tbody class="stripes2">
1398 <tr>
1399 <tr>
1399 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
1400 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
1400 <td class="author">test</td>
1401 <td class="author">test</td>
1401 <td class="description">
1402 <td class="description">
1402 <a href="/rev/fb9bc322513a">touching beginning and end of c</a>
1403 <a href="/rev/fb9bc322513a">touching beginning and end of c</a>
1403 <span class="branchhead">a-branch</span> <span class="tag">tip</span>
1404 <span class="branchname">a-branch</span>
1404 </td>
1405 </td>
1405 </tr>
1406 </tr>
1406 <tr><td colspan="3"><div class="bottomline inc-lineno"><pre class="sourcelines wrap">
1407 <tr><td colspan="3"><div class="bottomline inc-lineno"><pre class="sourcelines wrap">
1407 <span id="fb9bc322513a-l1.1" class="minusline">--- a/c Thu Jan 01 00:00:00 1970 +0000</span><a href="#fb9bc322513a-l1.1"></a>
1408 <span id="fb9bc322513a-l1.1" class="minusline">--- a/c Thu Jan 01 00:00:00 1970 +0000</span><a href="#fb9bc322513a-l1.1"></a>
1408 <span id="fb9bc322513a-l1.2" class="plusline">+++ b/c Thu Jan 01 00:00:00 1970 +0000</span><a href="#fb9bc322513a-l1.2"></a>
1409 <span id="fb9bc322513a-l1.2" class="plusline">+++ b/c Thu Jan 01 00:00:00 1970 +0000</span><a href="#fb9bc322513a-l1.2"></a>
1409 <span id="fb9bc322513a-l1.3" class="atline">@@ -1,6 +1,6 @@</span><a href="#fb9bc322513a-l1.3"></a>
1410 <span id="fb9bc322513a-l1.3" class="atline">@@ -1,6 +1,6 @@</span><a href="#fb9bc322513a-l1.3"></a>
1410 <span id="fb9bc322513a-l1.4"> 0</span><a href="#fb9bc322513a-l1.4"></a>
1411 <span id="fb9bc322513a-l1.4"> 0</span><a href="#fb9bc322513a-l1.4"></a>
1411 <span id="fb9bc322513a-l1.5"> 0</span><a href="#fb9bc322513a-l1.5"></a>
1412 <span id="fb9bc322513a-l1.5"> 0</span><a href="#fb9bc322513a-l1.5"></a>
1412 <span id="fb9bc322513a-l1.6" class="minusline">-b</span><a href="#fb9bc322513a-l1.6"></a>
1413 <span id="fb9bc322513a-l1.6" class="minusline">-b</span><a href="#fb9bc322513a-l1.6"></a>
1413 <span id="fb9bc322513a-l1.7" class="plusline">+b-</span><a href="#fb9bc322513a-l1.7"></a>
1414 <span id="fb9bc322513a-l1.7" class="plusline">+b-</span><a href="#fb9bc322513a-l1.7"></a>
1414 <span id="fb9bc322513a-l1.8"> c++</span><a href="#fb9bc322513a-l1.8"></a>
1415 <span id="fb9bc322513a-l1.8"> c++</span><a href="#fb9bc322513a-l1.8"></a>
1415 <span id="fb9bc322513a-l1.9"> </span><a href="#fb9bc322513a-l1.9"></a>
1416 <span id="fb9bc322513a-l1.9"> </span><a href="#fb9bc322513a-l1.9"></a>
1416 <span id="fb9bc322513a-l1.10"> a</span><a href="#fb9bc322513a-l1.10"></a></pre></div></td></tr>
1417 <span id="fb9bc322513a-l1.10"> a</span><a href="#fb9bc322513a-l1.10"></a></pre></div></td></tr>
1417 <tr>
1418 <tr>
1418 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
1419 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
1419 <td class="author">test</td>
1420 <td class="author">test</td>
1420 <td class="description">
1421 <td class="description">
1421 <a href="/rev/e95928d60479">touch beginning of c</a>
1422 <a href="/rev/e95928d60479">touch beginning of c</a>
1422 <span class="branchname">a-branch</span>
1423 <span class="branchname">a-branch</span>
1423 </td>
1424 </td>
1424 </tr>
1425 </tr>
1425 <tr><td colspan="3"><div class="bottomline inc-lineno"><pre class="sourcelines wrap">
1426 <tr><td colspan="3"><div class="bottomline inc-lineno"><pre class="sourcelines wrap">
1426 <span id="e95928d60479-l1.1" class="minusline">--- a/c Thu Jan 01 00:00:00 1970 +0000</span><a href="#e95928d60479-l1.1"></a>
1427 <span id="e95928d60479-l1.1" class="minusline">--- a/c Thu Jan 01 00:00:00 1970 +0000</span><a href="#e95928d60479-l1.1"></a>
1427 <span id="e95928d60479-l1.2" class="plusline">+++ b/c Thu Jan 01 00:00:00 1970 +0000</span><a href="#e95928d60479-l1.2"></a>
1428 <span id="e95928d60479-l1.2" class="plusline">+++ b/c Thu Jan 01 00:00:00 1970 +0000</span><a href="#e95928d60479-l1.2"></a>
1428 <span id="e95928d60479-l1.3" class="atline">@@ -1,7 +1,7 @@</span><a href="#e95928d60479-l1.3"></a>
1429 <span id="e95928d60479-l1.3" class="atline">@@ -1,7 +1,7 @@</span><a href="#e95928d60479-l1.3"></a>
1429 <span id="e95928d60479-l1.4"> 0</span><a href="#e95928d60479-l1.4"></a>
1430 <span id="e95928d60479-l1.4"> 0</span><a href="#e95928d60479-l1.4"></a>
1430 <span id="e95928d60479-l1.5"> 0</span><a href="#e95928d60479-l1.5"></a>
1431 <span id="e95928d60479-l1.5"> 0</span><a href="#e95928d60479-l1.5"></a>
1431 <span id="e95928d60479-l1.6"> b</span><a href="#e95928d60479-l1.6"></a>
1432 <span id="e95928d60479-l1.6"> b</span><a href="#e95928d60479-l1.6"></a>
1432 <span id="e95928d60479-l1.7" class="minusline">-c+</span><a href="#e95928d60479-l1.7"></a>
1433 <span id="e95928d60479-l1.7" class="minusline">-c+</span><a href="#e95928d60479-l1.7"></a>
1433 <span id="e95928d60479-l1.8" class="plusline">+c++</span><a href="#e95928d60479-l1.8"></a>
1434 <span id="e95928d60479-l1.8" class="plusline">+c++</span><a href="#e95928d60479-l1.8"></a>
1434 <span id="e95928d60479-l1.9"> </span><a href="#e95928d60479-l1.9"></a>
1435 <span id="e95928d60479-l1.9"> </span><a href="#e95928d60479-l1.9"></a>
1435 <span id="e95928d60479-l1.10"> a</span><a href="#e95928d60479-l1.10"></a>
1436 <span id="e95928d60479-l1.10"> a</span><a href="#e95928d60479-l1.10"></a>
1436 <span id="e95928d60479-l1.11"> a</span><a href="#e95928d60479-l1.11"></a></pre></div></td></tr>
1437 <span id="e95928d60479-l1.11"> a</span><a href="#e95928d60479-l1.11"></a></pre></div></td></tr>
1437 <tr>
1438 <tr>
1438 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
1439 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
1439 <td class="author">test</td>
1440 <td class="author">test</td>
1440 <td class="description">
1441 <td class="description">
1441 <a href="/rev/5c6574614c37">make c bigger and touch its beginning</a>
1442 <a href="/rev/5c6574614c37">make c bigger and touch its beginning</a>
1442 <span class="branchname">a-branch</span>
1443 <span class="branchname">a-branch</span>
1443 </td>
1444 </td>
1444 </tr>
1445 </tr>
1445 <tr><td colspan="3"><div class="bottomline inc-lineno"><pre class="sourcelines wrap">
1446 <tr><td colspan="3"><div class="bottomline inc-lineno"><pre class="sourcelines wrap">
1446 <span id="5c6574614c37-l1.1" class="minusline">--- a/c Thu Jan 01 00:00:00 1970 +0000</span><a href="#5c6574614c37-l1.1"></a>
1447 <span id="5c6574614c37-l1.1" class="minusline">--- a/c Thu Jan 01 00:00:00 1970 +0000</span><a href="#5c6574614c37-l1.1"></a>
1447 <span id="5c6574614c37-l1.2" class="plusline">+++ b/c Thu Jan 01 00:00:00 1970 +0000</span><a href="#5c6574614c37-l1.2"></a>
1448 <span id="5c6574614c37-l1.2" class="plusline">+++ b/c Thu Jan 01 00:00:00 1970 +0000</span><a href="#5c6574614c37-l1.2"></a>
1448 <span id="5c6574614c37-l1.3" class="atline">@@ -1,2 +1,11 @@</span><a href="#5c6574614c37-l1.3"></a>
1449 <span id="5c6574614c37-l1.3" class="atline">@@ -1,2 +1,11 @@</span><a href="#5c6574614c37-l1.3"></a>
1449 <span id="5c6574614c37-l1.4" class="plusline">+0</span><a href="#5c6574614c37-l1.4"></a>
1450 <span id="5c6574614c37-l1.4" class="plusline">+0</span><a href="#5c6574614c37-l1.4"></a>
1450 <span id="5c6574614c37-l1.5" class="plusline">+0</span><a href="#5c6574614c37-l1.5"></a>
1451 <span id="5c6574614c37-l1.5" class="plusline">+0</span><a href="#5c6574614c37-l1.5"></a>
1451 <span id="5c6574614c37-l1.6"> b</span><a href="#5c6574614c37-l1.6"></a>
1452 <span id="5c6574614c37-l1.6"> b</span><a href="#5c6574614c37-l1.6"></a>
1452 <span id="5c6574614c37-l1.7" class="minusline">-c</span><a href="#5c6574614c37-l1.7"></a>
1453 <span id="5c6574614c37-l1.7" class="minusline">-c</span><a href="#5c6574614c37-l1.7"></a>
1453 <span id="5c6574614c37-l1.8" class="plusline">+c+</span><a href="#5c6574614c37-l1.8"></a>
1454 <span id="5c6574614c37-l1.8" class="plusline">+c+</span><a href="#5c6574614c37-l1.8"></a>
1454 <span id="5c6574614c37-l1.9" class="plusline">+</span><a href="#5c6574614c37-l1.9"></a>
1455 <span id="5c6574614c37-l1.9" class="plusline">+</span><a href="#5c6574614c37-l1.9"></a>
1455 <span id="5c6574614c37-l1.10" class="plusline">+a</span><a href="#5c6574614c37-l1.10"></a>
1456 <span id="5c6574614c37-l1.10" class="plusline">+a</span><a href="#5c6574614c37-l1.10"></a>
1456 <span id="5c6574614c37-l1.11" class="plusline">+a</span><a href="#5c6574614c37-l1.11"></a>
1457 <span id="5c6574614c37-l1.11" class="plusline">+a</span><a href="#5c6574614c37-l1.11"></a>
1457 <span id="5c6574614c37-l1.12" class="plusline">+</span><a href="#5c6574614c37-l1.12"></a>
1458 <span id="5c6574614c37-l1.12" class="plusline">+</span><a href="#5c6574614c37-l1.12"></a>
1458 <span id="5c6574614c37-l1.13" class="plusline">+d</span><a href="#5c6574614c37-l1.13"></a>
1459 <span id="5c6574614c37-l1.13" class="plusline">+d</span><a href="#5c6574614c37-l1.13"></a>
1459 <span id="5c6574614c37-l1.14" class="plusline">+e</span><a href="#5c6574614c37-l1.14"></a>
1460 <span id="5c6574614c37-l1.14" class="plusline">+e</span><a href="#5c6574614c37-l1.14"></a>
1460 <span id="5c6574614c37-l1.15" class="plusline">+f</span><a href="#5c6574614c37-l1.15"></a></pre></div></td></tr>
1461 <span id="5c6574614c37-l1.15" class="plusline">+f</span><a href="#5c6574614c37-l1.15"></a></pre></div></td></tr>
1461 <tr>
1462 <tr>
1462 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
1463 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
1463 <td class="author">test</td>
1464 <td class="author">test</td>
1464 <td class="description">
1465 <td class="description">
1465 <a href="/rev/46c1a66bd8fc">change c</a>
1466 <a href="/rev/46c1a66bd8fc">change c</a>
1466 <span class="branchname">a-branch</span>
1467 <span class="branchname">a-branch</span>
1467 </td>
1468 </td>
1468 </tr>
1469 </tr>
1469 <tr><td colspan="3"><div class="bottomline inc-lineno"><pre class="sourcelines wrap">
1470 <tr><td colspan="3"><div class="bottomline inc-lineno"><pre class="sourcelines wrap">
1470 <span id="46c1a66bd8fc-l1.1" class="minusline">--- a/c Thu Jan 01 00:00:00 1970 +0000</span><a href="#46c1a66bd8fc-l1.1"></a>
1471 <span id="46c1a66bd8fc-l1.1" class="minusline">--- a/c Thu Jan 01 00:00:00 1970 +0000</span><a href="#46c1a66bd8fc-l1.1"></a>
1471 <span id="46c1a66bd8fc-l1.2" class="plusline">+++ b/c Thu Jan 01 00:00:00 1970 +0000</span><a href="#46c1a66bd8fc-l1.2"></a>
1472 <span id="46c1a66bd8fc-l1.2" class="plusline">+++ b/c Thu Jan 01 00:00:00 1970 +0000</span><a href="#46c1a66bd8fc-l1.2"></a>
1472 <span id="46c1a66bd8fc-l1.3" class="atline">@@ -1,1 +1,2 @@</span><a href="#46c1a66bd8fc-l1.3"></a>
1473 <span id="46c1a66bd8fc-l1.3" class="atline">@@ -1,1 +1,2 @@</span><a href="#46c1a66bd8fc-l1.3"></a>
1473 <span id="46c1a66bd8fc-l1.4"> b</span><a href="#46c1a66bd8fc-l1.4"></a>
1474 <span id="46c1a66bd8fc-l1.4"> b</span><a href="#46c1a66bd8fc-l1.4"></a>
1474 <span id="46c1a66bd8fc-l1.5" class="plusline">+c</span><a href="#46c1a66bd8fc-l1.5"></a></pre></div></td></tr>
1475 <span id="46c1a66bd8fc-l1.5" class="plusline">+c</span><a href="#46c1a66bd8fc-l1.5"></a></pre></div></td></tr>
1475 <tr>
1476 <tr>
1476 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
1477 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
1477 <td class="author">test</td>
1478 <td class="author">test</td>
1478 <td class="description">
1479 <td class="description">
1479 <a href="/rev/6563da9dcf87">b</a>
1480 <a href="/rev/6563da9dcf87">b</a>
1480
1481
1481 </td>
1482 </td>
1482 </tr>
1483 </tr>
1483 <tr><td colspan="3"><div class="bottomline inc-lineno"><pre class="sourcelines wrap">
1484 <tr><td colspan="3"><div class="bottomline inc-lineno"><pre class="sourcelines wrap">
1484 <span id="6563da9dcf87-l1.1" class="minusline">--- /dev/null Thu Jan 01 00:00:00 1970 +0000</span><a href="#6563da9dcf87-l1.1"></a>
1485 <span id="6563da9dcf87-l1.1" class="minusline">--- /dev/null Thu Jan 01 00:00:00 1970 +0000</span><a href="#6563da9dcf87-l1.1"></a>
1485 <span id="6563da9dcf87-l1.2" class="plusline">+++ b/b Thu Jan 01 00:00:00 1970 +0000</span><a href="#6563da9dcf87-l1.2"></a></pre></div></td></tr>
1486 <span id="6563da9dcf87-l1.2" class="plusline">+++ b/b Thu Jan 01 00:00:00 1970 +0000</span><a href="#6563da9dcf87-l1.2"></a></pre></div></td></tr>
1486
1487
1487 </tbody>
1488 </tbody>
1488 </table>
1489 </table>
1489
1490
1490 <div class="navigate">
1491 <div class="navigate">
1491 <a href="/log/tip/c?linerange=3%3A4&patch=&revcount=30">less</a>
1492 <a href="/log/tip/c?linerange=3%3A4&patch=&revcount=30">less</a>
1492 <a href="/log/tip/c?linerange=3%3A4&patch=&revcount=120">more</a>
1493 <a href="/log/tip/c?linerange=3%3A4&patch=&revcount=120">more</a>
1493 |
1494 |
1494 </div>
1495 </div>
1495
1496
1496 </div>
1497 </div>
1497 </div>
1498 </div>
1498
1499
1499
1500
1500
1501
1501 </body>
1502 </body>
1502 </html>
1503 </html>
1503
1504
1504 $ hg log -r 'followlines(c, 3:4, startrev=8, descend=True) and follow(c)' -p
1505 $ hg log -r 'followlines(c, 3:4, startrev=8, descend=True) and follow(c)' -p
1505 changeset: 8:5c6574614c37
1506 changeset: 8:5c6574614c37
1506 branch: a-branch
1507 branch: a-branch
1507 user: test
1508 user: test
1508 date: Thu Jan 01 00:00:00 1970 +0000
1509 date: Thu Jan 01 00:00:00 1970 +0000
1509 summary: make c bigger and touch its beginning
1510 summary: make c bigger and touch its beginning
1510
1511
1511 diff -r 46c1a66bd8fc -r 5c6574614c37 c
1512 diff -r 46c1a66bd8fc -r 5c6574614c37 c
1512 --- a/c Thu Jan 01 00:00:00 1970 +0000
1513 --- a/c Thu Jan 01 00:00:00 1970 +0000
1513 +++ b/c Thu Jan 01 00:00:00 1970 +0000
1514 +++ b/c Thu Jan 01 00:00:00 1970 +0000
1514 @@ -1,2 +1,11 @@
1515 @@ -1,2 +1,11 @@
1515 +0
1516 +0
1516 +0
1517 +0
1517 b
1518 b
1518 -c
1519 -c
1519 +c+
1520 +c+
1520 +
1521 +
1521 +a
1522 +a
1522 +a
1523 +a
1523 +
1524 +
1524 +d
1525 +d
1525 +e
1526 +e
1526 +f
1527 +f
1527
1528
1528 changeset: 10:e95928d60479
1529 changeset: 10:e95928d60479
1529 branch: a-branch
1530 branch: a-branch
1530 user: test
1531 user: test
1531 date: Thu Jan 01 00:00:00 1970 +0000
1532 date: Thu Jan 01 00:00:00 1970 +0000
1532 summary: touch beginning of c
1533 summary: touch beginning of c
1533
1534
1534 diff -r e1d3e9c5a23f -r e95928d60479 c
1535 diff -r e1d3e9c5a23f -r e95928d60479 c
1535 --- a/c Thu Jan 01 00:00:00 1970 +0000
1536 --- a/c Thu Jan 01 00:00:00 1970 +0000
1536 +++ b/c Thu Jan 01 00:00:00 1970 +0000
1537 +++ b/c Thu Jan 01 00:00:00 1970 +0000
1537 @@ -1,7 +1,7 @@
1538 @@ -1,7 +1,7 @@
1538 0
1539 0
1539 0
1540 0
1540 b
1541 b
1541 -c+
1542 -c+
1542 +c++
1543 +c++
1543
1544
1544 a
1545 a
1545 a
1546 a
1546
1547
1547 changeset: 11:fb9bc322513a
1548 changeset: 11:fb9bc322513a
1548 branch: a-branch
1549 branch: a-branch
1549 tag: tip
1550 user: test
1550 user: test
1551 date: Thu Jan 01 00:00:00 1970 +0000
1551 date: Thu Jan 01 00:00:00 1970 +0000
1552 summary: touching beginning and end of c
1552 summary: touching beginning and end of c
1553
1553
1554 diff -r e95928d60479 -r fb9bc322513a c
1554 diff -r e95928d60479 -r fb9bc322513a c
1555 --- a/c Thu Jan 01 00:00:00 1970 +0000
1555 --- a/c Thu Jan 01 00:00:00 1970 +0000
1556 +++ b/c Thu Jan 01 00:00:00 1970 +0000
1556 +++ b/c Thu Jan 01 00:00:00 1970 +0000
1557 @@ -1,6 +1,6 @@
1557 @@ -1,6 +1,6 @@
1558 0
1558 0
1559 0
1559 0
1560 -b
1560 -b
1561 +b-
1561 +b-
1562 c++
1562 c++
1563
1563
1564 a
1564 a
1565 @@ -8,4 +8,4 @@
1565 @@ -8,4 +8,4 @@
1566
1566
1567 d
1567 d
1568 e+
1568 e+
1569 -f
1569 -f
1570 +f+
1570 +f+
1571
1571
1572 $ (get-with-headers.py localhost:$HGPORT 'log/8/c?linerange=3:4&descend=')
1572 $ (get-with-headers.py localhost:$HGPORT 'log/8/c?linerange=3:4&descend=')
1573 200 Script output follows
1573 200 Script output follows
1574
1574
1575 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
1575 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
1576 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
1576 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
1577 <head>
1577 <head>
1578 <link rel="icon" href="/static/hgicon.png" type="image/png" />
1578 <link rel="icon" href="/static/hgicon.png" type="image/png" />
1579 <meta name="robots" content="index, nofollow" />
1579 <meta name="robots" content="index, nofollow" />
1580 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
1580 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
1581 <script type="text/javascript" src="/static/mercurial.js"></script>
1581 <script type="text/javascript" src="/static/mercurial.js"></script>
1582
1582
1583 <title>test: c history</title>
1583 <title>test: c history</title>
1584 <link rel="alternate" type="application/atom+xml"
1584 <link rel="alternate" type="application/atom+xml"
1585 href="/atom-log/tip/c" title="Atom feed for test:c" />
1585 href="/atom-log/tip/c" title="Atom feed for test:c" />
1586 <link rel="alternate" type="application/rss+xml"
1586 <link rel="alternate" type="application/rss+xml"
1587 href="/rss-log/tip/c" title="RSS feed for test:c" />
1587 href="/rss-log/tip/c" title="RSS feed for test:c" />
1588 </head>
1588 </head>
1589 <body>
1589 <body>
1590
1590
1591 <div class="container">
1591 <div class="container">
1592 <div class="menu">
1592 <div class="menu">
1593 <div class="logo">
1593 <div class="logo">
1594 <a href="https://mercurial-scm.org/">
1594 <a href="https://mercurial-scm.org/">
1595 <img src="/static/hglogo.png" alt="mercurial" /></a>
1595 <img src="/static/hglogo.png" alt="mercurial" /></a>
1596 </div>
1596 </div>
1597 <ul>
1597 <ul>
1598 <li><a href="/shortlog/8">log</a></li>
1598 <li><a href="/shortlog/8">log</a></li>
1599 <li><a href="/graph/8">graph</a></li>
1599 <li><a href="/graph/8">graph</a></li>
1600 <li><a href="/tags">tags</a></li>
1600 <li><a href="/tags">tags</a></li>
1601 <li><a href="/bookmarks">bookmarks</a></li>
1601 <li><a href="/bookmarks">bookmarks</a></li>
1602 <li><a href="/branches">branches</a></li>
1602 <li><a href="/branches">branches</a></li>
1603 </ul>
1603 </ul>
1604 <ul>
1604 <ul>
1605 <li><a href="/rev/8">changeset</a></li>
1605 <li><a href="/rev/8">changeset</a></li>
1606 <li><a href="/file/8">browse</a></li>
1606 <li><a href="/file/8">browse</a></li>
1607 </ul>
1607 </ul>
1608 <ul>
1608 <ul>
1609 <li><a href="/file/8/c">file</a></li>
1609 <li><a href="/file/8/c">file</a></li>
1610 <li><a href="/diff/8/c">diff</a></li>
1610 <li><a href="/diff/8/c">diff</a></li>
1611 <li><a href="/comparison/8/c">comparison</a></li>
1611 <li><a href="/comparison/8/c">comparison</a></li>
1612 <li><a href="/annotate/8/c">annotate</a></li>
1612 <li><a href="/annotate/8/c">annotate</a></li>
1613 <li class="active">file log</li>
1613 <li class="active">file log</li>
1614 <li><a href="/raw-file/8/c">raw</a></li>
1614 <li><a href="/raw-file/8/c">raw</a></li>
1615 </ul>
1615 </ul>
1616 <ul>
1616 <ul>
1617 <li><a href="/help">help</a></li>
1617 <li><a href="/help">help</a></li>
1618 </ul>
1618 </ul>
1619 <div class="atom-logo">
1619 <div class="atom-logo">
1620 <a href="/atom-log/tip/c" title="subscribe to atom feed">
1620 <a href="/atom-log/tip/c" title="subscribe to atom feed">
1621 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="atom feed" />
1621 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="atom feed" />
1622 </a>
1622 </a>
1623 </div>
1623 </div>
1624 </div>
1624 </div>
1625
1625
1626 <div class="main">
1626 <div class="main">
1627 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
1627 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
1628 <h3>
1628 <h3>
1629 log c @ 8:<a href="/rev/5c6574614c37">5c6574614c37</a>
1629 log c @ 8:<a href="/rev/5c6574614c37">5c6574614c37</a>
1630 <span class="branchname">a-branch</span>
1630 <span class="branchname">a-branch</span>
1631 (following lines 3:4, descending <a href="/log/8/c">back to filelog</a>)
1631 (following lines 3:4, descending <a href="/log/8/c">back to filelog</a>)
1632 </h3>
1632 </h3>
1633
1633
1634 <form class="search" action="/log">
1634 <form class="search" action="/log">
1635
1635
1636 <p><input name="rev" id="search1" type="text" size="30" /></p>
1636 <p><input name="rev" id="search1" type="text" size="30" /></p>
1637 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
1637 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
1638 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
1638 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
1639 </form>
1639 </form>
1640
1640
1641 <div class="navigate">
1641 <div class="navigate">
1642 <a href="/log/8/c?descend=&linerange=3%3A4&revcount=30">less</a>
1642 <a href="/log/8/c?descend=&linerange=3%3A4&revcount=30">less</a>
1643 <a href="/log/8/c?descend=&linerange=3%3A4&revcount=120">more</a>
1643 <a href="/log/8/c?descend=&linerange=3%3A4&revcount=120">more</a>
1644 | </div>
1644 | </div>
1645
1645
1646 <table class="bigtable">
1646 <table class="bigtable">
1647 <thead>
1647 <thead>
1648 <tr>
1648 <tr>
1649 <th class="age">age</th>
1649 <th class="age">age</th>
1650 <th class="author">author</th>
1650 <th class="author">author</th>
1651 <th class="description">description</th>
1651 <th class="description">description</th>
1652 </tr>
1652 </tr>
1653 </thead>
1653 </thead>
1654 <tbody class="stripes2">
1654 <tbody class="stripes2">
1655 <tr>
1655 <tr>
1656 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
1656 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
1657 <td class="author">test</td>
1657 <td class="author">test</td>
1658 <td class="description">
1658 <td class="description">
1659 <a href="/rev/5c6574614c37">make c bigger and touch its beginning</a>
1659 <a href="/rev/5c6574614c37">make c bigger and touch its beginning</a>
1660 <span class="branchname">a-branch</span>
1660 <span class="branchname">a-branch</span>
1661 </td>
1661 </td>
1662 </tr>
1662 </tr>
1663
1663
1664 <tr>
1664 <tr>
1665 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
1665 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
1666 <td class="author">test</td>
1666 <td class="author">test</td>
1667 <td class="description">
1667 <td class="description">
1668 <a href="/rev/e95928d60479">touch beginning of c</a>
1668 <a href="/rev/e95928d60479">touch beginning of c</a>
1669 <span class="branchname">a-branch</span>
1669 <span class="branchname">a-branch</span>
1670 </td>
1670 </td>
1671 </tr>
1671 </tr>
1672
1672
1673 <tr>
1673 <tr>
1674 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
1674 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
1675 <td class="author">test</td>
1675 <td class="author">test</td>
1676 <td class="description">
1676 <td class="description">
1677 <a href="/rev/fb9bc322513a">touching beginning and end of c</a>
1677 <a href="/rev/fb9bc322513a">touching beginning and end of c</a>
1678 <span class="branchhead">a-branch</span> <span class="tag">tip</span>
1678 <span class="branchname">a-branch</span>
1679 </td>
1679 </td>
1680 </tr>
1680 </tr>
1681
1681
1682
1682
1683 </tbody>
1683 </tbody>
1684 </table>
1684 </table>
1685
1685
1686 <div class="navigate">
1686 <div class="navigate">
1687 <a href="/log/8/c?descend=&linerange=3%3A4&revcount=30">less</a>
1687 <a href="/log/8/c?descend=&linerange=3%3A4&revcount=30">less</a>
1688 <a href="/log/8/c?descend=&linerange=3%3A4&revcount=120">more</a>
1688 <a href="/log/8/c?descend=&linerange=3%3A4&revcount=120">more</a>
1689 |
1689 |
1690 </div>
1690 </div>
1691
1691
1692 </div>
1692 </div>
1693 </div>
1693 </div>
1694
1694
1695
1695
1696
1696
1697 </body>
1697 </body>
1698 </html>
1698 </html>
1699
1699
1700
1700
1701 rss log
1701 rss log
1702
1702
1703 $ (get-with-headers.py localhost:$HGPORT 'rss-log/tip/a')
1703 $ (get-with-headers.py localhost:$HGPORT 'rss-log/tip/a')
1704 200 Script output follows
1704 200 Script output follows
1705
1705
1706 <?xml version="1.0" encoding="ascii"?>
1706 <?xml version="1.0" encoding="ascii"?>
1707 <rss version="2.0">
1707 <rss version="2.0">
1708 <channel>
1708 <channel>
1709 <link>http://*:$HGPORT/</link> (glob)
1709 <link>http://*:$HGPORT/</link> (glob)
1710 <language>en-us</language>
1710 <language>en-us</language>
1711
1711
1712 <title>test: a history</title>
1712 <title>test: a history</title>
1713 <description>a revision history</description>
1713 <description>a revision history</description>
1714 <item>
1714 <item>
1715 <title>second a</title>
1715 <title>second a</title>
1716 <link>http://*:$HGPORT/log/3f41bc784e7e/a</link> (glob)
1716 <link>http://*:$HGPORT/log/3f41bc784e7e/a</link> (glob)
1717 <description><![CDATA[second a]]></description>
1717 <description><![CDATA[second a]]></description>
1718 <author>&#116;&#101;&#115;&#116;</author>
1718 <author>&#116;&#101;&#115;&#116;</author>
1719 <pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate>
1719 <pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate>
1720 </item>
1720 </item>
1721 <item>
1721 <item>
1722 <title>first a</title>
1722 <title>first a</title>
1723 <link>http://*:$HGPORT/log/5ed941583260/a</link> (glob)
1723 <link>http://*:$HGPORT/log/5ed941583260/a</link> (glob)
1724 <description><![CDATA[first a]]></description>
1724 <description><![CDATA[first a]]></description>
1725 <author>&#116;&#101;&#115;&#116;</author>
1725 <author>&#116;&#101;&#115;&#116;</author>
1726 <pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate>
1726 <pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate>
1727 </item>
1727 </item>
1728
1728
1729 </channel>
1729 </channel>
1730 </rss>
1730 </rss>
1731
1731
1732 atom log
1732 atom log
1733
1733
1734 $ (get-with-headers.py localhost:$HGPORT 'atom-log/tip/a')
1734 $ (get-with-headers.py localhost:$HGPORT 'atom-log/tip/a')
1735 200 Script output follows
1735 200 Script output follows
1736
1736
1737 <?xml version="1.0" encoding="ascii"?>
1737 <?xml version="1.0" encoding="ascii"?>
1738 <feed xmlns="http://www.w3.org/2005/Atom">
1738 <feed xmlns="http://www.w3.org/2005/Atom">
1739 <id>http://*:$HGPORT/atom-log/tip/a</id> (glob)
1739 <id>http://*:$HGPORT/atom-log/tip/a</id> (glob)
1740 <link rel="self" href="http://*:$HGPORT/atom-log/tip/a"/> (glob)
1740 <link rel="self" href="http://*:$HGPORT/atom-log/tip/a"/> (glob)
1741 <title>test: a history</title>
1741 <title>test: a history</title>
1742 <updated>1970-01-01T00:00:00+00:00</updated>
1742 <updated>1970-01-01T00:00:00+00:00</updated>
1743
1743
1744 <entry>
1744 <entry>
1745 <title>[a-branch] second a</title>
1745 <title>[a-branch] second a</title>
1746 <id>http://*:$HGPORT/#changeset-3f41bc784e7e73035c6d47112c6cc7efb673adf8</id> (glob)
1746 <id>http://*:$HGPORT/#changeset-3f41bc784e7e73035c6d47112c6cc7efb673adf8</id> (glob)
1747 <link href="http://*:$HGPORT/rev/3f41bc784e7e"/> (glob)
1747 <link href="http://*:$HGPORT/rev/3f41bc784e7e"/> (glob)
1748 <author>
1748 <author>
1749 <name>test</name>
1749 <name>test</name>
1750 <email>&#116;&#101;&#115;&#116;</email>
1750 <email>&#116;&#101;&#115;&#116;</email>
1751 </author>
1751 </author>
1752 <updated>1970-01-01T00:00:00+00:00</updated>
1752 <updated>1970-01-01T00:00:00+00:00</updated>
1753 <published>1970-01-01T00:00:00+00:00</published>
1753 <published>1970-01-01T00:00:00+00:00</published>
1754 <content type="xhtml">
1754 <content type="xhtml">
1755 <table xmlns="http://www.w3.org/1999/xhtml">
1755 <table xmlns="http://www.w3.org/1999/xhtml">
1756 <tr>
1756 <tr>
1757 <th style="text-align:left;">changeset</th>
1757 <th style="text-align:left;">changeset</th>
1758 <td>3f41bc784e7e</td>
1758 <td>3f41bc784e7e</td>
1759 </tr>
1759 </tr>
1760 <tr>
1760 <tr>
1761 <th style="text-align:left;">branch</th>
1761 <th style="text-align:left;">branch</th>
1762 <td>a-branch</td>
1762 <td>a-branch</td>
1763 </tr>
1763 </tr>
1764 <tr>
1764 <tr>
1765 <th style="text-align:left;">bookmark</th>
1765 <th style="text-align:left;">bookmark</th>
1766 <td></td>
1766 <td></td>
1767 </tr>
1767 </tr>
1768 <tr>
1768 <tr>
1769 <th style="text-align:left;">tag</th>
1769 <th style="text-align:left;">tag</th>
1770 <td></td>
1770 <td></td>
1771 </tr>
1771 </tr>
1772 <tr>
1772 <tr>
1773 <th style="text-align:left;">user</th>
1773 <th style="text-align:left;">user</th>
1774 <td>&#116;&#101;&#115;&#116;</td>
1774 <td>&#116;&#101;&#115;&#116;</td>
1775 </tr>
1775 </tr>
1776 <tr>
1776 <tr>
1777 <th style="text-align:left;vertical-align:top;">description</th>
1777 <th style="text-align:left;vertical-align:top;">description</th>
1778 <td>second a</td>
1778 <td>second a</td>
1779 </tr>
1779 </tr>
1780 <tr>
1780 <tr>
1781 <th style="text-align:left;vertical-align:top;">files</th>
1781 <th style="text-align:left;vertical-align:top;">files</th>
1782 <td></td>
1782 <td></td>
1783 </tr>
1783 </tr>
1784 </table>
1784 </table>
1785 </content>
1785 </content>
1786 </entry>
1786 </entry>
1787 <entry>
1787 <entry>
1788 <title>first a</title>
1788 <title>first a</title>
1789 <id>http://*:$HGPORT/#changeset-5ed941583260248620985524192fdc382ef57c36</id> (glob)
1789 <id>http://*:$HGPORT/#changeset-5ed941583260248620985524192fdc382ef57c36</id> (glob)
1790 <link href="http://*:$HGPORT/rev/5ed941583260"/> (glob)
1790 <link href="http://*:$HGPORT/rev/5ed941583260"/> (glob)
1791 <author>
1791 <author>
1792 <name>test</name>
1792 <name>test</name>
1793 <email>&#116;&#101;&#115;&#116;</email>
1793 <email>&#116;&#101;&#115;&#116;</email>
1794 </author>
1794 </author>
1795 <updated>1970-01-01T00:00:00+00:00</updated>
1795 <updated>1970-01-01T00:00:00+00:00</updated>
1796 <published>1970-01-01T00:00:00+00:00</published>
1796 <published>1970-01-01T00:00:00+00:00</published>
1797 <content type="xhtml">
1797 <content type="xhtml">
1798 <table xmlns="http://www.w3.org/1999/xhtml">
1798 <table xmlns="http://www.w3.org/1999/xhtml">
1799 <tr>
1799 <tr>
1800 <th style="text-align:left;">changeset</th>
1800 <th style="text-align:left;">changeset</th>
1801 <td>5ed941583260</td>
1801 <td>5ed941583260</td>
1802 </tr>
1802 </tr>
1803 <tr>
1803 <tr>
1804 <th style="text-align:left;">branch</th>
1804 <th style="text-align:left;">branch</th>
1805 <td></td>
1805 <td></td>
1806 </tr>
1806 </tr>
1807 <tr>
1807 <tr>
1808 <th style="text-align:left;">bookmark</th>
1808 <th style="text-align:left;">bookmark</th>
1809 <td>a-bookmark</td>
1809 <td>a-bookmark</td>
1810 </tr>
1810 </tr>
1811 <tr>
1811 <tr>
1812 <th style="text-align:left;">tag</th>
1812 <th style="text-align:left;">tag</th>
1813 <td>a-tag</td>
1813 <td>a-tag</td>
1814 </tr>
1814 </tr>
1815 <tr>
1815 <tr>
1816 <th style="text-align:left;">user</th>
1816 <th style="text-align:left;">user</th>
1817 <td>&#116;&#101;&#115;&#116;</td>
1817 <td>&#116;&#101;&#115;&#116;</td>
1818 </tr>
1818 </tr>
1819 <tr>
1819 <tr>
1820 <th style="text-align:left;vertical-align:top;">description</th>
1820 <th style="text-align:left;vertical-align:top;">description</th>
1821 <td>first a</td>
1821 <td>first a</td>
1822 </tr>
1822 </tr>
1823 <tr>
1823 <tr>
1824 <th style="text-align:left;vertical-align:top;">files</th>
1824 <th style="text-align:left;vertical-align:top;">files</th>
1825 <td></td>
1825 <td></td>
1826 </tr>
1826 </tr>
1827 </table>
1827 </table>
1828 </content>
1828 </content>
1829 </entry>
1829 </entry>
1830
1830
1831 </feed>
1831 </feed>
1832
1832
1833 errors
1833 errors
1834
1834
1835 $ cat errors.log
1835 $ cat errors.log
1836
1836
1837 $ cd ..
1837 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now