##// END OF EJS Templates
log: use revsetlang.formatspec() to concatenate list expression...
Yuya Nishihara -
r35662:7a0a90d6 default
parent child Browse files
Show More
@@ -1,3930 +1,3932 b''
1 # cmdutil.py - help for command processing in mercurial
1 # cmdutil.py - help for command processing in mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-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 itertools
11 import itertools
12 import os
12 import os
13 import re
13 import re
14 import tempfile
14 import tempfile
15
15
16 from .i18n import _
16 from .i18n import _
17 from .node import (
17 from .node import (
18 hex,
18 hex,
19 nullid,
19 nullid,
20 nullrev,
20 nullrev,
21 short,
21 short,
22 )
22 )
23
23
24 from . import (
24 from . import (
25 bookmarks,
25 bookmarks,
26 changelog,
26 changelog,
27 copies,
27 copies,
28 crecord as crecordmod,
28 crecord as crecordmod,
29 dagop,
29 dagop,
30 dirstateguard,
30 dirstateguard,
31 encoding,
31 encoding,
32 error,
32 error,
33 formatter,
33 formatter,
34 graphmod,
34 graphmod,
35 match as matchmod,
35 match as matchmod,
36 mdiff,
36 mdiff,
37 obsolete,
37 obsolete,
38 patch,
38 patch,
39 pathutil,
39 pathutil,
40 pycompat,
40 pycompat,
41 registrar,
41 registrar,
42 revlog,
42 revlog,
43 revset,
43 revset,
44 revsetlang,
44 scmutil,
45 scmutil,
45 smartset,
46 smartset,
46 templatekw,
47 templatekw,
47 templater,
48 templater,
48 util,
49 util,
49 vfs as vfsmod,
50 vfs as vfsmod,
50 )
51 )
51 stringio = util.stringio
52 stringio = util.stringio
52
53
53 # templates of common command options
54 # templates of common command options
54
55
55 dryrunopts = [
56 dryrunopts = [
56 ('n', 'dry-run', None,
57 ('n', 'dry-run', None,
57 _('do not perform actions, just print output')),
58 _('do not perform actions, just print output')),
58 ]
59 ]
59
60
60 remoteopts = [
61 remoteopts = [
61 ('e', 'ssh', '',
62 ('e', 'ssh', '',
62 _('specify ssh command to use'), _('CMD')),
63 _('specify ssh command to use'), _('CMD')),
63 ('', 'remotecmd', '',
64 ('', 'remotecmd', '',
64 _('specify hg command to run on the remote side'), _('CMD')),
65 _('specify hg command to run on the remote side'), _('CMD')),
65 ('', 'insecure', None,
66 ('', 'insecure', None,
66 _('do not verify server certificate (ignoring web.cacerts config)')),
67 _('do not verify server certificate (ignoring web.cacerts config)')),
67 ]
68 ]
68
69
69 walkopts = [
70 walkopts = [
70 ('I', 'include', [],
71 ('I', 'include', [],
71 _('include names matching the given patterns'), _('PATTERN')),
72 _('include names matching the given patterns'), _('PATTERN')),
72 ('X', 'exclude', [],
73 ('X', 'exclude', [],
73 _('exclude names matching the given patterns'), _('PATTERN')),
74 _('exclude names matching the given patterns'), _('PATTERN')),
74 ]
75 ]
75
76
76 commitopts = [
77 commitopts = [
77 ('m', 'message', '',
78 ('m', 'message', '',
78 _('use text as commit message'), _('TEXT')),
79 _('use text as commit message'), _('TEXT')),
79 ('l', 'logfile', '',
80 ('l', 'logfile', '',
80 _('read commit message from file'), _('FILE')),
81 _('read commit message from file'), _('FILE')),
81 ]
82 ]
82
83
83 commitopts2 = [
84 commitopts2 = [
84 ('d', 'date', '',
85 ('d', 'date', '',
85 _('record the specified date as commit date'), _('DATE')),
86 _('record the specified date as commit date'), _('DATE')),
86 ('u', 'user', '',
87 ('u', 'user', '',
87 _('record the specified user as committer'), _('USER')),
88 _('record the specified user as committer'), _('USER')),
88 ]
89 ]
89
90
90 # hidden for now
91 # hidden for now
91 formatteropts = [
92 formatteropts = [
92 ('T', 'template', '',
93 ('T', 'template', '',
93 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
94 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
94 ]
95 ]
95
96
96 templateopts = [
97 templateopts = [
97 ('', 'style', '',
98 ('', 'style', '',
98 _('display using template map file (DEPRECATED)'), _('STYLE')),
99 _('display using template map file (DEPRECATED)'), _('STYLE')),
99 ('T', 'template', '',
100 ('T', 'template', '',
100 _('display with template'), _('TEMPLATE')),
101 _('display with template'), _('TEMPLATE')),
101 ]
102 ]
102
103
103 logopts = [
104 logopts = [
104 ('p', 'patch', None, _('show patch')),
105 ('p', 'patch', None, _('show patch')),
105 ('g', 'git', None, _('use git extended diff format')),
106 ('g', 'git', None, _('use git extended diff format')),
106 ('l', 'limit', '',
107 ('l', 'limit', '',
107 _('limit number of changes displayed'), _('NUM')),
108 _('limit number of changes displayed'), _('NUM')),
108 ('M', 'no-merges', None, _('do not show merges')),
109 ('M', 'no-merges', None, _('do not show merges')),
109 ('', 'stat', None, _('output diffstat-style summary of changes')),
110 ('', 'stat', None, _('output diffstat-style summary of changes')),
110 ('G', 'graph', None, _("show the revision DAG")),
111 ('G', 'graph', None, _("show the revision DAG")),
111 ] + templateopts
112 ] + templateopts
112
113
113 diffopts = [
114 diffopts = [
114 ('a', 'text', None, _('treat all files as text')),
115 ('a', 'text', None, _('treat all files as text')),
115 ('g', 'git', None, _('use git extended diff format')),
116 ('g', 'git', None, _('use git extended diff format')),
116 ('', 'binary', None, _('generate binary diffs in git mode (default)')),
117 ('', 'binary', None, _('generate binary diffs in git mode (default)')),
117 ('', 'nodates', None, _('omit dates from diff headers'))
118 ('', 'nodates', None, _('omit dates from diff headers'))
118 ]
119 ]
119
120
120 diffwsopts = [
121 diffwsopts = [
121 ('w', 'ignore-all-space', None,
122 ('w', 'ignore-all-space', None,
122 _('ignore white space when comparing lines')),
123 _('ignore white space when comparing lines')),
123 ('b', 'ignore-space-change', None,
124 ('b', 'ignore-space-change', None,
124 _('ignore changes in the amount of white space')),
125 _('ignore changes in the amount of white space')),
125 ('B', 'ignore-blank-lines', None,
126 ('B', 'ignore-blank-lines', None,
126 _('ignore changes whose lines are all blank')),
127 _('ignore changes whose lines are all blank')),
127 ('Z', 'ignore-space-at-eol', None,
128 ('Z', 'ignore-space-at-eol', None,
128 _('ignore changes in whitespace at EOL')),
129 _('ignore changes in whitespace at EOL')),
129 ]
130 ]
130
131
131 diffopts2 = [
132 diffopts2 = [
132 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
133 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
133 ('p', 'show-function', None, _('show which function each change is in')),
134 ('p', 'show-function', None, _('show which function each change is in')),
134 ('', 'reverse', None, _('produce a diff that undoes the changes')),
135 ('', 'reverse', None, _('produce a diff that undoes the changes')),
135 ] + diffwsopts + [
136 ] + diffwsopts + [
136 ('U', 'unified', '',
137 ('U', 'unified', '',
137 _('number of lines of context to show'), _('NUM')),
138 _('number of lines of context to show'), _('NUM')),
138 ('', 'stat', None, _('output diffstat-style summary of changes')),
139 ('', 'stat', None, _('output diffstat-style summary of changes')),
139 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
140 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
140 ]
141 ]
141
142
142 mergetoolopts = [
143 mergetoolopts = [
143 ('t', 'tool', '', _('specify merge tool')),
144 ('t', 'tool', '', _('specify merge tool')),
144 ]
145 ]
145
146
146 similarityopts = [
147 similarityopts = [
147 ('s', 'similarity', '',
148 ('s', 'similarity', '',
148 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
149 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
149 ]
150 ]
150
151
151 subrepoopts = [
152 subrepoopts = [
152 ('S', 'subrepos', None,
153 ('S', 'subrepos', None,
153 _('recurse into subrepositories'))
154 _('recurse into subrepositories'))
154 ]
155 ]
155
156
156 debugrevlogopts = [
157 debugrevlogopts = [
157 ('c', 'changelog', False, _('open changelog')),
158 ('c', 'changelog', False, _('open changelog')),
158 ('m', 'manifest', False, _('open manifest')),
159 ('m', 'manifest', False, _('open manifest')),
159 ('', 'dir', '', _('open directory manifest')),
160 ('', 'dir', '', _('open directory manifest')),
160 ]
161 ]
161
162
162 # special string such that everything below this line will be ingored in the
163 # special string such that everything below this line will be ingored in the
163 # editor text
164 # editor text
164 _linebelow = "^HG: ------------------------ >8 ------------------------$"
165 _linebelow = "^HG: ------------------------ >8 ------------------------$"
165
166
166 def ishunk(x):
167 def ishunk(x):
167 hunkclasses = (crecordmod.uihunk, patch.recordhunk)
168 hunkclasses = (crecordmod.uihunk, patch.recordhunk)
168 return isinstance(x, hunkclasses)
169 return isinstance(x, hunkclasses)
169
170
170 def newandmodified(chunks, originalchunks):
171 def newandmodified(chunks, originalchunks):
171 newlyaddedandmodifiedfiles = set()
172 newlyaddedandmodifiedfiles = set()
172 for chunk in chunks:
173 for chunk in chunks:
173 if ishunk(chunk) and chunk.header.isnewfile() and chunk not in \
174 if ishunk(chunk) and chunk.header.isnewfile() and chunk not in \
174 originalchunks:
175 originalchunks:
175 newlyaddedandmodifiedfiles.add(chunk.header.filename())
176 newlyaddedandmodifiedfiles.add(chunk.header.filename())
176 return newlyaddedandmodifiedfiles
177 return newlyaddedandmodifiedfiles
177
178
178 def parsealiases(cmd):
179 def parsealiases(cmd):
179 return cmd.lstrip("^").split("|")
180 return cmd.lstrip("^").split("|")
180
181
181 def setupwrapcolorwrite(ui):
182 def setupwrapcolorwrite(ui):
182 # wrap ui.write so diff output can be labeled/colorized
183 # wrap ui.write so diff output can be labeled/colorized
183 def wrapwrite(orig, *args, **kw):
184 def wrapwrite(orig, *args, **kw):
184 label = kw.pop(r'label', '')
185 label = kw.pop(r'label', '')
185 for chunk, l in patch.difflabel(lambda: args):
186 for chunk, l in patch.difflabel(lambda: args):
186 orig(chunk, label=label + l)
187 orig(chunk, label=label + l)
187
188
188 oldwrite = ui.write
189 oldwrite = ui.write
189 def wrap(*args, **kwargs):
190 def wrap(*args, **kwargs):
190 return wrapwrite(oldwrite, *args, **kwargs)
191 return wrapwrite(oldwrite, *args, **kwargs)
191 setattr(ui, 'write', wrap)
192 setattr(ui, 'write', wrap)
192 return oldwrite
193 return oldwrite
193
194
194 def filterchunks(ui, originalhunks, usecurses, testfile, operation=None):
195 def filterchunks(ui, originalhunks, usecurses, testfile, operation=None):
195 if usecurses:
196 if usecurses:
196 if testfile:
197 if testfile:
197 recordfn = crecordmod.testdecorator(testfile,
198 recordfn = crecordmod.testdecorator(testfile,
198 crecordmod.testchunkselector)
199 crecordmod.testchunkselector)
199 else:
200 else:
200 recordfn = crecordmod.chunkselector
201 recordfn = crecordmod.chunkselector
201
202
202 return crecordmod.filterpatch(ui, originalhunks, recordfn, operation)
203 return crecordmod.filterpatch(ui, originalhunks, recordfn, operation)
203
204
204 else:
205 else:
205 return patch.filterpatch(ui, originalhunks, operation)
206 return patch.filterpatch(ui, originalhunks, operation)
206
207
207 def recordfilter(ui, originalhunks, operation=None):
208 def recordfilter(ui, originalhunks, operation=None):
208 """ Prompts the user to filter the originalhunks and return a list of
209 """ Prompts the user to filter the originalhunks and return a list of
209 selected hunks.
210 selected hunks.
210 *operation* is used for to build ui messages to indicate the user what
211 *operation* is used for to build ui messages to indicate the user what
211 kind of filtering they are doing: reverting, committing, shelving, etc.
212 kind of filtering they are doing: reverting, committing, shelving, etc.
212 (see patch.filterpatch).
213 (see patch.filterpatch).
213 """
214 """
214 usecurses = crecordmod.checkcurses(ui)
215 usecurses = crecordmod.checkcurses(ui)
215 testfile = ui.config('experimental', 'crecordtest')
216 testfile = ui.config('experimental', 'crecordtest')
216 oldwrite = setupwrapcolorwrite(ui)
217 oldwrite = setupwrapcolorwrite(ui)
217 try:
218 try:
218 newchunks, newopts = filterchunks(ui, originalhunks, usecurses,
219 newchunks, newopts = filterchunks(ui, originalhunks, usecurses,
219 testfile, operation)
220 testfile, operation)
220 finally:
221 finally:
221 ui.write = oldwrite
222 ui.write = oldwrite
222 return newchunks, newopts
223 return newchunks, newopts
223
224
224 def dorecord(ui, repo, commitfunc, cmdsuggest, backupall,
225 def dorecord(ui, repo, commitfunc, cmdsuggest, backupall,
225 filterfn, *pats, **opts):
226 filterfn, *pats, **opts):
226 from . import merge as mergemod
227 from . import merge as mergemod
227 opts = pycompat.byteskwargs(opts)
228 opts = pycompat.byteskwargs(opts)
228 if not ui.interactive():
229 if not ui.interactive():
229 if cmdsuggest:
230 if cmdsuggest:
230 msg = _('running non-interactively, use %s instead') % cmdsuggest
231 msg = _('running non-interactively, use %s instead') % cmdsuggest
231 else:
232 else:
232 msg = _('running non-interactively')
233 msg = _('running non-interactively')
233 raise error.Abort(msg)
234 raise error.Abort(msg)
234
235
235 # make sure username is set before going interactive
236 # make sure username is set before going interactive
236 if not opts.get('user'):
237 if not opts.get('user'):
237 ui.username() # raise exception, username not provided
238 ui.username() # raise exception, username not provided
238
239
239 def recordfunc(ui, repo, message, match, opts):
240 def recordfunc(ui, repo, message, match, opts):
240 """This is generic record driver.
241 """This is generic record driver.
241
242
242 Its job is to interactively filter local changes, and
243 Its job is to interactively filter local changes, and
243 accordingly prepare working directory into a state in which the
244 accordingly prepare working directory into a state in which the
244 job can be delegated to a non-interactive commit command such as
245 job can be delegated to a non-interactive commit command such as
245 'commit' or 'qrefresh'.
246 'commit' or 'qrefresh'.
246
247
247 After the actual job is done by non-interactive command, the
248 After the actual job is done by non-interactive command, the
248 working directory is restored to its original state.
249 working directory is restored to its original state.
249
250
250 In the end we'll record interesting changes, and everything else
251 In the end we'll record interesting changes, and everything else
251 will be left in place, so the user can continue working.
252 will be left in place, so the user can continue working.
252 """
253 """
253
254
254 checkunfinished(repo, commit=True)
255 checkunfinished(repo, commit=True)
255 wctx = repo[None]
256 wctx = repo[None]
256 merge = len(wctx.parents()) > 1
257 merge = len(wctx.parents()) > 1
257 if merge:
258 if merge:
258 raise error.Abort(_('cannot partially commit a merge '
259 raise error.Abort(_('cannot partially commit a merge '
259 '(use "hg commit" instead)'))
260 '(use "hg commit" instead)'))
260
261
261 def fail(f, msg):
262 def fail(f, msg):
262 raise error.Abort('%s: %s' % (f, msg))
263 raise error.Abort('%s: %s' % (f, msg))
263
264
264 force = opts.get('force')
265 force = opts.get('force')
265 if not force:
266 if not force:
266 vdirs = []
267 vdirs = []
267 match.explicitdir = vdirs.append
268 match.explicitdir = vdirs.append
268 match.bad = fail
269 match.bad = fail
269
270
270 status = repo.status(match=match)
271 status = repo.status(match=match)
271 if not force:
272 if not force:
272 repo.checkcommitpatterns(wctx, vdirs, match, status, fail)
273 repo.checkcommitpatterns(wctx, vdirs, match, status, fail)
273 diffopts = patch.difffeatureopts(ui, opts=opts, whitespace=True)
274 diffopts = patch.difffeatureopts(ui, opts=opts, whitespace=True)
274 diffopts.nodates = True
275 diffopts.nodates = True
275 diffopts.git = True
276 diffopts.git = True
276 diffopts.showfunc = True
277 diffopts.showfunc = True
277 originaldiff = patch.diff(repo, changes=status, opts=diffopts)
278 originaldiff = patch.diff(repo, changes=status, opts=diffopts)
278 originalchunks = patch.parsepatch(originaldiff)
279 originalchunks = patch.parsepatch(originaldiff)
279
280
280 # 1. filter patch, since we are intending to apply subset of it
281 # 1. filter patch, since we are intending to apply subset of it
281 try:
282 try:
282 chunks, newopts = filterfn(ui, originalchunks)
283 chunks, newopts = filterfn(ui, originalchunks)
283 except error.PatchError as err:
284 except error.PatchError as err:
284 raise error.Abort(_('error parsing patch: %s') % err)
285 raise error.Abort(_('error parsing patch: %s') % err)
285 opts.update(newopts)
286 opts.update(newopts)
286
287
287 # We need to keep a backup of files that have been newly added and
288 # We need to keep a backup of files that have been newly added and
288 # modified during the recording process because there is a previous
289 # modified during the recording process because there is a previous
289 # version without the edit in the workdir
290 # version without the edit in the workdir
290 newlyaddedandmodifiedfiles = newandmodified(chunks, originalchunks)
291 newlyaddedandmodifiedfiles = newandmodified(chunks, originalchunks)
291 contenders = set()
292 contenders = set()
292 for h in chunks:
293 for h in chunks:
293 try:
294 try:
294 contenders.update(set(h.files()))
295 contenders.update(set(h.files()))
295 except AttributeError:
296 except AttributeError:
296 pass
297 pass
297
298
298 changed = status.modified + status.added + status.removed
299 changed = status.modified + status.added + status.removed
299 newfiles = [f for f in changed if f in contenders]
300 newfiles = [f for f in changed if f in contenders]
300 if not newfiles:
301 if not newfiles:
301 ui.status(_('no changes to record\n'))
302 ui.status(_('no changes to record\n'))
302 return 0
303 return 0
303
304
304 modified = set(status.modified)
305 modified = set(status.modified)
305
306
306 # 2. backup changed files, so we can restore them in the end
307 # 2. backup changed files, so we can restore them in the end
307
308
308 if backupall:
309 if backupall:
309 tobackup = changed
310 tobackup = changed
310 else:
311 else:
311 tobackup = [f for f in newfiles if f in modified or f in \
312 tobackup = [f for f in newfiles if f in modified or f in \
312 newlyaddedandmodifiedfiles]
313 newlyaddedandmodifiedfiles]
313 backups = {}
314 backups = {}
314 if tobackup:
315 if tobackup:
315 backupdir = repo.vfs.join('record-backups')
316 backupdir = repo.vfs.join('record-backups')
316 try:
317 try:
317 os.mkdir(backupdir)
318 os.mkdir(backupdir)
318 except OSError as err:
319 except OSError as err:
319 if err.errno != errno.EEXIST:
320 if err.errno != errno.EEXIST:
320 raise
321 raise
321 try:
322 try:
322 # backup continues
323 # backup continues
323 for f in tobackup:
324 for f in tobackup:
324 fd, tmpname = tempfile.mkstemp(prefix=f.replace('/', '_')+'.',
325 fd, tmpname = tempfile.mkstemp(prefix=f.replace('/', '_')+'.',
325 dir=backupdir)
326 dir=backupdir)
326 os.close(fd)
327 os.close(fd)
327 ui.debug('backup %r as %r\n' % (f, tmpname))
328 ui.debug('backup %r as %r\n' % (f, tmpname))
328 util.copyfile(repo.wjoin(f), tmpname, copystat=True)
329 util.copyfile(repo.wjoin(f), tmpname, copystat=True)
329 backups[f] = tmpname
330 backups[f] = tmpname
330
331
331 fp = stringio()
332 fp = stringio()
332 for c in chunks:
333 for c in chunks:
333 fname = c.filename()
334 fname = c.filename()
334 if fname in backups:
335 if fname in backups:
335 c.write(fp)
336 c.write(fp)
336 dopatch = fp.tell()
337 dopatch = fp.tell()
337 fp.seek(0)
338 fp.seek(0)
338
339
339 # 2.5 optionally review / modify patch in text editor
340 # 2.5 optionally review / modify patch in text editor
340 if opts.get('review', False):
341 if opts.get('review', False):
341 patchtext = (crecordmod.diffhelptext
342 patchtext = (crecordmod.diffhelptext
342 + crecordmod.patchhelptext
343 + crecordmod.patchhelptext
343 + fp.read())
344 + fp.read())
344 reviewedpatch = ui.edit(patchtext, "",
345 reviewedpatch = ui.edit(patchtext, "",
345 action="diff",
346 action="diff",
346 repopath=repo.path)
347 repopath=repo.path)
347 fp.truncate(0)
348 fp.truncate(0)
348 fp.write(reviewedpatch)
349 fp.write(reviewedpatch)
349 fp.seek(0)
350 fp.seek(0)
350
351
351 [os.unlink(repo.wjoin(c)) for c in newlyaddedandmodifiedfiles]
352 [os.unlink(repo.wjoin(c)) for c in newlyaddedandmodifiedfiles]
352 # 3a. apply filtered patch to clean repo (clean)
353 # 3a. apply filtered patch to clean repo (clean)
353 if backups:
354 if backups:
354 # Equivalent to hg.revert
355 # Equivalent to hg.revert
355 m = scmutil.matchfiles(repo, backups.keys())
356 m = scmutil.matchfiles(repo, backups.keys())
356 mergemod.update(repo, repo.dirstate.p1(),
357 mergemod.update(repo, repo.dirstate.p1(),
357 False, True, matcher=m)
358 False, True, matcher=m)
358
359
359 # 3b. (apply)
360 # 3b. (apply)
360 if dopatch:
361 if dopatch:
361 try:
362 try:
362 ui.debug('applying patch\n')
363 ui.debug('applying patch\n')
363 ui.debug(fp.getvalue())
364 ui.debug(fp.getvalue())
364 patch.internalpatch(ui, repo, fp, 1, eolmode=None)
365 patch.internalpatch(ui, repo, fp, 1, eolmode=None)
365 except error.PatchError as err:
366 except error.PatchError as err:
366 raise error.Abort(str(err))
367 raise error.Abort(str(err))
367 del fp
368 del fp
368
369
369 # 4. We prepared working directory according to filtered
370 # 4. We prepared working directory according to filtered
370 # patch. Now is the time to delegate the job to
371 # patch. Now is the time to delegate the job to
371 # commit/qrefresh or the like!
372 # commit/qrefresh or the like!
372
373
373 # Make all of the pathnames absolute.
374 # Make all of the pathnames absolute.
374 newfiles = [repo.wjoin(nf) for nf in newfiles]
375 newfiles = [repo.wjoin(nf) for nf in newfiles]
375 return commitfunc(ui, repo, *newfiles, **pycompat.strkwargs(opts))
376 return commitfunc(ui, repo, *newfiles, **pycompat.strkwargs(opts))
376 finally:
377 finally:
377 # 5. finally restore backed-up files
378 # 5. finally restore backed-up files
378 try:
379 try:
379 dirstate = repo.dirstate
380 dirstate = repo.dirstate
380 for realname, tmpname in backups.iteritems():
381 for realname, tmpname in backups.iteritems():
381 ui.debug('restoring %r to %r\n' % (tmpname, realname))
382 ui.debug('restoring %r to %r\n' % (tmpname, realname))
382
383
383 if dirstate[realname] == 'n':
384 if dirstate[realname] == 'n':
384 # without normallookup, restoring timestamp
385 # without normallookup, restoring timestamp
385 # may cause partially committed files
386 # may cause partially committed files
386 # to be treated as unmodified
387 # to be treated as unmodified
387 dirstate.normallookup(realname)
388 dirstate.normallookup(realname)
388
389
389 # copystat=True here and above are a hack to trick any
390 # copystat=True here and above are a hack to trick any
390 # editors that have f open that we haven't modified them.
391 # editors that have f open that we haven't modified them.
391 #
392 #
392 # Also note that this racy as an editor could notice the
393 # Also note that this racy as an editor could notice the
393 # file's mtime before we've finished writing it.
394 # file's mtime before we've finished writing it.
394 util.copyfile(tmpname, repo.wjoin(realname), copystat=True)
395 util.copyfile(tmpname, repo.wjoin(realname), copystat=True)
395 os.unlink(tmpname)
396 os.unlink(tmpname)
396 if tobackup:
397 if tobackup:
397 os.rmdir(backupdir)
398 os.rmdir(backupdir)
398 except OSError:
399 except OSError:
399 pass
400 pass
400
401
401 def recordinwlock(ui, repo, message, match, opts):
402 def recordinwlock(ui, repo, message, match, opts):
402 with repo.wlock():
403 with repo.wlock():
403 return recordfunc(ui, repo, message, match, opts)
404 return recordfunc(ui, repo, message, match, opts)
404
405
405 return commit(ui, repo, recordinwlock, pats, opts)
406 return commit(ui, repo, recordinwlock, pats, opts)
406
407
407 class dirnode(object):
408 class dirnode(object):
408 """
409 """
409 Represent a directory in user working copy with information required for
410 Represent a directory in user working copy with information required for
410 the purpose of tersing its status.
411 the purpose of tersing its status.
411
412
412 path is the path to the directory
413 path is the path to the directory
413
414
414 statuses is a set of statuses of all files in this directory (this includes
415 statuses is a set of statuses of all files in this directory (this includes
415 all the files in all the subdirectories too)
416 all the files in all the subdirectories too)
416
417
417 files is a list of files which are direct child of this directory
418 files is a list of files which are direct child of this directory
418
419
419 subdirs is a dictionary of sub-directory name as the key and it's own
420 subdirs is a dictionary of sub-directory name as the key and it's own
420 dirnode object as the value
421 dirnode object as the value
421 """
422 """
422
423
423 def __init__(self, dirpath):
424 def __init__(self, dirpath):
424 self.path = dirpath
425 self.path = dirpath
425 self.statuses = set([])
426 self.statuses = set([])
426 self.files = []
427 self.files = []
427 self.subdirs = {}
428 self.subdirs = {}
428
429
429 def _addfileindir(self, filename, status):
430 def _addfileindir(self, filename, status):
430 """Add a file in this directory as a direct child."""
431 """Add a file in this directory as a direct child."""
431 self.files.append((filename, status))
432 self.files.append((filename, status))
432
433
433 def addfile(self, filename, status):
434 def addfile(self, filename, status):
434 """
435 """
435 Add a file to this directory or to its direct parent directory.
436 Add a file to this directory or to its direct parent directory.
436
437
437 If the file is not direct child of this directory, we traverse to the
438 If the file is not direct child of this directory, we traverse to the
438 directory of which this file is a direct child of and add the file
439 directory of which this file is a direct child of and add the file
439 there.
440 there.
440 """
441 """
441
442
442 # the filename contains a path separator, it means it's not the direct
443 # the filename contains a path separator, it means it's not the direct
443 # child of this directory
444 # child of this directory
444 if '/' in filename:
445 if '/' in filename:
445 subdir, filep = filename.split('/', 1)
446 subdir, filep = filename.split('/', 1)
446
447
447 # does the dirnode object for subdir exists
448 # does the dirnode object for subdir exists
448 if subdir not in self.subdirs:
449 if subdir not in self.subdirs:
449 subdirpath = os.path.join(self.path, subdir)
450 subdirpath = os.path.join(self.path, subdir)
450 self.subdirs[subdir] = dirnode(subdirpath)
451 self.subdirs[subdir] = dirnode(subdirpath)
451
452
452 # try adding the file in subdir
453 # try adding the file in subdir
453 self.subdirs[subdir].addfile(filep, status)
454 self.subdirs[subdir].addfile(filep, status)
454
455
455 else:
456 else:
456 self._addfileindir(filename, status)
457 self._addfileindir(filename, status)
457
458
458 if status not in self.statuses:
459 if status not in self.statuses:
459 self.statuses.add(status)
460 self.statuses.add(status)
460
461
461 def iterfilepaths(self):
462 def iterfilepaths(self):
462 """Yield (status, path) for files directly under this directory."""
463 """Yield (status, path) for files directly under this directory."""
463 for f, st in self.files:
464 for f, st in self.files:
464 yield st, os.path.join(self.path, f)
465 yield st, os.path.join(self.path, f)
465
466
466 def tersewalk(self, terseargs):
467 def tersewalk(self, terseargs):
467 """
468 """
468 Yield (status, path) obtained by processing the status of this
469 Yield (status, path) obtained by processing the status of this
469 dirnode.
470 dirnode.
470
471
471 terseargs is the string of arguments passed by the user with `--terse`
472 terseargs is the string of arguments passed by the user with `--terse`
472 flag.
473 flag.
473
474
474 Following are the cases which can happen:
475 Following are the cases which can happen:
475
476
476 1) All the files in the directory (including all the files in its
477 1) All the files in the directory (including all the files in its
477 subdirectories) share the same status and the user has asked us to terse
478 subdirectories) share the same status and the user has asked us to terse
478 that status. -> yield (status, dirpath)
479 that status. -> yield (status, dirpath)
479
480
480 2) Otherwise, we do following:
481 2) Otherwise, we do following:
481
482
482 a) Yield (status, filepath) for all the files which are in this
483 a) Yield (status, filepath) for all the files which are in this
483 directory (only the ones in this directory, not the subdirs)
484 directory (only the ones in this directory, not the subdirs)
484
485
485 b) Recurse the function on all the subdirectories of this
486 b) Recurse the function on all the subdirectories of this
486 directory
487 directory
487 """
488 """
488
489
489 if len(self.statuses) == 1:
490 if len(self.statuses) == 1:
490 onlyst = self.statuses.pop()
491 onlyst = self.statuses.pop()
491
492
492 # Making sure we terse only when the status abbreviation is
493 # Making sure we terse only when the status abbreviation is
493 # passed as terse argument
494 # passed as terse argument
494 if onlyst in terseargs:
495 if onlyst in terseargs:
495 yield onlyst, self.path + pycompat.ossep
496 yield onlyst, self.path + pycompat.ossep
496 return
497 return
497
498
498 # add the files to status list
499 # add the files to status list
499 for st, fpath in self.iterfilepaths():
500 for st, fpath in self.iterfilepaths():
500 yield st, fpath
501 yield st, fpath
501
502
502 #recurse on the subdirs
503 #recurse on the subdirs
503 for dirobj in self.subdirs.values():
504 for dirobj in self.subdirs.values():
504 for st, fpath in dirobj.tersewalk(terseargs):
505 for st, fpath in dirobj.tersewalk(terseargs):
505 yield st, fpath
506 yield st, fpath
506
507
507 def tersedir(statuslist, terseargs):
508 def tersedir(statuslist, terseargs):
508 """
509 """
509 Terse the status if all the files in a directory shares the same status.
510 Terse the status if all the files in a directory shares the same status.
510
511
511 statuslist is scmutil.status() object which contains a list of files for
512 statuslist is scmutil.status() object which contains a list of files for
512 each status.
513 each status.
513 terseargs is string which is passed by the user as the argument to `--terse`
514 terseargs is string which is passed by the user as the argument to `--terse`
514 flag.
515 flag.
515
516
516 The function makes a tree of objects of dirnode class, and at each node it
517 The function makes a tree of objects of dirnode class, and at each node it
517 stores the information required to know whether we can terse a certain
518 stores the information required to know whether we can terse a certain
518 directory or not.
519 directory or not.
519 """
520 """
520 # the order matters here as that is used to produce final list
521 # the order matters here as that is used to produce final list
521 allst = ('m', 'a', 'r', 'd', 'u', 'i', 'c')
522 allst = ('m', 'a', 'r', 'd', 'u', 'i', 'c')
522
523
523 # checking the argument validity
524 # checking the argument validity
524 for s in pycompat.bytestr(terseargs):
525 for s in pycompat.bytestr(terseargs):
525 if s not in allst:
526 if s not in allst:
526 raise error.Abort(_("'%s' not recognized") % s)
527 raise error.Abort(_("'%s' not recognized") % s)
527
528
528 # creating a dirnode object for the root of the repo
529 # creating a dirnode object for the root of the repo
529 rootobj = dirnode('')
530 rootobj = dirnode('')
530 pstatus = ('modified', 'added', 'deleted', 'clean', 'unknown',
531 pstatus = ('modified', 'added', 'deleted', 'clean', 'unknown',
531 'ignored', 'removed')
532 'ignored', 'removed')
532
533
533 tersedict = {}
534 tersedict = {}
534 for attrname in pstatus:
535 for attrname in pstatus:
535 statuschar = attrname[0:1]
536 statuschar = attrname[0:1]
536 for f in getattr(statuslist, attrname):
537 for f in getattr(statuslist, attrname):
537 rootobj.addfile(f, statuschar)
538 rootobj.addfile(f, statuschar)
538 tersedict[statuschar] = []
539 tersedict[statuschar] = []
539
540
540 # we won't be tersing the root dir, so add files in it
541 # we won't be tersing the root dir, so add files in it
541 for st, fpath in rootobj.iterfilepaths():
542 for st, fpath in rootobj.iterfilepaths():
542 tersedict[st].append(fpath)
543 tersedict[st].append(fpath)
543
544
544 # process each sub-directory and build tersedict
545 # process each sub-directory and build tersedict
545 for subdir in rootobj.subdirs.values():
546 for subdir in rootobj.subdirs.values():
546 for st, f in subdir.tersewalk(terseargs):
547 for st, f in subdir.tersewalk(terseargs):
547 tersedict[st].append(f)
548 tersedict[st].append(f)
548
549
549 tersedlist = []
550 tersedlist = []
550 for st in allst:
551 for st in allst:
551 tersedict[st].sort()
552 tersedict[st].sort()
552 tersedlist.append(tersedict[st])
553 tersedlist.append(tersedict[st])
553
554
554 return tersedlist
555 return tersedlist
555
556
556 def _commentlines(raw):
557 def _commentlines(raw):
557 '''Surround lineswith a comment char and a new line'''
558 '''Surround lineswith a comment char and a new line'''
558 lines = raw.splitlines()
559 lines = raw.splitlines()
559 commentedlines = ['# %s' % line for line in lines]
560 commentedlines = ['# %s' % line for line in lines]
560 return '\n'.join(commentedlines) + '\n'
561 return '\n'.join(commentedlines) + '\n'
561
562
562 def _conflictsmsg(repo):
563 def _conflictsmsg(repo):
563 # avoid merge cycle
564 # avoid merge cycle
564 from . import merge as mergemod
565 from . import merge as mergemod
565 mergestate = mergemod.mergestate.read(repo)
566 mergestate = mergemod.mergestate.read(repo)
566 if not mergestate.active():
567 if not mergestate.active():
567 return
568 return
568
569
569 m = scmutil.match(repo[None])
570 m = scmutil.match(repo[None])
570 unresolvedlist = [f for f in mergestate.unresolved() if m(f)]
571 unresolvedlist = [f for f in mergestate.unresolved() if m(f)]
571 if unresolvedlist:
572 if unresolvedlist:
572 mergeliststr = '\n'.join(
573 mergeliststr = '\n'.join(
573 [' %s' % util.pathto(repo.root, pycompat.getcwd(), path)
574 [' %s' % util.pathto(repo.root, pycompat.getcwd(), path)
574 for path in unresolvedlist])
575 for path in unresolvedlist])
575 msg = _('''Unresolved merge conflicts:
576 msg = _('''Unresolved merge conflicts:
576
577
577 %s
578 %s
578
579
579 To mark files as resolved: hg resolve --mark FILE''') % mergeliststr
580 To mark files as resolved: hg resolve --mark FILE''') % mergeliststr
580 else:
581 else:
581 msg = _('No unresolved merge conflicts.')
582 msg = _('No unresolved merge conflicts.')
582
583
583 return _commentlines(msg)
584 return _commentlines(msg)
584
585
585 def _helpmessage(continuecmd, abortcmd):
586 def _helpmessage(continuecmd, abortcmd):
586 msg = _('To continue: %s\n'
587 msg = _('To continue: %s\n'
587 'To abort: %s') % (continuecmd, abortcmd)
588 'To abort: %s') % (continuecmd, abortcmd)
588 return _commentlines(msg)
589 return _commentlines(msg)
589
590
590 def _rebasemsg():
591 def _rebasemsg():
591 return _helpmessage('hg rebase --continue', 'hg rebase --abort')
592 return _helpmessage('hg rebase --continue', 'hg rebase --abort')
592
593
593 def _histeditmsg():
594 def _histeditmsg():
594 return _helpmessage('hg histedit --continue', 'hg histedit --abort')
595 return _helpmessage('hg histedit --continue', 'hg histedit --abort')
595
596
596 def _unshelvemsg():
597 def _unshelvemsg():
597 return _helpmessage('hg unshelve --continue', 'hg unshelve --abort')
598 return _helpmessage('hg unshelve --continue', 'hg unshelve --abort')
598
599
599 def _updatecleanmsg(dest=None):
600 def _updatecleanmsg(dest=None):
600 warning = _('warning: this will discard uncommitted changes')
601 warning = _('warning: this will discard uncommitted changes')
601 return 'hg update --clean %s (%s)' % (dest or '.', warning)
602 return 'hg update --clean %s (%s)' % (dest or '.', warning)
602
603
603 def _graftmsg():
604 def _graftmsg():
604 # tweakdefaults requires `update` to have a rev hence the `.`
605 # tweakdefaults requires `update` to have a rev hence the `.`
605 return _helpmessage('hg graft --continue', _updatecleanmsg())
606 return _helpmessage('hg graft --continue', _updatecleanmsg())
606
607
607 def _mergemsg():
608 def _mergemsg():
608 # tweakdefaults requires `update` to have a rev hence the `.`
609 # tweakdefaults requires `update` to have a rev hence the `.`
609 return _helpmessage('hg commit', _updatecleanmsg())
610 return _helpmessage('hg commit', _updatecleanmsg())
610
611
611 def _bisectmsg():
612 def _bisectmsg():
612 msg = _('To mark the changeset good: hg bisect --good\n'
613 msg = _('To mark the changeset good: hg bisect --good\n'
613 'To mark the changeset bad: hg bisect --bad\n'
614 'To mark the changeset bad: hg bisect --bad\n'
614 'To abort: hg bisect --reset\n')
615 'To abort: hg bisect --reset\n')
615 return _commentlines(msg)
616 return _commentlines(msg)
616
617
617 def fileexistspredicate(filename):
618 def fileexistspredicate(filename):
618 return lambda repo: repo.vfs.exists(filename)
619 return lambda repo: repo.vfs.exists(filename)
619
620
620 def _mergepredicate(repo):
621 def _mergepredicate(repo):
621 return len(repo[None].parents()) > 1
622 return len(repo[None].parents()) > 1
622
623
623 STATES = (
624 STATES = (
624 # (state, predicate to detect states, helpful message function)
625 # (state, predicate to detect states, helpful message function)
625 ('histedit', fileexistspredicate('histedit-state'), _histeditmsg),
626 ('histedit', fileexistspredicate('histedit-state'), _histeditmsg),
626 ('bisect', fileexistspredicate('bisect.state'), _bisectmsg),
627 ('bisect', fileexistspredicate('bisect.state'), _bisectmsg),
627 ('graft', fileexistspredicate('graftstate'), _graftmsg),
628 ('graft', fileexistspredicate('graftstate'), _graftmsg),
628 ('unshelve', fileexistspredicate('unshelverebasestate'), _unshelvemsg),
629 ('unshelve', fileexistspredicate('unshelverebasestate'), _unshelvemsg),
629 ('rebase', fileexistspredicate('rebasestate'), _rebasemsg),
630 ('rebase', fileexistspredicate('rebasestate'), _rebasemsg),
630 # The merge state is part of a list that will be iterated over.
631 # The merge state is part of a list that will be iterated over.
631 # They need to be last because some of the other unfinished states may also
632 # They need to be last because some of the other unfinished states may also
632 # be in a merge or update state (eg. rebase, histedit, graft, etc).
633 # be in a merge or update state (eg. rebase, histedit, graft, etc).
633 # We want those to have priority.
634 # We want those to have priority.
634 ('merge', _mergepredicate, _mergemsg),
635 ('merge', _mergepredicate, _mergemsg),
635 )
636 )
636
637
637 def _getrepostate(repo):
638 def _getrepostate(repo):
638 # experimental config: commands.status.skipstates
639 # experimental config: commands.status.skipstates
639 skip = set(repo.ui.configlist('commands', 'status.skipstates'))
640 skip = set(repo.ui.configlist('commands', 'status.skipstates'))
640 for state, statedetectionpredicate, msgfn in STATES:
641 for state, statedetectionpredicate, msgfn in STATES:
641 if state in skip:
642 if state in skip:
642 continue
643 continue
643 if statedetectionpredicate(repo):
644 if statedetectionpredicate(repo):
644 return (state, statedetectionpredicate, msgfn)
645 return (state, statedetectionpredicate, msgfn)
645
646
646 def morestatus(repo, fm):
647 def morestatus(repo, fm):
647 statetuple = _getrepostate(repo)
648 statetuple = _getrepostate(repo)
648 label = 'status.morestatus'
649 label = 'status.morestatus'
649 if statetuple:
650 if statetuple:
650 fm.startitem()
651 fm.startitem()
651 state, statedetectionpredicate, helpfulmsg = statetuple
652 state, statedetectionpredicate, helpfulmsg = statetuple
652 statemsg = _('The repository is in an unfinished *%s* state.') % state
653 statemsg = _('The repository is in an unfinished *%s* state.') % state
653 fm.write('statemsg', '%s\n', _commentlines(statemsg), label=label)
654 fm.write('statemsg', '%s\n', _commentlines(statemsg), label=label)
654 conmsg = _conflictsmsg(repo)
655 conmsg = _conflictsmsg(repo)
655 if conmsg:
656 if conmsg:
656 fm.write('conflictsmsg', '%s\n', conmsg, label=label)
657 fm.write('conflictsmsg', '%s\n', conmsg, label=label)
657 if helpfulmsg:
658 if helpfulmsg:
658 helpmsg = helpfulmsg()
659 helpmsg = helpfulmsg()
659 fm.write('helpmsg', '%s\n', helpmsg, label=label)
660 fm.write('helpmsg', '%s\n', helpmsg, label=label)
660
661
661 def findpossible(cmd, table, strict=False):
662 def findpossible(cmd, table, strict=False):
662 """
663 """
663 Return cmd -> (aliases, command table entry)
664 Return cmd -> (aliases, command table entry)
664 for each matching command.
665 for each matching command.
665 Return debug commands (or their aliases) only if no normal command matches.
666 Return debug commands (or their aliases) only if no normal command matches.
666 """
667 """
667 choice = {}
668 choice = {}
668 debugchoice = {}
669 debugchoice = {}
669
670
670 if cmd in table:
671 if cmd in table:
671 # short-circuit exact matches, "log" alias beats "^log|history"
672 # short-circuit exact matches, "log" alias beats "^log|history"
672 keys = [cmd]
673 keys = [cmd]
673 else:
674 else:
674 keys = table.keys()
675 keys = table.keys()
675
676
676 allcmds = []
677 allcmds = []
677 for e in keys:
678 for e in keys:
678 aliases = parsealiases(e)
679 aliases = parsealiases(e)
679 allcmds.extend(aliases)
680 allcmds.extend(aliases)
680 found = None
681 found = None
681 if cmd in aliases:
682 if cmd in aliases:
682 found = cmd
683 found = cmd
683 elif not strict:
684 elif not strict:
684 for a in aliases:
685 for a in aliases:
685 if a.startswith(cmd):
686 if a.startswith(cmd):
686 found = a
687 found = a
687 break
688 break
688 if found is not None:
689 if found is not None:
689 if aliases[0].startswith("debug") or found.startswith("debug"):
690 if aliases[0].startswith("debug") or found.startswith("debug"):
690 debugchoice[found] = (aliases, table[e])
691 debugchoice[found] = (aliases, table[e])
691 else:
692 else:
692 choice[found] = (aliases, table[e])
693 choice[found] = (aliases, table[e])
693
694
694 if not choice and debugchoice:
695 if not choice and debugchoice:
695 choice = debugchoice
696 choice = debugchoice
696
697
697 return choice, allcmds
698 return choice, allcmds
698
699
699 def findcmd(cmd, table, strict=True):
700 def findcmd(cmd, table, strict=True):
700 """Return (aliases, command table entry) for command string."""
701 """Return (aliases, command table entry) for command string."""
701 choice, allcmds = findpossible(cmd, table, strict)
702 choice, allcmds = findpossible(cmd, table, strict)
702
703
703 if cmd in choice:
704 if cmd in choice:
704 return choice[cmd]
705 return choice[cmd]
705
706
706 if len(choice) > 1:
707 if len(choice) > 1:
707 clist = sorted(choice)
708 clist = sorted(choice)
708 raise error.AmbiguousCommand(cmd, clist)
709 raise error.AmbiguousCommand(cmd, clist)
709
710
710 if choice:
711 if choice:
711 return list(choice.values())[0]
712 return list(choice.values())[0]
712
713
713 raise error.UnknownCommand(cmd, allcmds)
714 raise error.UnknownCommand(cmd, allcmds)
714
715
715 def findrepo(p):
716 def findrepo(p):
716 while not os.path.isdir(os.path.join(p, ".hg")):
717 while not os.path.isdir(os.path.join(p, ".hg")):
717 oldp, p = p, os.path.dirname(p)
718 oldp, p = p, os.path.dirname(p)
718 if p == oldp:
719 if p == oldp:
719 return None
720 return None
720
721
721 return p
722 return p
722
723
723 def bailifchanged(repo, merge=True, hint=None):
724 def bailifchanged(repo, merge=True, hint=None):
724 """ enforce the precondition that working directory must be clean.
725 """ enforce the precondition that working directory must be clean.
725
726
726 'merge' can be set to false if a pending uncommitted merge should be
727 'merge' can be set to false if a pending uncommitted merge should be
727 ignored (such as when 'update --check' runs).
728 ignored (such as when 'update --check' runs).
728
729
729 'hint' is the usual hint given to Abort exception.
730 'hint' is the usual hint given to Abort exception.
730 """
731 """
731
732
732 if merge and repo.dirstate.p2() != nullid:
733 if merge and repo.dirstate.p2() != nullid:
733 raise error.Abort(_('outstanding uncommitted merge'), hint=hint)
734 raise error.Abort(_('outstanding uncommitted merge'), hint=hint)
734 modified, added, removed, deleted = repo.status()[:4]
735 modified, added, removed, deleted = repo.status()[:4]
735 if modified or added or removed or deleted:
736 if modified or added or removed or deleted:
736 raise error.Abort(_('uncommitted changes'), hint=hint)
737 raise error.Abort(_('uncommitted changes'), hint=hint)
737 ctx = repo[None]
738 ctx = repo[None]
738 for s in sorted(ctx.substate):
739 for s in sorted(ctx.substate):
739 ctx.sub(s).bailifchanged(hint=hint)
740 ctx.sub(s).bailifchanged(hint=hint)
740
741
741 def logmessage(ui, opts):
742 def logmessage(ui, opts):
742 """ get the log message according to -m and -l option """
743 """ get the log message according to -m and -l option """
743 message = opts.get('message')
744 message = opts.get('message')
744 logfile = opts.get('logfile')
745 logfile = opts.get('logfile')
745
746
746 if message and logfile:
747 if message and logfile:
747 raise error.Abort(_('options --message and --logfile are mutually '
748 raise error.Abort(_('options --message and --logfile are mutually '
748 'exclusive'))
749 'exclusive'))
749 if not message and logfile:
750 if not message and logfile:
750 try:
751 try:
751 if isstdiofilename(logfile):
752 if isstdiofilename(logfile):
752 message = ui.fin.read()
753 message = ui.fin.read()
753 else:
754 else:
754 message = '\n'.join(util.readfile(logfile).splitlines())
755 message = '\n'.join(util.readfile(logfile).splitlines())
755 except IOError as inst:
756 except IOError as inst:
756 raise error.Abort(_("can't read commit message '%s': %s") %
757 raise error.Abort(_("can't read commit message '%s': %s") %
757 (logfile, encoding.strtolocal(inst.strerror)))
758 (logfile, encoding.strtolocal(inst.strerror)))
758 return message
759 return message
759
760
760 def mergeeditform(ctxorbool, baseformname):
761 def mergeeditform(ctxorbool, baseformname):
761 """return appropriate editform name (referencing a committemplate)
762 """return appropriate editform name (referencing a committemplate)
762
763
763 'ctxorbool' is either a ctx to be committed, or a bool indicating whether
764 'ctxorbool' is either a ctx to be committed, or a bool indicating whether
764 merging is committed.
765 merging is committed.
765
766
766 This returns baseformname with '.merge' appended if it is a merge,
767 This returns baseformname with '.merge' appended if it is a merge,
767 otherwise '.normal' is appended.
768 otherwise '.normal' is appended.
768 """
769 """
769 if isinstance(ctxorbool, bool):
770 if isinstance(ctxorbool, bool):
770 if ctxorbool:
771 if ctxorbool:
771 return baseformname + ".merge"
772 return baseformname + ".merge"
772 elif 1 < len(ctxorbool.parents()):
773 elif 1 < len(ctxorbool.parents()):
773 return baseformname + ".merge"
774 return baseformname + ".merge"
774
775
775 return baseformname + ".normal"
776 return baseformname + ".normal"
776
777
777 def getcommiteditor(edit=False, finishdesc=None, extramsg=None,
778 def getcommiteditor(edit=False, finishdesc=None, extramsg=None,
778 editform='', **opts):
779 editform='', **opts):
779 """get appropriate commit message editor according to '--edit' option
780 """get appropriate commit message editor according to '--edit' option
780
781
781 'finishdesc' is a function to be called with edited commit message
782 'finishdesc' is a function to be called with edited commit message
782 (= 'description' of the new changeset) just after editing, but
783 (= 'description' of the new changeset) just after editing, but
783 before checking empty-ness. It should return actual text to be
784 before checking empty-ness. It should return actual text to be
784 stored into history. This allows to change description before
785 stored into history. This allows to change description before
785 storing.
786 storing.
786
787
787 'extramsg' is a extra message to be shown in the editor instead of
788 'extramsg' is a extra message to be shown in the editor instead of
788 'Leave message empty to abort commit' line. 'HG: ' prefix and EOL
789 'Leave message empty to abort commit' line. 'HG: ' prefix and EOL
789 is automatically added.
790 is automatically added.
790
791
791 'editform' is a dot-separated list of names, to distinguish
792 'editform' is a dot-separated list of names, to distinguish
792 the purpose of commit text editing.
793 the purpose of commit text editing.
793
794
794 'getcommiteditor' returns 'commitforceeditor' regardless of
795 'getcommiteditor' returns 'commitforceeditor' regardless of
795 'edit', if one of 'finishdesc' or 'extramsg' is specified, because
796 'edit', if one of 'finishdesc' or 'extramsg' is specified, because
796 they are specific for usage in MQ.
797 they are specific for usage in MQ.
797 """
798 """
798 if edit or finishdesc or extramsg:
799 if edit or finishdesc or extramsg:
799 return lambda r, c, s: commitforceeditor(r, c, s,
800 return lambda r, c, s: commitforceeditor(r, c, s,
800 finishdesc=finishdesc,
801 finishdesc=finishdesc,
801 extramsg=extramsg,
802 extramsg=extramsg,
802 editform=editform)
803 editform=editform)
803 elif editform:
804 elif editform:
804 return lambda r, c, s: commiteditor(r, c, s, editform=editform)
805 return lambda r, c, s: commiteditor(r, c, s, editform=editform)
805 else:
806 else:
806 return commiteditor
807 return commiteditor
807
808
808 def loglimit(opts):
809 def loglimit(opts):
809 """get the log limit according to option -l/--limit"""
810 """get the log limit according to option -l/--limit"""
810 limit = opts.get('limit')
811 limit = opts.get('limit')
811 if limit:
812 if limit:
812 try:
813 try:
813 limit = int(limit)
814 limit = int(limit)
814 except ValueError:
815 except ValueError:
815 raise error.Abort(_('limit must be a positive integer'))
816 raise error.Abort(_('limit must be a positive integer'))
816 if limit <= 0:
817 if limit <= 0:
817 raise error.Abort(_('limit must be positive'))
818 raise error.Abort(_('limit must be positive'))
818 else:
819 else:
819 limit = None
820 limit = None
820 return limit
821 return limit
821
822
822 def makefilename(repo, pat, node, desc=None,
823 def makefilename(repo, pat, node, desc=None,
823 total=None, seqno=None, revwidth=None, pathname=None):
824 total=None, seqno=None, revwidth=None, pathname=None):
824 node_expander = {
825 node_expander = {
825 'H': lambda: hex(node),
826 'H': lambda: hex(node),
826 'R': lambda: '%d' % repo.changelog.rev(node),
827 'R': lambda: '%d' % repo.changelog.rev(node),
827 'h': lambda: short(node),
828 'h': lambda: short(node),
828 'm': lambda: re.sub('[^\w]', '_', desc or '')
829 'm': lambda: re.sub('[^\w]', '_', desc or '')
829 }
830 }
830 expander = {
831 expander = {
831 '%': lambda: '%',
832 '%': lambda: '%',
832 'b': lambda: os.path.basename(repo.root),
833 'b': lambda: os.path.basename(repo.root),
833 }
834 }
834
835
835 try:
836 try:
836 if node:
837 if node:
837 expander.update(node_expander)
838 expander.update(node_expander)
838 if node:
839 if node:
839 expander['r'] = (lambda:
840 expander['r'] = (lambda:
840 ('%d' % repo.changelog.rev(node)).zfill(revwidth or 0))
841 ('%d' % repo.changelog.rev(node)).zfill(revwidth or 0))
841 if total is not None:
842 if total is not None:
842 expander['N'] = lambda: '%d' % total
843 expander['N'] = lambda: '%d' % total
843 if seqno is not None:
844 if seqno is not None:
844 expander['n'] = lambda: '%d' % seqno
845 expander['n'] = lambda: '%d' % seqno
845 if total is not None and seqno is not None:
846 if total is not None and seqno is not None:
846 expander['n'] = (lambda: ('%d' % seqno).zfill(len('%d' % total)))
847 expander['n'] = (lambda: ('%d' % seqno).zfill(len('%d' % total)))
847 if pathname is not None:
848 if pathname is not None:
848 expander['s'] = lambda: os.path.basename(pathname)
849 expander['s'] = lambda: os.path.basename(pathname)
849 expander['d'] = lambda: os.path.dirname(pathname) or '.'
850 expander['d'] = lambda: os.path.dirname(pathname) or '.'
850 expander['p'] = lambda: pathname
851 expander['p'] = lambda: pathname
851
852
852 newname = []
853 newname = []
853 patlen = len(pat)
854 patlen = len(pat)
854 i = 0
855 i = 0
855 while i < patlen:
856 while i < patlen:
856 c = pat[i:i + 1]
857 c = pat[i:i + 1]
857 if c == '%':
858 if c == '%':
858 i += 1
859 i += 1
859 c = pat[i:i + 1]
860 c = pat[i:i + 1]
860 c = expander[c]()
861 c = expander[c]()
861 newname.append(c)
862 newname.append(c)
862 i += 1
863 i += 1
863 return ''.join(newname)
864 return ''.join(newname)
864 except KeyError as inst:
865 except KeyError as inst:
865 raise error.Abort(_("invalid format spec '%%%s' in output filename") %
866 raise error.Abort(_("invalid format spec '%%%s' in output filename") %
866 inst.args[0])
867 inst.args[0])
867
868
868 def isstdiofilename(pat):
869 def isstdiofilename(pat):
869 """True if the given pat looks like a filename denoting stdin/stdout"""
870 """True if the given pat looks like a filename denoting stdin/stdout"""
870 return not pat or pat == '-'
871 return not pat or pat == '-'
871
872
872 class _unclosablefile(object):
873 class _unclosablefile(object):
873 def __init__(self, fp):
874 def __init__(self, fp):
874 self._fp = fp
875 self._fp = fp
875
876
876 def close(self):
877 def close(self):
877 pass
878 pass
878
879
879 def __iter__(self):
880 def __iter__(self):
880 return iter(self._fp)
881 return iter(self._fp)
881
882
882 def __getattr__(self, attr):
883 def __getattr__(self, attr):
883 return getattr(self._fp, attr)
884 return getattr(self._fp, attr)
884
885
885 def __enter__(self):
886 def __enter__(self):
886 return self
887 return self
887
888
888 def __exit__(self, exc_type, exc_value, exc_tb):
889 def __exit__(self, exc_type, exc_value, exc_tb):
889 pass
890 pass
890
891
891 def makefileobj(repo, pat, node=None, desc=None, total=None,
892 def makefileobj(repo, pat, node=None, desc=None, total=None,
892 seqno=None, revwidth=None, mode='wb', modemap=None,
893 seqno=None, revwidth=None, mode='wb', modemap=None,
893 pathname=None):
894 pathname=None):
894
895
895 writable = mode not in ('r', 'rb')
896 writable = mode not in ('r', 'rb')
896
897
897 if isstdiofilename(pat):
898 if isstdiofilename(pat):
898 if writable:
899 if writable:
899 fp = repo.ui.fout
900 fp = repo.ui.fout
900 else:
901 else:
901 fp = repo.ui.fin
902 fp = repo.ui.fin
902 return _unclosablefile(fp)
903 return _unclosablefile(fp)
903 fn = makefilename(repo, pat, node, desc, total, seqno, revwidth, pathname)
904 fn = makefilename(repo, pat, node, desc, total, seqno, revwidth, pathname)
904 if modemap is not None:
905 if modemap is not None:
905 mode = modemap.get(fn, mode)
906 mode = modemap.get(fn, mode)
906 if mode == 'wb':
907 if mode == 'wb':
907 modemap[fn] = 'ab'
908 modemap[fn] = 'ab'
908 return open(fn, mode)
909 return open(fn, mode)
909
910
910 def openrevlog(repo, cmd, file_, opts):
911 def openrevlog(repo, cmd, file_, opts):
911 """opens the changelog, manifest, a filelog or a given revlog"""
912 """opens the changelog, manifest, a filelog or a given revlog"""
912 cl = opts['changelog']
913 cl = opts['changelog']
913 mf = opts['manifest']
914 mf = opts['manifest']
914 dir = opts['dir']
915 dir = opts['dir']
915 msg = None
916 msg = None
916 if cl and mf:
917 if cl and mf:
917 msg = _('cannot specify --changelog and --manifest at the same time')
918 msg = _('cannot specify --changelog and --manifest at the same time')
918 elif cl and dir:
919 elif cl and dir:
919 msg = _('cannot specify --changelog and --dir at the same time')
920 msg = _('cannot specify --changelog and --dir at the same time')
920 elif cl or mf or dir:
921 elif cl or mf or dir:
921 if file_:
922 if file_:
922 msg = _('cannot specify filename with --changelog or --manifest')
923 msg = _('cannot specify filename with --changelog or --manifest')
923 elif not repo:
924 elif not repo:
924 msg = _('cannot specify --changelog or --manifest or --dir '
925 msg = _('cannot specify --changelog or --manifest or --dir '
925 'without a repository')
926 'without a repository')
926 if msg:
927 if msg:
927 raise error.Abort(msg)
928 raise error.Abort(msg)
928
929
929 r = None
930 r = None
930 if repo:
931 if repo:
931 if cl:
932 if cl:
932 r = repo.unfiltered().changelog
933 r = repo.unfiltered().changelog
933 elif dir:
934 elif dir:
934 if 'treemanifest' not in repo.requirements:
935 if 'treemanifest' not in repo.requirements:
935 raise error.Abort(_("--dir can only be used on repos with "
936 raise error.Abort(_("--dir can only be used on repos with "
936 "treemanifest enabled"))
937 "treemanifest enabled"))
937 dirlog = repo.manifestlog._revlog.dirlog(dir)
938 dirlog = repo.manifestlog._revlog.dirlog(dir)
938 if len(dirlog):
939 if len(dirlog):
939 r = dirlog
940 r = dirlog
940 elif mf:
941 elif mf:
941 r = repo.manifestlog._revlog
942 r = repo.manifestlog._revlog
942 elif file_:
943 elif file_:
943 filelog = repo.file(file_)
944 filelog = repo.file(file_)
944 if len(filelog):
945 if len(filelog):
945 r = filelog
946 r = filelog
946 if not r:
947 if not r:
947 if not file_:
948 if not file_:
948 raise error.CommandError(cmd, _('invalid arguments'))
949 raise error.CommandError(cmd, _('invalid arguments'))
949 if not os.path.isfile(file_):
950 if not os.path.isfile(file_):
950 raise error.Abort(_("revlog '%s' not found") % file_)
951 raise error.Abort(_("revlog '%s' not found") % file_)
951 r = revlog.revlog(vfsmod.vfs(pycompat.getcwd(), audit=False),
952 r = revlog.revlog(vfsmod.vfs(pycompat.getcwd(), audit=False),
952 file_[:-2] + ".i")
953 file_[:-2] + ".i")
953 return r
954 return r
954
955
955 def copy(ui, repo, pats, opts, rename=False):
956 def copy(ui, repo, pats, opts, rename=False):
956 # called with the repo lock held
957 # called with the repo lock held
957 #
958 #
958 # hgsep => pathname that uses "/" to separate directories
959 # hgsep => pathname that uses "/" to separate directories
959 # ossep => pathname that uses os.sep to separate directories
960 # ossep => pathname that uses os.sep to separate directories
960 cwd = repo.getcwd()
961 cwd = repo.getcwd()
961 targets = {}
962 targets = {}
962 after = opts.get("after")
963 after = opts.get("after")
963 dryrun = opts.get("dry_run")
964 dryrun = opts.get("dry_run")
964 wctx = repo[None]
965 wctx = repo[None]
965
966
966 def walkpat(pat):
967 def walkpat(pat):
967 srcs = []
968 srcs = []
968 if after:
969 if after:
969 badstates = '?'
970 badstates = '?'
970 else:
971 else:
971 badstates = '?r'
972 badstates = '?r'
972 m = scmutil.match(wctx, [pat], opts, globbed=True)
973 m = scmutil.match(wctx, [pat], opts, globbed=True)
973 for abs in wctx.walk(m):
974 for abs in wctx.walk(m):
974 state = repo.dirstate[abs]
975 state = repo.dirstate[abs]
975 rel = m.rel(abs)
976 rel = m.rel(abs)
976 exact = m.exact(abs)
977 exact = m.exact(abs)
977 if state in badstates:
978 if state in badstates:
978 if exact and state == '?':
979 if exact and state == '?':
979 ui.warn(_('%s: not copying - file is not managed\n') % rel)
980 ui.warn(_('%s: not copying - file is not managed\n') % rel)
980 if exact and state == 'r':
981 if exact and state == 'r':
981 ui.warn(_('%s: not copying - file has been marked for'
982 ui.warn(_('%s: not copying - file has been marked for'
982 ' remove\n') % rel)
983 ' remove\n') % rel)
983 continue
984 continue
984 # abs: hgsep
985 # abs: hgsep
985 # rel: ossep
986 # rel: ossep
986 srcs.append((abs, rel, exact))
987 srcs.append((abs, rel, exact))
987 return srcs
988 return srcs
988
989
989 # abssrc: hgsep
990 # abssrc: hgsep
990 # relsrc: ossep
991 # relsrc: ossep
991 # otarget: ossep
992 # otarget: ossep
992 def copyfile(abssrc, relsrc, otarget, exact):
993 def copyfile(abssrc, relsrc, otarget, exact):
993 abstarget = pathutil.canonpath(repo.root, cwd, otarget)
994 abstarget = pathutil.canonpath(repo.root, cwd, otarget)
994 if '/' in abstarget:
995 if '/' in abstarget:
995 # We cannot normalize abstarget itself, this would prevent
996 # We cannot normalize abstarget itself, this would prevent
996 # case only renames, like a => A.
997 # case only renames, like a => A.
997 abspath, absname = abstarget.rsplit('/', 1)
998 abspath, absname = abstarget.rsplit('/', 1)
998 abstarget = repo.dirstate.normalize(abspath) + '/' + absname
999 abstarget = repo.dirstate.normalize(abspath) + '/' + absname
999 reltarget = repo.pathto(abstarget, cwd)
1000 reltarget = repo.pathto(abstarget, cwd)
1000 target = repo.wjoin(abstarget)
1001 target = repo.wjoin(abstarget)
1001 src = repo.wjoin(abssrc)
1002 src = repo.wjoin(abssrc)
1002 state = repo.dirstate[abstarget]
1003 state = repo.dirstate[abstarget]
1003
1004
1004 scmutil.checkportable(ui, abstarget)
1005 scmutil.checkportable(ui, abstarget)
1005
1006
1006 # check for collisions
1007 # check for collisions
1007 prevsrc = targets.get(abstarget)
1008 prevsrc = targets.get(abstarget)
1008 if prevsrc is not None:
1009 if prevsrc is not None:
1009 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
1010 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
1010 (reltarget, repo.pathto(abssrc, cwd),
1011 (reltarget, repo.pathto(abssrc, cwd),
1011 repo.pathto(prevsrc, cwd)))
1012 repo.pathto(prevsrc, cwd)))
1012 return
1013 return
1013
1014
1014 # check for overwrites
1015 # check for overwrites
1015 exists = os.path.lexists(target)
1016 exists = os.path.lexists(target)
1016 samefile = False
1017 samefile = False
1017 if exists and abssrc != abstarget:
1018 if exists and abssrc != abstarget:
1018 if (repo.dirstate.normalize(abssrc) ==
1019 if (repo.dirstate.normalize(abssrc) ==
1019 repo.dirstate.normalize(abstarget)):
1020 repo.dirstate.normalize(abstarget)):
1020 if not rename:
1021 if not rename:
1021 ui.warn(_("%s: can't copy - same file\n") % reltarget)
1022 ui.warn(_("%s: can't copy - same file\n") % reltarget)
1022 return
1023 return
1023 exists = False
1024 exists = False
1024 samefile = True
1025 samefile = True
1025
1026
1026 if not after and exists or after and state in 'mn':
1027 if not after and exists or after and state in 'mn':
1027 if not opts['force']:
1028 if not opts['force']:
1028 if state in 'mn':
1029 if state in 'mn':
1029 msg = _('%s: not overwriting - file already committed\n')
1030 msg = _('%s: not overwriting - file already committed\n')
1030 if after:
1031 if after:
1031 flags = '--after --force'
1032 flags = '--after --force'
1032 else:
1033 else:
1033 flags = '--force'
1034 flags = '--force'
1034 if rename:
1035 if rename:
1035 hint = _('(hg rename %s to replace the file by '
1036 hint = _('(hg rename %s to replace the file by '
1036 'recording a rename)\n') % flags
1037 'recording a rename)\n') % flags
1037 else:
1038 else:
1038 hint = _('(hg copy %s to replace the file by '
1039 hint = _('(hg copy %s to replace the file by '
1039 'recording a copy)\n') % flags
1040 'recording a copy)\n') % flags
1040 else:
1041 else:
1041 msg = _('%s: not overwriting - file exists\n')
1042 msg = _('%s: not overwriting - file exists\n')
1042 if rename:
1043 if rename:
1043 hint = _('(hg rename --after to record the rename)\n')
1044 hint = _('(hg rename --after to record the rename)\n')
1044 else:
1045 else:
1045 hint = _('(hg copy --after to record the copy)\n')
1046 hint = _('(hg copy --after to record the copy)\n')
1046 ui.warn(msg % reltarget)
1047 ui.warn(msg % reltarget)
1047 ui.warn(hint)
1048 ui.warn(hint)
1048 return
1049 return
1049
1050
1050 if after:
1051 if after:
1051 if not exists:
1052 if not exists:
1052 if rename:
1053 if rename:
1053 ui.warn(_('%s: not recording move - %s does not exist\n') %
1054 ui.warn(_('%s: not recording move - %s does not exist\n') %
1054 (relsrc, reltarget))
1055 (relsrc, reltarget))
1055 else:
1056 else:
1056 ui.warn(_('%s: not recording copy - %s does not exist\n') %
1057 ui.warn(_('%s: not recording copy - %s does not exist\n') %
1057 (relsrc, reltarget))
1058 (relsrc, reltarget))
1058 return
1059 return
1059 elif not dryrun:
1060 elif not dryrun:
1060 try:
1061 try:
1061 if exists:
1062 if exists:
1062 os.unlink(target)
1063 os.unlink(target)
1063 targetdir = os.path.dirname(target) or '.'
1064 targetdir = os.path.dirname(target) or '.'
1064 if not os.path.isdir(targetdir):
1065 if not os.path.isdir(targetdir):
1065 os.makedirs(targetdir)
1066 os.makedirs(targetdir)
1066 if samefile:
1067 if samefile:
1067 tmp = target + "~hgrename"
1068 tmp = target + "~hgrename"
1068 os.rename(src, tmp)
1069 os.rename(src, tmp)
1069 os.rename(tmp, target)
1070 os.rename(tmp, target)
1070 else:
1071 else:
1071 util.copyfile(src, target)
1072 util.copyfile(src, target)
1072 srcexists = True
1073 srcexists = True
1073 except IOError as inst:
1074 except IOError as inst:
1074 if inst.errno == errno.ENOENT:
1075 if inst.errno == errno.ENOENT:
1075 ui.warn(_('%s: deleted in working directory\n') % relsrc)
1076 ui.warn(_('%s: deleted in working directory\n') % relsrc)
1076 srcexists = False
1077 srcexists = False
1077 else:
1078 else:
1078 ui.warn(_('%s: cannot copy - %s\n') %
1079 ui.warn(_('%s: cannot copy - %s\n') %
1079 (relsrc, encoding.strtolocal(inst.strerror)))
1080 (relsrc, encoding.strtolocal(inst.strerror)))
1080 return True # report a failure
1081 return True # report a failure
1081
1082
1082 if ui.verbose or not exact:
1083 if ui.verbose or not exact:
1083 if rename:
1084 if rename:
1084 ui.status(_('moving %s to %s\n') % (relsrc, reltarget))
1085 ui.status(_('moving %s to %s\n') % (relsrc, reltarget))
1085 else:
1086 else:
1086 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
1087 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
1087
1088
1088 targets[abstarget] = abssrc
1089 targets[abstarget] = abssrc
1089
1090
1090 # fix up dirstate
1091 # fix up dirstate
1091 scmutil.dirstatecopy(ui, repo, wctx, abssrc, abstarget,
1092 scmutil.dirstatecopy(ui, repo, wctx, abssrc, abstarget,
1092 dryrun=dryrun, cwd=cwd)
1093 dryrun=dryrun, cwd=cwd)
1093 if rename and not dryrun:
1094 if rename and not dryrun:
1094 if not after and srcexists and not samefile:
1095 if not after and srcexists and not samefile:
1095 repo.wvfs.unlinkpath(abssrc)
1096 repo.wvfs.unlinkpath(abssrc)
1096 wctx.forget([abssrc])
1097 wctx.forget([abssrc])
1097
1098
1098 # pat: ossep
1099 # pat: ossep
1099 # dest ossep
1100 # dest ossep
1100 # srcs: list of (hgsep, hgsep, ossep, bool)
1101 # srcs: list of (hgsep, hgsep, ossep, bool)
1101 # return: function that takes hgsep and returns ossep
1102 # return: function that takes hgsep and returns ossep
1102 def targetpathfn(pat, dest, srcs):
1103 def targetpathfn(pat, dest, srcs):
1103 if os.path.isdir(pat):
1104 if os.path.isdir(pat):
1104 abspfx = pathutil.canonpath(repo.root, cwd, pat)
1105 abspfx = pathutil.canonpath(repo.root, cwd, pat)
1105 abspfx = util.localpath(abspfx)
1106 abspfx = util.localpath(abspfx)
1106 if destdirexists:
1107 if destdirexists:
1107 striplen = len(os.path.split(abspfx)[0])
1108 striplen = len(os.path.split(abspfx)[0])
1108 else:
1109 else:
1109 striplen = len(abspfx)
1110 striplen = len(abspfx)
1110 if striplen:
1111 if striplen:
1111 striplen += len(pycompat.ossep)
1112 striplen += len(pycompat.ossep)
1112 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
1113 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
1113 elif destdirexists:
1114 elif destdirexists:
1114 res = lambda p: os.path.join(dest,
1115 res = lambda p: os.path.join(dest,
1115 os.path.basename(util.localpath(p)))
1116 os.path.basename(util.localpath(p)))
1116 else:
1117 else:
1117 res = lambda p: dest
1118 res = lambda p: dest
1118 return res
1119 return res
1119
1120
1120 # pat: ossep
1121 # pat: ossep
1121 # dest ossep
1122 # dest ossep
1122 # srcs: list of (hgsep, hgsep, ossep, bool)
1123 # srcs: list of (hgsep, hgsep, ossep, bool)
1123 # return: function that takes hgsep and returns ossep
1124 # return: function that takes hgsep and returns ossep
1124 def targetpathafterfn(pat, dest, srcs):
1125 def targetpathafterfn(pat, dest, srcs):
1125 if matchmod.patkind(pat):
1126 if matchmod.patkind(pat):
1126 # a mercurial pattern
1127 # a mercurial pattern
1127 res = lambda p: os.path.join(dest,
1128 res = lambda p: os.path.join(dest,
1128 os.path.basename(util.localpath(p)))
1129 os.path.basename(util.localpath(p)))
1129 else:
1130 else:
1130 abspfx = pathutil.canonpath(repo.root, cwd, pat)
1131 abspfx = pathutil.canonpath(repo.root, cwd, pat)
1131 if len(abspfx) < len(srcs[0][0]):
1132 if len(abspfx) < len(srcs[0][0]):
1132 # A directory. Either the target path contains the last
1133 # A directory. Either the target path contains the last
1133 # component of the source path or it does not.
1134 # component of the source path or it does not.
1134 def evalpath(striplen):
1135 def evalpath(striplen):
1135 score = 0
1136 score = 0
1136 for s in srcs:
1137 for s in srcs:
1137 t = os.path.join(dest, util.localpath(s[0])[striplen:])
1138 t = os.path.join(dest, util.localpath(s[0])[striplen:])
1138 if os.path.lexists(t):
1139 if os.path.lexists(t):
1139 score += 1
1140 score += 1
1140 return score
1141 return score
1141
1142
1142 abspfx = util.localpath(abspfx)
1143 abspfx = util.localpath(abspfx)
1143 striplen = len(abspfx)
1144 striplen = len(abspfx)
1144 if striplen:
1145 if striplen:
1145 striplen += len(pycompat.ossep)
1146 striplen += len(pycompat.ossep)
1146 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
1147 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
1147 score = evalpath(striplen)
1148 score = evalpath(striplen)
1148 striplen1 = len(os.path.split(abspfx)[0])
1149 striplen1 = len(os.path.split(abspfx)[0])
1149 if striplen1:
1150 if striplen1:
1150 striplen1 += len(pycompat.ossep)
1151 striplen1 += len(pycompat.ossep)
1151 if evalpath(striplen1) > score:
1152 if evalpath(striplen1) > score:
1152 striplen = striplen1
1153 striplen = striplen1
1153 res = lambda p: os.path.join(dest,
1154 res = lambda p: os.path.join(dest,
1154 util.localpath(p)[striplen:])
1155 util.localpath(p)[striplen:])
1155 else:
1156 else:
1156 # a file
1157 # a file
1157 if destdirexists:
1158 if destdirexists:
1158 res = lambda p: os.path.join(dest,
1159 res = lambda p: os.path.join(dest,
1159 os.path.basename(util.localpath(p)))
1160 os.path.basename(util.localpath(p)))
1160 else:
1161 else:
1161 res = lambda p: dest
1162 res = lambda p: dest
1162 return res
1163 return res
1163
1164
1164 pats = scmutil.expandpats(pats)
1165 pats = scmutil.expandpats(pats)
1165 if not pats:
1166 if not pats:
1166 raise error.Abort(_('no source or destination specified'))
1167 raise error.Abort(_('no source or destination specified'))
1167 if len(pats) == 1:
1168 if len(pats) == 1:
1168 raise error.Abort(_('no destination specified'))
1169 raise error.Abort(_('no destination specified'))
1169 dest = pats.pop()
1170 dest = pats.pop()
1170 destdirexists = os.path.isdir(dest) and not os.path.islink(dest)
1171 destdirexists = os.path.isdir(dest) and not os.path.islink(dest)
1171 if not destdirexists:
1172 if not destdirexists:
1172 if len(pats) > 1 or matchmod.patkind(pats[0]):
1173 if len(pats) > 1 or matchmod.patkind(pats[0]):
1173 raise error.Abort(_('with multiple sources, destination must be an '
1174 raise error.Abort(_('with multiple sources, destination must be an '
1174 'existing directory'))
1175 'existing directory'))
1175 if util.endswithsep(dest):
1176 if util.endswithsep(dest):
1176 raise error.Abort(_('destination %s is not a directory') % dest)
1177 raise error.Abort(_('destination %s is not a directory') % dest)
1177
1178
1178 tfn = targetpathfn
1179 tfn = targetpathfn
1179 if after:
1180 if after:
1180 tfn = targetpathafterfn
1181 tfn = targetpathafterfn
1181 copylist = []
1182 copylist = []
1182 for pat in pats:
1183 for pat in pats:
1183 srcs = walkpat(pat)
1184 srcs = walkpat(pat)
1184 if not srcs:
1185 if not srcs:
1185 continue
1186 continue
1186 copylist.append((tfn(pat, dest, srcs), srcs))
1187 copylist.append((tfn(pat, dest, srcs), srcs))
1187 if not copylist:
1188 if not copylist:
1188 raise error.Abort(_('no files to copy'))
1189 raise error.Abort(_('no files to copy'))
1189
1190
1190 errors = 0
1191 errors = 0
1191 for targetpath, srcs in copylist:
1192 for targetpath, srcs in copylist:
1192 for abssrc, relsrc, exact in srcs:
1193 for abssrc, relsrc, exact in srcs:
1193 if copyfile(abssrc, relsrc, targetpath(abssrc), exact):
1194 if copyfile(abssrc, relsrc, targetpath(abssrc), exact):
1194 errors += 1
1195 errors += 1
1195
1196
1196 if errors:
1197 if errors:
1197 ui.warn(_('(consider using --after)\n'))
1198 ui.warn(_('(consider using --after)\n'))
1198
1199
1199 return errors != 0
1200 return errors != 0
1200
1201
1201 ## facility to let extension process additional data into an import patch
1202 ## facility to let extension process additional data into an import patch
1202 # list of identifier to be executed in order
1203 # list of identifier to be executed in order
1203 extrapreimport = [] # run before commit
1204 extrapreimport = [] # run before commit
1204 extrapostimport = [] # run after commit
1205 extrapostimport = [] # run after commit
1205 # mapping from identifier to actual import function
1206 # mapping from identifier to actual import function
1206 #
1207 #
1207 # 'preimport' are run before the commit is made and are provided the following
1208 # 'preimport' are run before the commit is made and are provided the following
1208 # arguments:
1209 # arguments:
1209 # - repo: the localrepository instance,
1210 # - repo: the localrepository instance,
1210 # - patchdata: data extracted from patch header (cf m.patch.patchheadermap),
1211 # - patchdata: data extracted from patch header (cf m.patch.patchheadermap),
1211 # - extra: the future extra dictionary of the changeset, please mutate it,
1212 # - extra: the future extra dictionary of the changeset, please mutate it,
1212 # - opts: the import options.
1213 # - opts: the import options.
1213 # XXX ideally, we would just pass an ctx ready to be computed, that would allow
1214 # XXX ideally, we would just pass an ctx ready to be computed, that would allow
1214 # mutation of in memory commit and more. Feel free to rework the code to get
1215 # mutation of in memory commit and more. Feel free to rework the code to get
1215 # there.
1216 # there.
1216 extrapreimportmap = {}
1217 extrapreimportmap = {}
1217 # 'postimport' are run after the commit is made and are provided the following
1218 # 'postimport' are run after the commit is made and are provided the following
1218 # argument:
1219 # argument:
1219 # - ctx: the changectx created by import.
1220 # - ctx: the changectx created by import.
1220 extrapostimportmap = {}
1221 extrapostimportmap = {}
1221
1222
1222 def tryimportone(ui, repo, hunk, parents, opts, msgs, updatefunc):
1223 def tryimportone(ui, repo, hunk, parents, opts, msgs, updatefunc):
1223 """Utility function used by commands.import to import a single patch
1224 """Utility function used by commands.import to import a single patch
1224
1225
1225 This function is explicitly defined here to help the evolve extension to
1226 This function is explicitly defined here to help the evolve extension to
1226 wrap this part of the import logic.
1227 wrap this part of the import logic.
1227
1228
1228 The API is currently a bit ugly because it a simple code translation from
1229 The API is currently a bit ugly because it a simple code translation from
1229 the import command. Feel free to make it better.
1230 the import command. Feel free to make it better.
1230
1231
1231 :hunk: a patch (as a binary string)
1232 :hunk: a patch (as a binary string)
1232 :parents: nodes that will be parent of the created commit
1233 :parents: nodes that will be parent of the created commit
1233 :opts: the full dict of option passed to the import command
1234 :opts: the full dict of option passed to the import command
1234 :msgs: list to save commit message to.
1235 :msgs: list to save commit message to.
1235 (used in case we need to save it when failing)
1236 (used in case we need to save it when failing)
1236 :updatefunc: a function that update a repo to a given node
1237 :updatefunc: a function that update a repo to a given node
1237 updatefunc(<repo>, <node>)
1238 updatefunc(<repo>, <node>)
1238 """
1239 """
1239 # avoid cycle context -> subrepo -> cmdutil
1240 # avoid cycle context -> subrepo -> cmdutil
1240 from . import context
1241 from . import context
1241 extractdata = patch.extract(ui, hunk)
1242 extractdata = patch.extract(ui, hunk)
1242 tmpname = extractdata.get('filename')
1243 tmpname = extractdata.get('filename')
1243 message = extractdata.get('message')
1244 message = extractdata.get('message')
1244 user = opts.get('user') or extractdata.get('user')
1245 user = opts.get('user') or extractdata.get('user')
1245 date = opts.get('date') or extractdata.get('date')
1246 date = opts.get('date') or extractdata.get('date')
1246 branch = extractdata.get('branch')
1247 branch = extractdata.get('branch')
1247 nodeid = extractdata.get('nodeid')
1248 nodeid = extractdata.get('nodeid')
1248 p1 = extractdata.get('p1')
1249 p1 = extractdata.get('p1')
1249 p2 = extractdata.get('p2')
1250 p2 = extractdata.get('p2')
1250
1251
1251 nocommit = opts.get('no_commit')
1252 nocommit = opts.get('no_commit')
1252 importbranch = opts.get('import_branch')
1253 importbranch = opts.get('import_branch')
1253 update = not opts.get('bypass')
1254 update = not opts.get('bypass')
1254 strip = opts["strip"]
1255 strip = opts["strip"]
1255 prefix = opts["prefix"]
1256 prefix = opts["prefix"]
1256 sim = float(opts.get('similarity') or 0)
1257 sim = float(opts.get('similarity') or 0)
1257 if not tmpname:
1258 if not tmpname:
1258 return (None, None, False)
1259 return (None, None, False)
1259
1260
1260 rejects = False
1261 rejects = False
1261
1262
1262 try:
1263 try:
1263 cmdline_message = logmessage(ui, opts)
1264 cmdline_message = logmessage(ui, opts)
1264 if cmdline_message:
1265 if cmdline_message:
1265 # pickup the cmdline msg
1266 # pickup the cmdline msg
1266 message = cmdline_message
1267 message = cmdline_message
1267 elif message:
1268 elif message:
1268 # pickup the patch msg
1269 # pickup the patch msg
1269 message = message.strip()
1270 message = message.strip()
1270 else:
1271 else:
1271 # launch the editor
1272 # launch the editor
1272 message = None
1273 message = None
1273 ui.debug('message:\n%s\n' % message)
1274 ui.debug('message:\n%s\n' % message)
1274
1275
1275 if len(parents) == 1:
1276 if len(parents) == 1:
1276 parents.append(repo[nullid])
1277 parents.append(repo[nullid])
1277 if opts.get('exact'):
1278 if opts.get('exact'):
1278 if not nodeid or not p1:
1279 if not nodeid or not p1:
1279 raise error.Abort(_('not a Mercurial patch'))
1280 raise error.Abort(_('not a Mercurial patch'))
1280 p1 = repo[p1]
1281 p1 = repo[p1]
1281 p2 = repo[p2 or nullid]
1282 p2 = repo[p2 or nullid]
1282 elif p2:
1283 elif p2:
1283 try:
1284 try:
1284 p1 = repo[p1]
1285 p1 = repo[p1]
1285 p2 = repo[p2]
1286 p2 = repo[p2]
1286 # Without any options, consider p2 only if the
1287 # Without any options, consider p2 only if the
1287 # patch is being applied on top of the recorded
1288 # patch is being applied on top of the recorded
1288 # first parent.
1289 # first parent.
1289 if p1 != parents[0]:
1290 if p1 != parents[0]:
1290 p1 = parents[0]
1291 p1 = parents[0]
1291 p2 = repo[nullid]
1292 p2 = repo[nullid]
1292 except error.RepoError:
1293 except error.RepoError:
1293 p1, p2 = parents
1294 p1, p2 = parents
1294 if p2.node() == nullid:
1295 if p2.node() == nullid:
1295 ui.warn(_("warning: import the patch as a normal revision\n"
1296 ui.warn(_("warning: import the patch as a normal revision\n"
1296 "(use --exact to import the patch as a merge)\n"))
1297 "(use --exact to import the patch as a merge)\n"))
1297 else:
1298 else:
1298 p1, p2 = parents
1299 p1, p2 = parents
1299
1300
1300 n = None
1301 n = None
1301 if update:
1302 if update:
1302 if p1 != parents[0]:
1303 if p1 != parents[0]:
1303 updatefunc(repo, p1.node())
1304 updatefunc(repo, p1.node())
1304 if p2 != parents[1]:
1305 if p2 != parents[1]:
1305 repo.setparents(p1.node(), p2.node())
1306 repo.setparents(p1.node(), p2.node())
1306
1307
1307 if opts.get('exact') or importbranch:
1308 if opts.get('exact') or importbranch:
1308 repo.dirstate.setbranch(branch or 'default')
1309 repo.dirstate.setbranch(branch or 'default')
1309
1310
1310 partial = opts.get('partial', False)
1311 partial = opts.get('partial', False)
1311 files = set()
1312 files = set()
1312 try:
1313 try:
1313 patch.patch(ui, repo, tmpname, strip=strip, prefix=prefix,
1314 patch.patch(ui, repo, tmpname, strip=strip, prefix=prefix,
1314 files=files, eolmode=None, similarity=sim / 100.0)
1315 files=files, eolmode=None, similarity=sim / 100.0)
1315 except error.PatchError as e:
1316 except error.PatchError as e:
1316 if not partial:
1317 if not partial:
1317 raise error.Abort(str(e))
1318 raise error.Abort(str(e))
1318 if partial:
1319 if partial:
1319 rejects = True
1320 rejects = True
1320
1321
1321 files = list(files)
1322 files = list(files)
1322 if nocommit:
1323 if nocommit:
1323 if message:
1324 if message:
1324 msgs.append(message)
1325 msgs.append(message)
1325 else:
1326 else:
1326 if opts.get('exact') or p2:
1327 if opts.get('exact') or p2:
1327 # If you got here, you either use --force and know what
1328 # If you got here, you either use --force and know what
1328 # you are doing or used --exact or a merge patch while
1329 # you are doing or used --exact or a merge patch while
1329 # being updated to its first parent.
1330 # being updated to its first parent.
1330 m = None
1331 m = None
1331 else:
1332 else:
1332 m = scmutil.matchfiles(repo, files or [])
1333 m = scmutil.matchfiles(repo, files or [])
1333 editform = mergeeditform(repo[None], 'import.normal')
1334 editform = mergeeditform(repo[None], 'import.normal')
1334 if opts.get('exact'):
1335 if opts.get('exact'):
1335 editor = None
1336 editor = None
1336 else:
1337 else:
1337 editor = getcommiteditor(editform=editform,
1338 editor = getcommiteditor(editform=editform,
1338 **pycompat.strkwargs(opts))
1339 **pycompat.strkwargs(opts))
1339 extra = {}
1340 extra = {}
1340 for idfunc in extrapreimport:
1341 for idfunc in extrapreimport:
1341 extrapreimportmap[idfunc](repo, extractdata, extra, opts)
1342 extrapreimportmap[idfunc](repo, extractdata, extra, opts)
1342 overrides = {}
1343 overrides = {}
1343 if partial:
1344 if partial:
1344 overrides[('ui', 'allowemptycommit')] = True
1345 overrides[('ui', 'allowemptycommit')] = True
1345 with repo.ui.configoverride(overrides, 'import'):
1346 with repo.ui.configoverride(overrides, 'import'):
1346 n = repo.commit(message, user,
1347 n = repo.commit(message, user,
1347 date, match=m,
1348 date, match=m,
1348 editor=editor, extra=extra)
1349 editor=editor, extra=extra)
1349 for idfunc in extrapostimport:
1350 for idfunc in extrapostimport:
1350 extrapostimportmap[idfunc](repo[n])
1351 extrapostimportmap[idfunc](repo[n])
1351 else:
1352 else:
1352 if opts.get('exact') or importbranch:
1353 if opts.get('exact') or importbranch:
1353 branch = branch or 'default'
1354 branch = branch or 'default'
1354 else:
1355 else:
1355 branch = p1.branch()
1356 branch = p1.branch()
1356 store = patch.filestore()
1357 store = patch.filestore()
1357 try:
1358 try:
1358 files = set()
1359 files = set()
1359 try:
1360 try:
1360 patch.patchrepo(ui, repo, p1, store, tmpname, strip, prefix,
1361 patch.patchrepo(ui, repo, p1, store, tmpname, strip, prefix,
1361 files, eolmode=None)
1362 files, eolmode=None)
1362 except error.PatchError as e:
1363 except error.PatchError as e:
1363 raise error.Abort(str(e))
1364 raise error.Abort(str(e))
1364 if opts.get('exact'):
1365 if opts.get('exact'):
1365 editor = None
1366 editor = None
1366 else:
1367 else:
1367 editor = getcommiteditor(editform='import.bypass')
1368 editor = getcommiteditor(editform='import.bypass')
1368 memctx = context.memctx(repo, (p1.node(), p2.node()),
1369 memctx = context.memctx(repo, (p1.node(), p2.node()),
1369 message,
1370 message,
1370 files=files,
1371 files=files,
1371 filectxfn=store,
1372 filectxfn=store,
1372 user=user,
1373 user=user,
1373 date=date,
1374 date=date,
1374 branch=branch,
1375 branch=branch,
1375 editor=editor)
1376 editor=editor)
1376 n = memctx.commit()
1377 n = memctx.commit()
1377 finally:
1378 finally:
1378 store.close()
1379 store.close()
1379 if opts.get('exact') and nocommit:
1380 if opts.get('exact') and nocommit:
1380 # --exact with --no-commit is still useful in that it does merge
1381 # --exact with --no-commit is still useful in that it does merge
1381 # and branch bits
1382 # and branch bits
1382 ui.warn(_("warning: can't check exact import with --no-commit\n"))
1383 ui.warn(_("warning: can't check exact import with --no-commit\n"))
1383 elif opts.get('exact') and hex(n) != nodeid:
1384 elif opts.get('exact') and hex(n) != nodeid:
1384 raise error.Abort(_('patch is damaged or loses information'))
1385 raise error.Abort(_('patch is damaged or loses information'))
1385 msg = _('applied to working directory')
1386 msg = _('applied to working directory')
1386 if n:
1387 if n:
1387 # i18n: refers to a short changeset id
1388 # i18n: refers to a short changeset id
1388 msg = _('created %s') % short(n)
1389 msg = _('created %s') % short(n)
1389 return (msg, n, rejects)
1390 return (msg, n, rejects)
1390 finally:
1391 finally:
1391 os.unlink(tmpname)
1392 os.unlink(tmpname)
1392
1393
1393 # facility to let extensions include additional data in an exported patch
1394 # facility to let extensions include additional data in an exported patch
1394 # list of identifiers to be executed in order
1395 # list of identifiers to be executed in order
1395 extraexport = []
1396 extraexport = []
1396 # mapping from identifier to actual export function
1397 # mapping from identifier to actual export function
1397 # function as to return a string to be added to the header or None
1398 # function as to return a string to be added to the header or None
1398 # it is given two arguments (sequencenumber, changectx)
1399 # it is given two arguments (sequencenumber, changectx)
1399 extraexportmap = {}
1400 extraexportmap = {}
1400
1401
1401 def _exportsingle(repo, ctx, match, switch_parent, rev, seqno, write, diffopts):
1402 def _exportsingle(repo, ctx, match, switch_parent, rev, seqno, write, diffopts):
1402 node = scmutil.binnode(ctx)
1403 node = scmutil.binnode(ctx)
1403 parents = [p.node() for p in ctx.parents() if p]
1404 parents = [p.node() for p in ctx.parents() if p]
1404 branch = ctx.branch()
1405 branch = ctx.branch()
1405 if switch_parent:
1406 if switch_parent:
1406 parents.reverse()
1407 parents.reverse()
1407
1408
1408 if parents:
1409 if parents:
1409 prev = parents[0]
1410 prev = parents[0]
1410 else:
1411 else:
1411 prev = nullid
1412 prev = nullid
1412
1413
1413 write("# HG changeset patch\n")
1414 write("# HG changeset patch\n")
1414 write("# User %s\n" % ctx.user())
1415 write("# User %s\n" % ctx.user())
1415 write("# Date %d %d\n" % ctx.date())
1416 write("# Date %d %d\n" % ctx.date())
1416 write("# %s\n" % util.datestr(ctx.date()))
1417 write("# %s\n" % util.datestr(ctx.date()))
1417 if branch and branch != 'default':
1418 if branch and branch != 'default':
1418 write("# Branch %s\n" % branch)
1419 write("# Branch %s\n" % branch)
1419 write("# Node ID %s\n" % hex(node))
1420 write("# Node ID %s\n" % hex(node))
1420 write("# Parent %s\n" % hex(prev))
1421 write("# Parent %s\n" % hex(prev))
1421 if len(parents) > 1:
1422 if len(parents) > 1:
1422 write("# Parent %s\n" % hex(parents[1]))
1423 write("# Parent %s\n" % hex(parents[1]))
1423
1424
1424 for headerid in extraexport:
1425 for headerid in extraexport:
1425 header = extraexportmap[headerid](seqno, ctx)
1426 header = extraexportmap[headerid](seqno, ctx)
1426 if header is not None:
1427 if header is not None:
1427 write('# %s\n' % header)
1428 write('# %s\n' % header)
1428 write(ctx.description().rstrip())
1429 write(ctx.description().rstrip())
1429 write("\n\n")
1430 write("\n\n")
1430
1431
1431 for chunk, label in patch.diffui(repo, prev, node, match, opts=diffopts):
1432 for chunk, label in patch.diffui(repo, prev, node, match, opts=diffopts):
1432 write(chunk, label=label)
1433 write(chunk, label=label)
1433
1434
1434 def export(repo, revs, fntemplate='hg-%h.patch', fp=None, switch_parent=False,
1435 def export(repo, revs, fntemplate='hg-%h.patch', fp=None, switch_parent=False,
1435 opts=None, match=None):
1436 opts=None, match=None):
1436 '''export changesets as hg patches
1437 '''export changesets as hg patches
1437
1438
1438 Args:
1439 Args:
1439 repo: The repository from which we're exporting revisions.
1440 repo: The repository from which we're exporting revisions.
1440 revs: A list of revisions to export as revision numbers.
1441 revs: A list of revisions to export as revision numbers.
1441 fntemplate: An optional string to use for generating patch file names.
1442 fntemplate: An optional string to use for generating patch file names.
1442 fp: An optional file-like object to which patches should be written.
1443 fp: An optional file-like object to which patches should be written.
1443 switch_parent: If True, show diffs against second parent when not nullid.
1444 switch_parent: If True, show diffs against second parent when not nullid.
1444 Default is false, which always shows diff against p1.
1445 Default is false, which always shows diff against p1.
1445 opts: diff options to use for generating the patch.
1446 opts: diff options to use for generating the patch.
1446 match: If specified, only export changes to files matching this matcher.
1447 match: If specified, only export changes to files matching this matcher.
1447
1448
1448 Returns:
1449 Returns:
1449 Nothing.
1450 Nothing.
1450
1451
1451 Side Effect:
1452 Side Effect:
1452 "HG Changeset Patch" data is emitted to one of the following
1453 "HG Changeset Patch" data is emitted to one of the following
1453 destinations:
1454 destinations:
1454 fp is specified: All revs are written to the specified
1455 fp is specified: All revs are written to the specified
1455 file-like object.
1456 file-like object.
1456 fntemplate specified: Each rev is written to a unique file named using
1457 fntemplate specified: Each rev is written to a unique file named using
1457 the given template.
1458 the given template.
1458 Neither fp nor template specified: All revs written to repo.ui.write()
1459 Neither fp nor template specified: All revs written to repo.ui.write()
1459 '''
1460 '''
1460
1461
1461 total = len(revs)
1462 total = len(revs)
1462 revwidth = max(len(str(rev)) for rev in revs)
1463 revwidth = max(len(str(rev)) for rev in revs)
1463 filemode = {}
1464 filemode = {}
1464
1465
1465 write = None
1466 write = None
1466 dest = '<unnamed>'
1467 dest = '<unnamed>'
1467 if fp:
1468 if fp:
1468 dest = getattr(fp, 'name', dest)
1469 dest = getattr(fp, 'name', dest)
1469 def write(s, **kw):
1470 def write(s, **kw):
1470 fp.write(s)
1471 fp.write(s)
1471 elif not fntemplate:
1472 elif not fntemplate:
1472 write = repo.ui.write
1473 write = repo.ui.write
1473
1474
1474 for seqno, rev in enumerate(revs, 1):
1475 for seqno, rev in enumerate(revs, 1):
1475 ctx = repo[rev]
1476 ctx = repo[rev]
1476 fo = None
1477 fo = None
1477 if not fp and fntemplate:
1478 if not fp and fntemplate:
1478 desc_lines = ctx.description().rstrip().split('\n')
1479 desc_lines = ctx.description().rstrip().split('\n')
1479 desc = desc_lines[0] #Commit always has a first line.
1480 desc = desc_lines[0] #Commit always has a first line.
1480 fo = makefileobj(repo, fntemplate, ctx.node(), desc=desc,
1481 fo = makefileobj(repo, fntemplate, ctx.node(), desc=desc,
1481 total=total, seqno=seqno, revwidth=revwidth,
1482 total=total, seqno=seqno, revwidth=revwidth,
1482 mode='wb', modemap=filemode)
1483 mode='wb', modemap=filemode)
1483 dest = fo.name
1484 dest = fo.name
1484 def write(s, **kw):
1485 def write(s, **kw):
1485 fo.write(s)
1486 fo.write(s)
1486 if not dest.startswith('<'):
1487 if not dest.startswith('<'):
1487 repo.ui.note("%s\n" % dest)
1488 repo.ui.note("%s\n" % dest)
1488 _exportsingle(
1489 _exportsingle(
1489 repo, ctx, match, switch_parent, rev, seqno, write, opts)
1490 repo, ctx, match, switch_parent, rev, seqno, write, opts)
1490 if fo is not None:
1491 if fo is not None:
1491 fo.close()
1492 fo.close()
1492
1493
1493 def diffordiffstat(ui, repo, diffopts, node1, node2, match,
1494 def diffordiffstat(ui, repo, diffopts, node1, node2, match,
1494 changes=None, stat=False, fp=None, prefix='',
1495 changes=None, stat=False, fp=None, prefix='',
1495 root='', listsubrepos=False, hunksfilterfn=None):
1496 root='', listsubrepos=False, hunksfilterfn=None):
1496 '''show diff or diffstat.'''
1497 '''show diff or diffstat.'''
1497 if fp is None:
1498 if fp is None:
1498 write = ui.write
1499 write = ui.write
1499 else:
1500 else:
1500 def write(s, **kw):
1501 def write(s, **kw):
1501 fp.write(s)
1502 fp.write(s)
1502
1503
1503 if root:
1504 if root:
1504 relroot = pathutil.canonpath(repo.root, repo.getcwd(), root)
1505 relroot = pathutil.canonpath(repo.root, repo.getcwd(), root)
1505 else:
1506 else:
1506 relroot = ''
1507 relroot = ''
1507 if relroot != '':
1508 if relroot != '':
1508 # XXX relative roots currently don't work if the root is within a
1509 # XXX relative roots currently don't work if the root is within a
1509 # subrepo
1510 # subrepo
1510 uirelroot = match.uipath(relroot)
1511 uirelroot = match.uipath(relroot)
1511 relroot += '/'
1512 relroot += '/'
1512 for matchroot in match.files():
1513 for matchroot in match.files():
1513 if not matchroot.startswith(relroot):
1514 if not matchroot.startswith(relroot):
1514 ui.warn(_('warning: %s not inside relative root %s\n') % (
1515 ui.warn(_('warning: %s not inside relative root %s\n') % (
1515 match.uipath(matchroot), uirelroot))
1516 match.uipath(matchroot), uirelroot))
1516
1517
1517 if stat:
1518 if stat:
1518 diffopts = diffopts.copy(context=0, noprefix=False)
1519 diffopts = diffopts.copy(context=0, noprefix=False)
1519 width = 80
1520 width = 80
1520 if not ui.plain():
1521 if not ui.plain():
1521 width = ui.termwidth()
1522 width = ui.termwidth()
1522 chunks = patch.diff(repo, node1, node2, match, changes, opts=diffopts,
1523 chunks = patch.diff(repo, node1, node2, match, changes, opts=diffopts,
1523 prefix=prefix, relroot=relroot,
1524 prefix=prefix, relroot=relroot,
1524 hunksfilterfn=hunksfilterfn)
1525 hunksfilterfn=hunksfilterfn)
1525 for chunk, label in patch.diffstatui(util.iterlines(chunks),
1526 for chunk, label in patch.diffstatui(util.iterlines(chunks),
1526 width=width):
1527 width=width):
1527 write(chunk, label=label)
1528 write(chunk, label=label)
1528 else:
1529 else:
1529 for chunk, label in patch.diffui(repo, node1, node2, match,
1530 for chunk, label in patch.diffui(repo, node1, node2, match,
1530 changes, opts=diffopts, prefix=prefix,
1531 changes, opts=diffopts, prefix=prefix,
1531 relroot=relroot,
1532 relroot=relroot,
1532 hunksfilterfn=hunksfilterfn):
1533 hunksfilterfn=hunksfilterfn):
1533 write(chunk, label=label)
1534 write(chunk, label=label)
1534
1535
1535 if listsubrepos:
1536 if listsubrepos:
1536 ctx1 = repo[node1]
1537 ctx1 = repo[node1]
1537 ctx2 = repo[node2]
1538 ctx2 = repo[node2]
1538 for subpath, sub in scmutil.itersubrepos(ctx1, ctx2):
1539 for subpath, sub in scmutil.itersubrepos(ctx1, ctx2):
1539 tempnode2 = node2
1540 tempnode2 = node2
1540 try:
1541 try:
1541 if node2 is not None:
1542 if node2 is not None:
1542 tempnode2 = ctx2.substate[subpath][1]
1543 tempnode2 = ctx2.substate[subpath][1]
1543 except KeyError:
1544 except KeyError:
1544 # A subrepo that existed in node1 was deleted between node1 and
1545 # A subrepo that existed in node1 was deleted between node1 and
1545 # node2 (inclusive). Thus, ctx2's substate won't contain that
1546 # node2 (inclusive). Thus, ctx2's substate won't contain that
1546 # subpath. The best we can do is to ignore it.
1547 # subpath. The best we can do is to ignore it.
1547 tempnode2 = None
1548 tempnode2 = None
1548 submatch = matchmod.subdirmatcher(subpath, match)
1549 submatch = matchmod.subdirmatcher(subpath, match)
1549 sub.diff(ui, diffopts, tempnode2, submatch, changes=changes,
1550 sub.diff(ui, diffopts, tempnode2, submatch, changes=changes,
1550 stat=stat, fp=fp, prefix=prefix)
1551 stat=stat, fp=fp, prefix=prefix)
1551
1552
1552 def _changesetlabels(ctx):
1553 def _changesetlabels(ctx):
1553 labels = ['log.changeset', 'changeset.%s' % ctx.phasestr()]
1554 labels = ['log.changeset', 'changeset.%s' % ctx.phasestr()]
1554 if ctx.obsolete():
1555 if ctx.obsolete():
1555 labels.append('changeset.obsolete')
1556 labels.append('changeset.obsolete')
1556 if ctx.isunstable():
1557 if ctx.isunstable():
1557 labels.append('changeset.unstable')
1558 labels.append('changeset.unstable')
1558 for instability in ctx.instabilities():
1559 for instability in ctx.instabilities():
1559 labels.append('instability.%s' % instability)
1560 labels.append('instability.%s' % instability)
1560 return ' '.join(labels)
1561 return ' '.join(labels)
1561
1562
1562 class changeset_printer(object):
1563 class changeset_printer(object):
1563 '''show changeset information when templating not requested.'''
1564 '''show changeset information when templating not requested.'''
1564
1565
1565 def __init__(self, ui, repo, matchfn, diffopts, buffered):
1566 def __init__(self, ui, repo, matchfn, diffopts, buffered):
1566 self.ui = ui
1567 self.ui = ui
1567 self.repo = repo
1568 self.repo = repo
1568 self.buffered = buffered
1569 self.buffered = buffered
1569 self.matchfn = matchfn
1570 self.matchfn = matchfn
1570 self.diffopts = diffopts
1571 self.diffopts = diffopts
1571 self.header = {}
1572 self.header = {}
1572 self.hunk = {}
1573 self.hunk = {}
1573 self.lastheader = None
1574 self.lastheader = None
1574 self.footer = None
1575 self.footer = None
1575 self._columns = templatekw.getlogcolumns()
1576 self._columns = templatekw.getlogcolumns()
1576
1577
1577 def flush(self, ctx):
1578 def flush(self, ctx):
1578 rev = ctx.rev()
1579 rev = ctx.rev()
1579 if rev in self.header:
1580 if rev in self.header:
1580 h = self.header[rev]
1581 h = self.header[rev]
1581 if h != self.lastheader:
1582 if h != self.lastheader:
1582 self.lastheader = h
1583 self.lastheader = h
1583 self.ui.write(h)
1584 self.ui.write(h)
1584 del self.header[rev]
1585 del self.header[rev]
1585 if rev in self.hunk:
1586 if rev in self.hunk:
1586 self.ui.write(self.hunk[rev])
1587 self.ui.write(self.hunk[rev])
1587 del self.hunk[rev]
1588 del self.hunk[rev]
1588
1589
1589 def close(self):
1590 def close(self):
1590 if self.footer:
1591 if self.footer:
1591 self.ui.write(self.footer)
1592 self.ui.write(self.footer)
1592
1593
1593 def show(self, ctx, copies=None, matchfn=None, hunksfilterfn=None,
1594 def show(self, ctx, copies=None, matchfn=None, hunksfilterfn=None,
1594 **props):
1595 **props):
1595 props = pycompat.byteskwargs(props)
1596 props = pycompat.byteskwargs(props)
1596 if self.buffered:
1597 if self.buffered:
1597 self.ui.pushbuffer(labeled=True)
1598 self.ui.pushbuffer(labeled=True)
1598 self._show(ctx, copies, matchfn, hunksfilterfn, props)
1599 self._show(ctx, copies, matchfn, hunksfilterfn, props)
1599 self.hunk[ctx.rev()] = self.ui.popbuffer()
1600 self.hunk[ctx.rev()] = self.ui.popbuffer()
1600 else:
1601 else:
1601 self._show(ctx, copies, matchfn, hunksfilterfn, props)
1602 self._show(ctx, copies, matchfn, hunksfilterfn, props)
1602
1603
1603 def _show(self, ctx, copies, matchfn, hunksfilterfn, props):
1604 def _show(self, ctx, copies, matchfn, hunksfilterfn, props):
1604 '''show a single changeset or file revision'''
1605 '''show a single changeset or file revision'''
1605 changenode = ctx.node()
1606 changenode = ctx.node()
1606 rev = ctx.rev()
1607 rev = ctx.rev()
1607
1608
1608 if self.ui.quiet:
1609 if self.ui.quiet:
1609 self.ui.write("%s\n" % scmutil.formatchangeid(ctx),
1610 self.ui.write("%s\n" % scmutil.formatchangeid(ctx),
1610 label='log.node')
1611 label='log.node')
1611 return
1612 return
1612
1613
1613 columns = self._columns
1614 columns = self._columns
1614 self.ui.write(columns['changeset'] % scmutil.formatchangeid(ctx),
1615 self.ui.write(columns['changeset'] % scmutil.formatchangeid(ctx),
1615 label=_changesetlabels(ctx))
1616 label=_changesetlabels(ctx))
1616
1617
1617 # branches are shown first before any other names due to backwards
1618 # branches are shown first before any other names due to backwards
1618 # compatibility
1619 # compatibility
1619 branch = ctx.branch()
1620 branch = ctx.branch()
1620 # don't show the default branch name
1621 # don't show the default branch name
1621 if branch != 'default':
1622 if branch != 'default':
1622 self.ui.write(columns['branch'] % branch, label='log.branch')
1623 self.ui.write(columns['branch'] % branch, label='log.branch')
1623
1624
1624 for nsname, ns in self.repo.names.iteritems():
1625 for nsname, ns in self.repo.names.iteritems():
1625 # branches has special logic already handled above, so here we just
1626 # branches has special logic already handled above, so here we just
1626 # skip it
1627 # skip it
1627 if nsname == 'branches':
1628 if nsname == 'branches':
1628 continue
1629 continue
1629 # we will use the templatename as the color name since those two
1630 # we will use the templatename as the color name since those two
1630 # should be the same
1631 # should be the same
1631 for name in ns.names(self.repo, changenode):
1632 for name in ns.names(self.repo, changenode):
1632 self.ui.write(ns.logfmt % name,
1633 self.ui.write(ns.logfmt % name,
1633 label='log.%s' % ns.colorname)
1634 label='log.%s' % ns.colorname)
1634 if self.ui.debugflag:
1635 if self.ui.debugflag:
1635 self.ui.write(columns['phase'] % ctx.phasestr(), label='log.phase')
1636 self.ui.write(columns['phase'] % ctx.phasestr(), label='log.phase')
1636 for pctx in scmutil.meaningfulparents(self.repo, ctx):
1637 for pctx in scmutil.meaningfulparents(self.repo, ctx):
1637 label = 'log.parent changeset.%s' % pctx.phasestr()
1638 label = 'log.parent changeset.%s' % pctx.phasestr()
1638 self.ui.write(columns['parent'] % scmutil.formatchangeid(pctx),
1639 self.ui.write(columns['parent'] % scmutil.formatchangeid(pctx),
1639 label=label)
1640 label=label)
1640
1641
1641 if self.ui.debugflag and rev is not None:
1642 if self.ui.debugflag and rev is not None:
1642 mnode = ctx.manifestnode()
1643 mnode = ctx.manifestnode()
1643 mrev = self.repo.manifestlog._revlog.rev(mnode)
1644 mrev = self.repo.manifestlog._revlog.rev(mnode)
1644 self.ui.write(columns['manifest']
1645 self.ui.write(columns['manifest']
1645 % scmutil.formatrevnode(self.ui, mrev, mnode),
1646 % scmutil.formatrevnode(self.ui, mrev, mnode),
1646 label='ui.debug log.manifest')
1647 label='ui.debug log.manifest')
1647 self.ui.write(columns['user'] % ctx.user(), label='log.user')
1648 self.ui.write(columns['user'] % ctx.user(), label='log.user')
1648 self.ui.write(columns['date'] % util.datestr(ctx.date()),
1649 self.ui.write(columns['date'] % util.datestr(ctx.date()),
1649 label='log.date')
1650 label='log.date')
1650
1651
1651 if ctx.isunstable():
1652 if ctx.isunstable():
1652 instabilities = ctx.instabilities()
1653 instabilities = ctx.instabilities()
1653 self.ui.write(columns['instability'] % ', '.join(instabilities),
1654 self.ui.write(columns['instability'] % ', '.join(instabilities),
1654 label='log.instability')
1655 label='log.instability')
1655
1656
1656 elif ctx.obsolete():
1657 elif ctx.obsolete():
1657 self._showobsfate(ctx)
1658 self._showobsfate(ctx)
1658
1659
1659 self._exthook(ctx)
1660 self._exthook(ctx)
1660
1661
1661 if self.ui.debugflag:
1662 if self.ui.debugflag:
1662 files = ctx.p1().status(ctx)[:3]
1663 files = ctx.p1().status(ctx)[:3]
1663 for key, value in zip(['files', 'files+', 'files-'], files):
1664 for key, value in zip(['files', 'files+', 'files-'], files):
1664 if value:
1665 if value:
1665 self.ui.write(columns[key] % " ".join(value),
1666 self.ui.write(columns[key] % " ".join(value),
1666 label='ui.debug log.files')
1667 label='ui.debug log.files')
1667 elif ctx.files() and self.ui.verbose:
1668 elif ctx.files() and self.ui.verbose:
1668 self.ui.write(columns['files'] % " ".join(ctx.files()),
1669 self.ui.write(columns['files'] % " ".join(ctx.files()),
1669 label='ui.note log.files')
1670 label='ui.note log.files')
1670 if copies and self.ui.verbose:
1671 if copies and self.ui.verbose:
1671 copies = ['%s (%s)' % c for c in copies]
1672 copies = ['%s (%s)' % c for c in copies]
1672 self.ui.write(columns['copies'] % ' '.join(copies),
1673 self.ui.write(columns['copies'] % ' '.join(copies),
1673 label='ui.note log.copies')
1674 label='ui.note log.copies')
1674
1675
1675 extra = ctx.extra()
1676 extra = ctx.extra()
1676 if extra and self.ui.debugflag:
1677 if extra and self.ui.debugflag:
1677 for key, value in sorted(extra.items()):
1678 for key, value in sorted(extra.items()):
1678 self.ui.write(columns['extra'] % (key, util.escapestr(value)),
1679 self.ui.write(columns['extra'] % (key, util.escapestr(value)),
1679 label='ui.debug log.extra')
1680 label='ui.debug log.extra')
1680
1681
1681 description = ctx.description().strip()
1682 description = ctx.description().strip()
1682 if description:
1683 if description:
1683 if self.ui.verbose:
1684 if self.ui.verbose:
1684 self.ui.write(_("description:\n"),
1685 self.ui.write(_("description:\n"),
1685 label='ui.note log.description')
1686 label='ui.note log.description')
1686 self.ui.write(description,
1687 self.ui.write(description,
1687 label='ui.note log.description')
1688 label='ui.note log.description')
1688 self.ui.write("\n\n")
1689 self.ui.write("\n\n")
1689 else:
1690 else:
1690 self.ui.write(columns['summary'] % description.splitlines()[0],
1691 self.ui.write(columns['summary'] % description.splitlines()[0],
1691 label='log.summary')
1692 label='log.summary')
1692 self.ui.write("\n")
1693 self.ui.write("\n")
1693
1694
1694 self.showpatch(ctx, matchfn, hunksfilterfn=hunksfilterfn)
1695 self.showpatch(ctx, matchfn, hunksfilterfn=hunksfilterfn)
1695
1696
1696 def _showobsfate(self, ctx):
1697 def _showobsfate(self, ctx):
1697 obsfate = templatekw.showobsfate(repo=self.repo, ctx=ctx, ui=self.ui)
1698 obsfate = templatekw.showobsfate(repo=self.repo, ctx=ctx, ui=self.ui)
1698
1699
1699 if obsfate:
1700 if obsfate:
1700 for obsfateline in obsfate:
1701 for obsfateline in obsfate:
1701 self.ui.write(self._columns['obsolete'] % obsfateline,
1702 self.ui.write(self._columns['obsolete'] % obsfateline,
1702 label='log.obsfate')
1703 label='log.obsfate')
1703
1704
1704 def _exthook(self, ctx):
1705 def _exthook(self, ctx):
1705 '''empty method used by extension as a hook point
1706 '''empty method used by extension as a hook point
1706 '''
1707 '''
1707
1708
1708 def showpatch(self, ctx, matchfn, hunksfilterfn=None):
1709 def showpatch(self, ctx, matchfn, hunksfilterfn=None):
1709 if not matchfn:
1710 if not matchfn:
1710 matchfn = self.matchfn
1711 matchfn = self.matchfn
1711 if matchfn:
1712 if matchfn:
1712 stat = self.diffopts.get('stat')
1713 stat = self.diffopts.get('stat')
1713 diff = self.diffopts.get('patch')
1714 diff = self.diffopts.get('patch')
1714 diffopts = patch.diffallopts(self.ui, self.diffopts)
1715 diffopts = patch.diffallopts(self.ui, self.diffopts)
1715 node = ctx.node()
1716 node = ctx.node()
1716 prev = ctx.p1().node()
1717 prev = ctx.p1().node()
1717 if stat:
1718 if stat:
1718 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
1719 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
1719 match=matchfn, stat=True,
1720 match=matchfn, stat=True,
1720 hunksfilterfn=hunksfilterfn)
1721 hunksfilterfn=hunksfilterfn)
1721 if diff:
1722 if diff:
1722 if stat:
1723 if stat:
1723 self.ui.write("\n")
1724 self.ui.write("\n")
1724 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
1725 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
1725 match=matchfn, stat=False,
1726 match=matchfn, stat=False,
1726 hunksfilterfn=hunksfilterfn)
1727 hunksfilterfn=hunksfilterfn)
1727 self.ui.write("\n")
1728 self.ui.write("\n")
1728
1729
1729 class jsonchangeset(changeset_printer):
1730 class jsonchangeset(changeset_printer):
1730 '''format changeset information.'''
1731 '''format changeset information.'''
1731
1732
1732 def __init__(self, ui, repo, matchfn, diffopts, buffered):
1733 def __init__(self, ui, repo, matchfn, diffopts, buffered):
1733 changeset_printer.__init__(self, ui, repo, matchfn, diffopts, buffered)
1734 changeset_printer.__init__(self, ui, repo, matchfn, diffopts, buffered)
1734 self.cache = {}
1735 self.cache = {}
1735 self._first = True
1736 self._first = True
1736
1737
1737 def close(self):
1738 def close(self):
1738 if not self._first:
1739 if not self._first:
1739 self.ui.write("\n]\n")
1740 self.ui.write("\n]\n")
1740 else:
1741 else:
1741 self.ui.write("[]\n")
1742 self.ui.write("[]\n")
1742
1743
1743 def _show(self, ctx, copies, matchfn, hunksfilterfn, props):
1744 def _show(self, ctx, copies, matchfn, hunksfilterfn, props):
1744 '''show a single changeset or file revision'''
1745 '''show a single changeset or file revision'''
1745 rev = ctx.rev()
1746 rev = ctx.rev()
1746 if rev is None:
1747 if rev is None:
1747 jrev = jnode = 'null'
1748 jrev = jnode = 'null'
1748 else:
1749 else:
1749 jrev = '%d' % rev
1750 jrev = '%d' % rev
1750 jnode = '"%s"' % hex(ctx.node())
1751 jnode = '"%s"' % hex(ctx.node())
1751 j = encoding.jsonescape
1752 j = encoding.jsonescape
1752
1753
1753 if self._first:
1754 if self._first:
1754 self.ui.write("[\n {")
1755 self.ui.write("[\n {")
1755 self._first = False
1756 self._first = False
1756 else:
1757 else:
1757 self.ui.write(",\n {")
1758 self.ui.write(",\n {")
1758
1759
1759 if self.ui.quiet:
1760 if self.ui.quiet:
1760 self.ui.write(('\n "rev": %s') % jrev)
1761 self.ui.write(('\n "rev": %s') % jrev)
1761 self.ui.write((',\n "node": %s') % jnode)
1762 self.ui.write((',\n "node": %s') % jnode)
1762 self.ui.write('\n }')
1763 self.ui.write('\n }')
1763 return
1764 return
1764
1765
1765 self.ui.write(('\n "rev": %s') % jrev)
1766 self.ui.write(('\n "rev": %s') % jrev)
1766 self.ui.write((',\n "node": %s') % jnode)
1767 self.ui.write((',\n "node": %s') % jnode)
1767 self.ui.write((',\n "branch": "%s"') % j(ctx.branch()))
1768 self.ui.write((',\n "branch": "%s"') % j(ctx.branch()))
1768 self.ui.write((',\n "phase": "%s"') % ctx.phasestr())
1769 self.ui.write((',\n "phase": "%s"') % ctx.phasestr())
1769 self.ui.write((',\n "user": "%s"') % j(ctx.user()))
1770 self.ui.write((',\n "user": "%s"') % j(ctx.user()))
1770 self.ui.write((',\n "date": [%d, %d]') % ctx.date())
1771 self.ui.write((',\n "date": [%d, %d]') % ctx.date())
1771 self.ui.write((',\n "desc": "%s"') % j(ctx.description()))
1772 self.ui.write((',\n "desc": "%s"') % j(ctx.description()))
1772
1773
1773 self.ui.write((',\n "bookmarks": [%s]') %
1774 self.ui.write((',\n "bookmarks": [%s]') %
1774 ", ".join('"%s"' % j(b) for b in ctx.bookmarks()))
1775 ", ".join('"%s"' % j(b) for b in ctx.bookmarks()))
1775 self.ui.write((',\n "tags": [%s]') %
1776 self.ui.write((',\n "tags": [%s]') %
1776 ", ".join('"%s"' % j(t) for t in ctx.tags()))
1777 ", ".join('"%s"' % j(t) for t in ctx.tags()))
1777 self.ui.write((',\n "parents": [%s]') %
1778 self.ui.write((',\n "parents": [%s]') %
1778 ", ".join('"%s"' % c.hex() for c in ctx.parents()))
1779 ", ".join('"%s"' % c.hex() for c in ctx.parents()))
1779
1780
1780 if self.ui.debugflag:
1781 if self.ui.debugflag:
1781 if rev is None:
1782 if rev is None:
1782 jmanifestnode = 'null'
1783 jmanifestnode = 'null'
1783 else:
1784 else:
1784 jmanifestnode = '"%s"' % hex(ctx.manifestnode())
1785 jmanifestnode = '"%s"' % hex(ctx.manifestnode())
1785 self.ui.write((',\n "manifest": %s') % jmanifestnode)
1786 self.ui.write((',\n "manifest": %s') % jmanifestnode)
1786
1787
1787 self.ui.write((',\n "extra": {%s}') %
1788 self.ui.write((',\n "extra": {%s}') %
1788 ", ".join('"%s": "%s"' % (j(k), j(v))
1789 ", ".join('"%s": "%s"' % (j(k), j(v))
1789 for k, v in ctx.extra().items()))
1790 for k, v in ctx.extra().items()))
1790
1791
1791 files = ctx.p1().status(ctx)
1792 files = ctx.p1().status(ctx)
1792 self.ui.write((',\n "modified": [%s]') %
1793 self.ui.write((',\n "modified": [%s]') %
1793 ", ".join('"%s"' % j(f) for f in files[0]))
1794 ", ".join('"%s"' % j(f) for f in files[0]))
1794 self.ui.write((',\n "added": [%s]') %
1795 self.ui.write((',\n "added": [%s]') %
1795 ", ".join('"%s"' % j(f) for f in files[1]))
1796 ", ".join('"%s"' % j(f) for f in files[1]))
1796 self.ui.write((',\n "removed": [%s]') %
1797 self.ui.write((',\n "removed": [%s]') %
1797 ", ".join('"%s"' % j(f) for f in files[2]))
1798 ", ".join('"%s"' % j(f) for f in files[2]))
1798
1799
1799 elif self.ui.verbose:
1800 elif self.ui.verbose:
1800 self.ui.write((',\n "files": [%s]') %
1801 self.ui.write((',\n "files": [%s]') %
1801 ", ".join('"%s"' % j(f) for f in ctx.files()))
1802 ", ".join('"%s"' % j(f) for f in ctx.files()))
1802
1803
1803 if copies:
1804 if copies:
1804 self.ui.write((',\n "copies": {%s}') %
1805 self.ui.write((',\n "copies": {%s}') %
1805 ", ".join('"%s": "%s"' % (j(k), j(v))
1806 ", ".join('"%s": "%s"' % (j(k), j(v))
1806 for k, v in copies))
1807 for k, v in copies))
1807
1808
1808 matchfn = self.matchfn
1809 matchfn = self.matchfn
1809 if matchfn:
1810 if matchfn:
1810 stat = self.diffopts.get('stat')
1811 stat = self.diffopts.get('stat')
1811 diff = self.diffopts.get('patch')
1812 diff = self.diffopts.get('patch')
1812 diffopts = patch.difffeatureopts(self.ui, self.diffopts, git=True)
1813 diffopts = patch.difffeatureopts(self.ui, self.diffopts, git=True)
1813 node, prev = ctx.node(), ctx.p1().node()
1814 node, prev = ctx.node(), ctx.p1().node()
1814 if stat:
1815 if stat:
1815 self.ui.pushbuffer()
1816 self.ui.pushbuffer()
1816 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
1817 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
1817 match=matchfn, stat=True)
1818 match=matchfn, stat=True)
1818 self.ui.write((',\n "diffstat": "%s"')
1819 self.ui.write((',\n "diffstat": "%s"')
1819 % j(self.ui.popbuffer()))
1820 % j(self.ui.popbuffer()))
1820 if diff:
1821 if diff:
1821 self.ui.pushbuffer()
1822 self.ui.pushbuffer()
1822 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
1823 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
1823 match=matchfn, stat=False)
1824 match=matchfn, stat=False)
1824 self.ui.write((',\n "diff": "%s"') % j(self.ui.popbuffer()))
1825 self.ui.write((',\n "diff": "%s"') % j(self.ui.popbuffer()))
1825
1826
1826 self.ui.write("\n }")
1827 self.ui.write("\n }")
1827
1828
1828 class changeset_templater(changeset_printer):
1829 class changeset_templater(changeset_printer):
1829 '''format changeset information.
1830 '''format changeset information.
1830
1831
1831 Note: there are a variety of convenience functions to build a
1832 Note: there are a variety of convenience functions to build a
1832 changeset_templater for common cases. See functions such as:
1833 changeset_templater for common cases. See functions such as:
1833 makelogtemplater, show_changeset, buildcommittemplate, or other
1834 makelogtemplater, show_changeset, buildcommittemplate, or other
1834 functions that use changesest_templater.
1835 functions that use changesest_templater.
1835 '''
1836 '''
1836
1837
1837 # Arguments before "buffered" used to be positional. Consider not
1838 # Arguments before "buffered" used to be positional. Consider not
1838 # adding/removing arguments before "buffered" to not break callers.
1839 # adding/removing arguments before "buffered" to not break callers.
1839 def __init__(self, ui, repo, tmplspec, matchfn=None, diffopts=None,
1840 def __init__(self, ui, repo, tmplspec, matchfn=None, diffopts=None,
1840 buffered=False):
1841 buffered=False):
1841 diffopts = diffopts or {}
1842 diffopts = diffopts or {}
1842
1843
1843 changeset_printer.__init__(self, ui, repo, matchfn, diffopts, buffered)
1844 changeset_printer.__init__(self, ui, repo, matchfn, diffopts, buffered)
1844 tres = formatter.templateresources(ui, repo)
1845 tres = formatter.templateresources(ui, repo)
1845 self.t = formatter.loadtemplater(ui, tmplspec,
1846 self.t = formatter.loadtemplater(ui, tmplspec,
1846 defaults=templatekw.keywords,
1847 defaults=templatekw.keywords,
1847 resources=tres,
1848 resources=tres,
1848 cache=templatekw.defaulttempl)
1849 cache=templatekw.defaulttempl)
1849 self._counter = itertools.count()
1850 self._counter = itertools.count()
1850 self.cache = tres['cache'] # shared with _graphnodeformatter()
1851 self.cache = tres['cache'] # shared with _graphnodeformatter()
1851
1852
1852 self._tref = tmplspec.ref
1853 self._tref = tmplspec.ref
1853 self._parts = {'header': '', 'footer': '',
1854 self._parts = {'header': '', 'footer': '',
1854 tmplspec.ref: tmplspec.ref,
1855 tmplspec.ref: tmplspec.ref,
1855 'docheader': '', 'docfooter': '',
1856 'docheader': '', 'docfooter': '',
1856 'separator': ''}
1857 'separator': ''}
1857 if tmplspec.mapfile:
1858 if tmplspec.mapfile:
1858 # find correct templates for current mode, for backward
1859 # find correct templates for current mode, for backward
1859 # compatibility with 'log -v/-q/--debug' using a mapfile
1860 # compatibility with 'log -v/-q/--debug' using a mapfile
1860 tmplmodes = [
1861 tmplmodes = [
1861 (True, ''),
1862 (True, ''),
1862 (self.ui.verbose, '_verbose'),
1863 (self.ui.verbose, '_verbose'),
1863 (self.ui.quiet, '_quiet'),
1864 (self.ui.quiet, '_quiet'),
1864 (self.ui.debugflag, '_debug'),
1865 (self.ui.debugflag, '_debug'),
1865 ]
1866 ]
1866 for mode, postfix in tmplmodes:
1867 for mode, postfix in tmplmodes:
1867 for t in self._parts:
1868 for t in self._parts:
1868 cur = t + postfix
1869 cur = t + postfix
1869 if mode and cur in self.t:
1870 if mode and cur in self.t:
1870 self._parts[t] = cur
1871 self._parts[t] = cur
1871 else:
1872 else:
1872 partnames = [p for p in self._parts.keys() if p != tmplspec.ref]
1873 partnames = [p for p in self._parts.keys() if p != tmplspec.ref]
1873 m = formatter.templatepartsmap(tmplspec, self.t, partnames)
1874 m = formatter.templatepartsmap(tmplspec, self.t, partnames)
1874 self._parts.update(m)
1875 self._parts.update(m)
1875
1876
1876 if self._parts['docheader']:
1877 if self._parts['docheader']:
1877 self.ui.write(templater.stringify(self.t(self._parts['docheader'])))
1878 self.ui.write(templater.stringify(self.t(self._parts['docheader'])))
1878
1879
1879 def close(self):
1880 def close(self):
1880 if self._parts['docfooter']:
1881 if self._parts['docfooter']:
1881 if not self.footer:
1882 if not self.footer:
1882 self.footer = ""
1883 self.footer = ""
1883 self.footer += templater.stringify(self.t(self._parts['docfooter']))
1884 self.footer += templater.stringify(self.t(self._parts['docfooter']))
1884 return super(changeset_templater, self).close()
1885 return super(changeset_templater, self).close()
1885
1886
1886 def _show(self, ctx, copies, matchfn, hunksfilterfn, props):
1887 def _show(self, ctx, copies, matchfn, hunksfilterfn, props):
1887 '''show a single changeset or file revision'''
1888 '''show a single changeset or file revision'''
1888 props = props.copy()
1889 props = props.copy()
1889 props['ctx'] = ctx
1890 props['ctx'] = ctx
1890 props['index'] = index = next(self._counter)
1891 props['index'] = index = next(self._counter)
1891 props['revcache'] = {'copies': copies}
1892 props['revcache'] = {'copies': copies}
1892 props = pycompat.strkwargs(props)
1893 props = pycompat.strkwargs(props)
1893
1894
1894 # write separator, which wouldn't work well with the header part below
1895 # write separator, which wouldn't work well with the header part below
1895 # since there's inherently a conflict between header (across items) and
1896 # since there's inherently a conflict between header (across items) and
1896 # separator (per item)
1897 # separator (per item)
1897 if self._parts['separator'] and index > 0:
1898 if self._parts['separator'] and index > 0:
1898 self.ui.write(templater.stringify(self.t(self._parts['separator'])))
1899 self.ui.write(templater.stringify(self.t(self._parts['separator'])))
1899
1900
1900 # write header
1901 # write header
1901 if self._parts['header']:
1902 if self._parts['header']:
1902 h = templater.stringify(self.t(self._parts['header'], **props))
1903 h = templater.stringify(self.t(self._parts['header'], **props))
1903 if self.buffered:
1904 if self.buffered:
1904 self.header[ctx.rev()] = h
1905 self.header[ctx.rev()] = h
1905 else:
1906 else:
1906 if self.lastheader != h:
1907 if self.lastheader != h:
1907 self.lastheader = h
1908 self.lastheader = h
1908 self.ui.write(h)
1909 self.ui.write(h)
1909
1910
1910 # write changeset metadata, then patch if requested
1911 # write changeset metadata, then patch if requested
1911 key = self._parts[self._tref]
1912 key = self._parts[self._tref]
1912 self.ui.write(templater.stringify(self.t(key, **props)))
1913 self.ui.write(templater.stringify(self.t(key, **props)))
1913 self.showpatch(ctx, matchfn, hunksfilterfn=hunksfilterfn)
1914 self.showpatch(ctx, matchfn, hunksfilterfn=hunksfilterfn)
1914
1915
1915 if self._parts['footer']:
1916 if self._parts['footer']:
1916 if not self.footer:
1917 if not self.footer:
1917 self.footer = templater.stringify(
1918 self.footer = templater.stringify(
1918 self.t(self._parts['footer'], **props))
1919 self.t(self._parts['footer'], **props))
1919
1920
1920 def logtemplatespec(tmpl, mapfile):
1921 def logtemplatespec(tmpl, mapfile):
1921 if mapfile:
1922 if mapfile:
1922 return formatter.templatespec('changeset', tmpl, mapfile)
1923 return formatter.templatespec('changeset', tmpl, mapfile)
1923 else:
1924 else:
1924 return formatter.templatespec('', tmpl, None)
1925 return formatter.templatespec('', tmpl, None)
1925
1926
1926 def _lookuplogtemplate(ui, tmpl, style):
1927 def _lookuplogtemplate(ui, tmpl, style):
1927 """Find the template matching the given template spec or style
1928 """Find the template matching the given template spec or style
1928
1929
1929 See formatter.lookuptemplate() for details.
1930 See formatter.lookuptemplate() for details.
1930 """
1931 """
1931
1932
1932 # ui settings
1933 # ui settings
1933 if not tmpl and not style: # template are stronger than style
1934 if not tmpl and not style: # template are stronger than style
1934 tmpl = ui.config('ui', 'logtemplate')
1935 tmpl = ui.config('ui', 'logtemplate')
1935 if tmpl:
1936 if tmpl:
1936 return logtemplatespec(templater.unquotestring(tmpl), None)
1937 return logtemplatespec(templater.unquotestring(tmpl), None)
1937 else:
1938 else:
1938 style = util.expandpath(ui.config('ui', 'style'))
1939 style = util.expandpath(ui.config('ui', 'style'))
1939
1940
1940 if not tmpl and style:
1941 if not tmpl and style:
1941 mapfile = style
1942 mapfile = style
1942 if not os.path.split(mapfile)[0]:
1943 if not os.path.split(mapfile)[0]:
1943 mapname = (templater.templatepath('map-cmdline.' + mapfile)
1944 mapname = (templater.templatepath('map-cmdline.' + mapfile)
1944 or templater.templatepath(mapfile))
1945 or templater.templatepath(mapfile))
1945 if mapname:
1946 if mapname:
1946 mapfile = mapname
1947 mapfile = mapname
1947 return logtemplatespec(None, mapfile)
1948 return logtemplatespec(None, mapfile)
1948
1949
1949 if not tmpl:
1950 if not tmpl:
1950 return logtemplatespec(None, None)
1951 return logtemplatespec(None, None)
1951
1952
1952 return formatter.lookuptemplate(ui, 'changeset', tmpl)
1953 return formatter.lookuptemplate(ui, 'changeset', tmpl)
1953
1954
1954 def makelogtemplater(ui, repo, tmpl, buffered=False):
1955 def makelogtemplater(ui, repo, tmpl, buffered=False):
1955 """Create a changeset_templater from a literal template 'tmpl'
1956 """Create a changeset_templater from a literal template 'tmpl'
1956 byte-string."""
1957 byte-string."""
1957 spec = logtemplatespec(tmpl, None)
1958 spec = logtemplatespec(tmpl, None)
1958 return changeset_templater(ui, repo, spec, buffered=buffered)
1959 return changeset_templater(ui, repo, spec, buffered=buffered)
1959
1960
1960 def show_changeset(ui, repo, opts, buffered=False):
1961 def show_changeset(ui, repo, opts, buffered=False):
1961 """show one changeset using template or regular display.
1962 """show one changeset using template or regular display.
1962
1963
1963 Display format will be the first non-empty hit of:
1964 Display format will be the first non-empty hit of:
1964 1. option 'template'
1965 1. option 'template'
1965 2. option 'style'
1966 2. option 'style'
1966 3. [ui] setting 'logtemplate'
1967 3. [ui] setting 'logtemplate'
1967 4. [ui] setting 'style'
1968 4. [ui] setting 'style'
1968 If all of these values are either the unset or the empty string,
1969 If all of these values are either the unset or the empty string,
1969 regular display via changeset_printer() is done.
1970 regular display via changeset_printer() is done.
1970 """
1971 """
1971 # options
1972 # options
1972 match = None
1973 match = None
1973 if opts.get('patch') or opts.get('stat'):
1974 if opts.get('patch') or opts.get('stat'):
1974 match = scmutil.matchall(repo)
1975 match = scmutil.matchall(repo)
1975
1976
1976 if opts.get('template') == 'json':
1977 if opts.get('template') == 'json':
1977 return jsonchangeset(ui, repo, match, opts, buffered)
1978 return jsonchangeset(ui, repo, match, opts, buffered)
1978
1979
1979 spec = _lookuplogtemplate(ui, opts.get('template'), opts.get('style'))
1980 spec = _lookuplogtemplate(ui, opts.get('template'), opts.get('style'))
1980
1981
1981 if not spec.ref and not spec.tmpl and not spec.mapfile:
1982 if not spec.ref and not spec.tmpl and not spec.mapfile:
1982 return changeset_printer(ui, repo, match, opts, buffered)
1983 return changeset_printer(ui, repo, match, opts, buffered)
1983
1984
1984 return changeset_templater(ui, repo, spec, match, opts, buffered)
1985 return changeset_templater(ui, repo, spec, match, opts, buffered)
1985
1986
1986 def showmarker(fm, marker, index=None):
1987 def showmarker(fm, marker, index=None):
1987 """utility function to display obsolescence marker in a readable way
1988 """utility function to display obsolescence marker in a readable way
1988
1989
1989 To be used by debug function."""
1990 To be used by debug function."""
1990 if index is not None:
1991 if index is not None:
1991 fm.write('index', '%i ', index)
1992 fm.write('index', '%i ', index)
1992 fm.write('prednode', '%s ', hex(marker.prednode()))
1993 fm.write('prednode', '%s ', hex(marker.prednode()))
1993 succs = marker.succnodes()
1994 succs = marker.succnodes()
1994 fm.condwrite(succs, 'succnodes', '%s ',
1995 fm.condwrite(succs, 'succnodes', '%s ',
1995 fm.formatlist(map(hex, succs), name='node'))
1996 fm.formatlist(map(hex, succs), name='node'))
1996 fm.write('flag', '%X ', marker.flags())
1997 fm.write('flag', '%X ', marker.flags())
1997 parents = marker.parentnodes()
1998 parents = marker.parentnodes()
1998 if parents is not None:
1999 if parents is not None:
1999 fm.write('parentnodes', '{%s} ',
2000 fm.write('parentnodes', '{%s} ',
2000 fm.formatlist(map(hex, parents), name='node', sep=', '))
2001 fm.formatlist(map(hex, parents), name='node', sep=', '))
2001 fm.write('date', '(%s) ', fm.formatdate(marker.date()))
2002 fm.write('date', '(%s) ', fm.formatdate(marker.date()))
2002 meta = marker.metadata().copy()
2003 meta = marker.metadata().copy()
2003 meta.pop('date', None)
2004 meta.pop('date', None)
2004 fm.write('metadata', '{%s}', fm.formatdict(meta, fmt='%r: %r', sep=', '))
2005 fm.write('metadata', '{%s}', fm.formatdict(meta, fmt='%r: %r', sep=', '))
2005 fm.plain('\n')
2006 fm.plain('\n')
2006
2007
2007 def finddate(ui, repo, date):
2008 def finddate(ui, repo, date):
2008 """Find the tipmost changeset that matches the given date spec"""
2009 """Find the tipmost changeset that matches the given date spec"""
2009
2010
2010 df = util.matchdate(date)
2011 df = util.matchdate(date)
2011 m = scmutil.matchall(repo)
2012 m = scmutil.matchall(repo)
2012 results = {}
2013 results = {}
2013
2014
2014 def prep(ctx, fns):
2015 def prep(ctx, fns):
2015 d = ctx.date()
2016 d = ctx.date()
2016 if df(d[0]):
2017 if df(d[0]):
2017 results[ctx.rev()] = d
2018 results[ctx.rev()] = d
2018
2019
2019 for ctx in walkchangerevs(repo, m, {'rev': None}, prep):
2020 for ctx in walkchangerevs(repo, m, {'rev': None}, prep):
2020 rev = ctx.rev()
2021 rev = ctx.rev()
2021 if rev in results:
2022 if rev in results:
2022 ui.status(_("found revision %s from %s\n") %
2023 ui.status(_("found revision %s from %s\n") %
2023 (rev, util.datestr(results[rev])))
2024 (rev, util.datestr(results[rev])))
2024 return '%d' % rev
2025 return '%d' % rev
2025
2026
2026 raise error.Abort(_("revision matching date not found"))
2027 raise error.Abort(_("revision matching date not found"))
2027
2028
2028 def increasingwindows(windowsize=8, sizelimit=512):
2029 def increasingwindows(windowsize=8, sizelimit=512):
2029 while True:
2030 while True:
2030 yield windowsize
2031 yield windowsize
2031 if windowsize < sizelimit:
2032 if windowsize < sizelimit:
2032 windowsize *= 2
2033 windowsize *= 2
2033
2034
2034 class FileWalkError(Exception):
2035 class FileWalkError(Exception):
2035 pass
2036 pass
2036
2037
2037 def walkfilerevs(repo, match, follow, revs, fncache):
2038 def walkfilerevs(repo, match, follow, revs, fncache):
2038 '''Walks the file history for the matched files.
2039 '''Walks the file history for the matched files.
2039
2040
2040 Returns the changeset revs that are involved in the file history.
2041 Returns the changeset revs that are involved in the file history.
2041
2042
2042 Throws FileWalkError if the file history can't be walked using
2043 Throws FileWalkError if the file history can't be walked using
2043 filelogs alone.
2044 filelogs alone.
2044 '''
2045 '''
2045 wanted = set()
2046 wanted = set()
2046 copies = []
2047 copies = []
2047 minrev, maxrev = min(revs), max(revs)
2048 minrev, maxrev = min(revs), max(revs)
2048 def filerevgen(filelog, last):
2049 def filerevgen(filelog, last):
2049 """
2050 """
2050 Only files, no patterns. Check the history of each file.
2051 Only files, no patterns. Check the history of each file.
2051
2052
2052 Examines filelog entries within minrev, maxrev linkrev range
2053 Examines filelog entries within minrev, maxrev linkrev range
2053 Returns an iterator yielding (linkrev, parentlinkrevs, copied)
2054 Returns an iterator yielding (linkrev, parentlinkrevs, copied)
2054 tuples in backwards order
2055 tuples in backwards order
2055 """
2056 """
2056 cl_count = len(repo)
2057 cl_count = len(repo)
2057 revs = []
2058 revs = []
2058 for j in xrange(0, last + 1):
2059 for j in xrange(0, last + 1):
2059 linkrev = filelog.linkrev(j)
2060 linkrev = filelog.linkrev(j)
2060 if linkrev < minrev:
2061 if linkrev < minrev:
2061 continue
2062 continue
2062 # only yield rev for which we have the changelog, it can
2063 # only yield rev for which we have the changelog, it can
2063 # happen while doing "hg log" during a pull or commit
2064 # happen while doing "hg log" during a pull or commit
2064 if linkrev >= cl_count:
2065 if linkrev >= cl_count:
2065 break
2066 break
2066
2067
2067 parentlinkrevs = []
2068 parentlinkrevs = []
2068 for p in filelog.parentrevs(j):
2069 for p in filelog.parentrevs(j):
2069 if p != nullrev:
2070 if p != nullrev:
2070 parentlinkrevs.append(filelog.linkrev(p))
2071 parentlinkrevs.append(filelog.linkrev(p))
2071 n = filelog.node(j)
2072 n = filelog.node(j)
2072 revs.append((linkrev, parentlinkrevs,
2073 revs.append((linkrev, parentlinkrevs,
2073 follow and filelog.renamed(n)))
2074 follow and filelog.renamed(n)))
2074
2075
2075 return reversed(revs)
2076 return reversed(revs)
2076 def iterfiles():
2077 def iterfiles():
2077 pctx = repo['.']
2078 pctx = repo['.']
2078 for filename in match.files():
2079 for filename in match.files():
2079 if follow:
2080 if follow:
2080 if filename not in pctx:
2081 if filename not in pctx:
2081 raise error.Abort(_('cannot follow file not in parent '
2082 raise error.Abort(_('cannot follow file not in parent '
2082 'revision: "%s"') % filename)
2083 'revision: "%s"') % filename)
2083 yield filename, pctx[filename].filenode()
2084 yield filename, pctx[filename].filenode()
2084 else:
2085 else:
2085 yield filename, None
2086 yield filename, None
2086 for filename_node in copies:
2087 for filename_node in copies:
2087 yield filename_node
2088 yield filename_node
2088
2089
2089 for file_, node in iterfiles():
2090 for file_, node in iterfiles():
2090 filelog = repo.file(file_)
2091 filelog = repo.file(file_)
2091 if not len(filelog):
2092 if not len(filelog):
2092 if node is None:
2093 if node is None:
2093 # A zero count may be a directory or deleted file, so
2094 # A zero count may be a directory or deleted file, so
2094 # try to find matching entries on the slow path.
2095 # try to find matching entries on the slow path.
2095 if follow:
2096 if follow:
2096 raise error.Abort(
2097 raise error.Abort(
2097 _('cannot follow nonexistent file: "%s"') % file_)
2098 _('cannot follow nonexistent file: "%s"') % file_)
2098 raise FileWalkError("Cannot walk via filelog")
2099 raise FileWalkError("Cannot walk via filelog")
2099 else:
2100 else:
2100 continue
2101 continue
2101
2102
2102 if node is None:
2103 if node is None:
2103 last = len(filelog) - 1
2104 last = len(filelog) - 1
2104 else:
2105 else:
2105 last = filelog.rev(node)
2106 last = filelog.rev(node)
2106
2107
2107 # keep track of all ancestors of the file
2108 # keep track of all ancestors of the file
2108 ancestors = {filelog.linkrev(last)}
2109 ancestors = {filelog.linkrev(last)}
2109
2110
2110 # iterate from latest to oldest revision
2111 # iterate from latest to oldest revision
2111 for rev, flparentlinkrevs, copied in filerevgen(filelog, last):
2112 for rev, flparentlinkrevs, copied in filerevgen(filelog, last):
2112 if not follow:
2113 if not follow:
2113 if rev > maxrev:
2114 if rev > maxrev:
2114 continue
2115 continue
2115 else:
2116 else:
2116 # Note that last might not be the first interesting
2117 # Note that last might not be the first interesting
2117 # rev to us:
2118 # rev to us:
2118 # if the file has been changed after maxrev, we'll
2119 # if the file has been changed after maxrev, we'll
2119 # have linkrev(last) > maxrev, and we still need
2120 # have linkrev(last) > maxrev, and we still need
2120 # to explore the file graph
2121 # to explore the file graph
2121 if rev not in ancestors:
2122 if rev not in ancestors:
2122 continue
2123 continue
2123 # XXX insert 1327 fix here
2124 # XXX insert 1327 fix here
2124 if flparentlinkrevs:
2125 if flparentlinkrevs:
2125 ancestors.update(flparentlinkrevs)
2126 ancestors.update(flparentlinkrevs)
2126
2127
2127 fncache.setdefault(rev, []).append(file_)
2128 fncache.setdefault(rev, []).append(file_)
2128 wanted.add(rev)
2129 wanted.add(rev)
2129 if copied:
2130 if copied:
2130 copies.append(copied)
2131 copies.append(copied)
2131
2132
2132 return wanted
2133 return wanted
2133
2134
2134 class _followfilter(object):
2135 class _followfilter(object):
2135 def __init__(self, repo, onlyfirst=False):
2136 def __init__(self, repo, onlyfirst=False):
2136 self.repo = repo
2137 self.repo = repo
2137 self.startrev = nullrev
2138 self.startrev = nullrev
2138 self.roots = set()
2139 self.roots = set()
2139 self.onlyfirst = onlyfirst
2140 self.onlyfirst = onlyfirst
2140
2141
2141 def match(self, rev):
2142 def match(self, rev):
2142 def realparents(rev):
2143 def realparents(rev):
2143 if self.onlyfirst:
2144 if self.onlyfirst:
2144 return self.repo.changelog.parentrevs(rev)[0:1]
2145 return self.repo.changelog.parentrevs(rev)[0:1]
2145 else:
2146 else:
2146 return filter(lambda x: x != nullrev,
2147 return filter(lambda x: x != nullrev,
2147 self.repo.changelog.parentrevs(rev))
2148 self.repo.changelog.parentrevs(rev))
2148
2149
2149 if self.startrev == nullrev:
2150 if self.startrev == nullrev:
2150 self.startrev = rev
2151 self.startrev = rev
2151 return True
2152 return True
2152
2153
2153 if rev > self.startrev:
2154 if rev > self.startrev:
2154 # forward: all descendants
2155 # forward: all descendants
2155 if not self.roots:
2156 if not self.roots:
2156 self.roots.add(self.startrev)
2157 self.roots.add(self.startrev)
2157 for parent in realparents(rev):
2158 for parent in realparents(rev):
2158 if parent in self.roots:
2159 if parent in self.roots:
2159 self.roots.add(rev)
2160 self.roots.add(rev)
2160 return True
2161 return True
2161 else:
2162 else:
2162 # backwards: all parents
2163 # backwards: all parents
2163 if not self.roots:
2164 if not self.roots:
2164 self.roots.update(realparents(self.startrev))
2165 self.roots.update(realparents(self.startrev))
2165 if rev in self.roots:
2166 if rev in self.roots:
2166 self.roots.remove(rev)
2167 self.roots.remove(rev)
2167 self.roots.update(realparents(rev))
2168 self.roots.update(realparents(rev))
2168 return True
2169 return True
2169
2170
2170 return False
2171 return False
2171
2172
2172 def walkchangerevs(repo, match, opts, prepare):
2173 def walkchangerevs(repo, match, opts, prepare):
2173 '''Iterate over files and the revs in which they changed.
2174 '''Iterate over files and the revs in which they changed.
2174
2175
2175 Callers most commonly need to iterate backwards over the history
2176 Callers most commonly need to iterate backwards over the history
2176 in which they are interested. Doing so has awful (quadratic-looking)
2177 in which they are interested. Doing so has awful (quadratic-looking)
2177 performance, so we use iterators in a "windowed" way.
2178 performance, so we use iterators in a "windowed" way.
2178
2179
2179 We walk a window of revisions in the desired order. Within the
2180 We walk a window of revisions in the desired order. Within the
2180 window, we first walk forwards to gather data, then in the desired
2181 window, we first walk forwards to gather data, then in the desired
2181 order (usually backwards) to display it.
2182 order (usually backwards) to display it.
2182
2183
2183 This function returns an iterator yielding contexts. Before
2184 This function returns an iterator yielding contexts. Before
2184 yielding each context, the iterator will first call the prepare
2185 yielding each context, the iterator will first call the prepare
2185 function on each context in the window in forward order.'''
2186 function on each context in the window in forward order.'''
2186
2187
2187 follow = opts.get('follow') or opts.get('follow_first')
2188 follow = opts.get('follow') or opts.get('follow_first')
2188 revs = _logrevs(repo, opts)
2189 revs = _logrevs(repo, opts)
2189 if not revs:
2190 if not revs:
2190 return []
2191 return []
2191 wanted = set()
2192 wanted = set()
2192 slowpath = match.anypats() or (not match.always() and opts.get('removed'))
2193 slowpath = match.anypats() or (not match.always() and opts.get('removed'))
2193 fncache = {}
2194 fncache = {}
2194 change = repo.changectx
2195 change = repo.changectx
2195
2196
2196 # First step is to fill wanted, the set of revisions that we want to yield.
2197 # First step is to fill wanted, the set of revisions that we want to yield.
2197 # When it does not induce extra cost, we also fill fncache for revisions in
2198 # When it does not induce extra cost, we also fill fncache for revisions in
2198 # wanted: a cache of filenames that were changed (ctx.files()) and that
2199 # wanted: a cache of filenames that were changed (ctx.files()) and that
2199 # match the file filtering conditions.
2200 # match the file filtering conditions.
2200
2201
2201 if match.always():
2202 if match.always():
2202 # No files, no patterns. Display all revs.
2203 # No files, no patterns. Display all revs.
2203 wanted = revs
2204 wanted = revs
2204 elif not slowpath:
2205 elif not slowpath:
2205 # We only have to read through the filelog to find wanted revisions
2206 # We only have to read through the filelog to find wanted revisions
2206
2207
2207 try:
2208 try:
2208 wanted = walkfilerevs(repo, match, follow, revs, fncache)
2209 wanted = walkfilerevs(repo, match, follow, revs, fncache)
2209 except FileWalkError:
2210 except FileWalkError:
2210 slowpath = True
2211 slowpath = True
2211
2212
2212 # We decided to fall back to the slowpath because at least one
2213 # We decided to fall back to the slowpath because at least one
2213 # of the paths was not a file. Check to see if at least one of them
2214 # of the paths was not a file. Check to see if at least one of them
2214 # existed in history, otherwise simply return
2215 # existed in history, otherwise simply return
2215 for path in match.files():
2216 for path in match.files():
2216 if path == '.' or path in repo.store:
2217 if path == '.' or path in repo.store:
2217 break
2218 break
2218 else:
2219 else:
2219 return []
2220 return []
2220
2221
2221 if slowpath:
2222 if slowpath:
2222 # We have to read the changelog to match filenames against
2223 # We have to read the changelog to match filenames against
2223 # changed files
2224 # changed files
2224
2225
2225 if follow:
2226 if follow:
2226 raise error.Abort(_('can only follow copies/renames for explicit '
2227 raise error.Abort(_('can only follow copies/renames for explicit '
2227 'filenames'))
2228 'filenames'))
2228
2229
2229 # The slow path checks files modified in every changeset.
2230 # The slow path checks files modified in every changeset.
2230 # This is really slow on large repos, so compute the set lazily.
2231 # This is really slow on large repos, so compute the set lazily.
2231 class lazywantedset(object):
2232 class lazywantedset(object):
2232 def __init__(self):
2233 def __init__(self):
2233 self.set = set()
2234 self.set = set()
2234 self.revs = set(revs)
2235 self.revs = set(revs)
2235
2236
2236 # No need to worry about locality here because it will be accessed
2237 # No need to worry about locality here because it will be accessed
2237 # in the same order as the increasing window below.
2238 # in the same order as the increasing window below.
2238 def __contains__(self, value):
2239 def __contains__(self, value):
2239 if value in self.set:
2240 if value in self.set:
2240 return True
2241 return True
2241 elif not value in self.revs:
2242 elif not value in self.revs:
2242 return False
2243 return False
2243 else:
2244 else:
2244 self.revs.discard(value)
2245 self.revs.discard(value)
2245 ctx = change(value)
2246 ctx = change(value)
2246 matches = filter(match, ctx.files())
2247 matches = filter(match, ctx.files())
2247 if matches:
2248 if matches:
2248 fncache[value] = matches
2249 fncache[value] = matches
2249 self.set.add(value)
2250 self.set.add(value)
2250 return True
2251 return True
2251 return False
2252 return False
2252
2253
2253 def discard(self, value):
2254 def discard(self, value):
2254 self.revs.discard(value)
2255 self.revs.discard(value)
2255 self.set.discard(value)
2256 self.set.discard(value)
2256
2257
2257 wanted = lazywantedset()
2258 wanted = lazywantedset()
2258
2259
2259 # it might be worthwhile to do this in the iterator if the rev range
2260 # it might be worthwhile to do this in the iterator if the rev range
2260 # is descending and the prune args are all within that range
2261 # is descending and the prune args are all within that range
2261 for rev in opts.get('prune', ()):
2262 for rev in opts.get('prune', ()):
2262 rev = repo[rev].rev()
2263 rev = repo[rev].rev()
2263 ff = _followfilter(repo)
2264 ff = _followfilter(repo)
2264 stop = min(revs[0], revs[-1])
2265 stop = min(revs[0], revs[-1])
2265 for x in xrange(rev, stop - 1, -1):
2266 for x in xrange(rev, stop - 1, -1):
2266 if ff.match(x):
2267 if ff.match(x):
2267 wanted = wanted - [x]
2268 wanted = wanted - [x]
2268
2269
2269 # Now that wanted is correctly initialized, we can iterate over the
2270 # Now that wanted is correctly initialized, we can iterate over the
2270 # revision range, yielding only revisions in wanted.
2271 # revision range, yielding only revisions in wanted.
2271 def iterate():
2272 def iterate():
2272 if follow and match.always():
2273 if follow and match.always():
2273 ff = _followfilter(repo, onlyfirst=opts.get('follow_first'))
2274 ff = _followfilter(repo, onlyfirst=opts.get('follow_first'))
2274 def want(rev):
2275 def want(rev):
2275 return ff.match(rev) and rev in wanted
2276 return ff.match(rev) and rev in wanted
2276 else:
2277 else:
2277 def want(rev):
2278 def want(rev):
2278 return rev in wanted
2279 return rev in wanted
2279
2280
2280 it = iter(revs)
2281 it = iter(revs)
2281 stopiteration = False
2282 stopiteration = False
2282 for windowsize in increasingwindows():
2283 for windowsize in increasingwindows():
2283 nrevs = []
2284 nrevs = []
2284 for i in xrange(windowsize):
2285 for i in xrange(windowsize):
2285 rev = next(it, None)
2286 rev = next(it, None)
2286 if rev is None:
2287 if rev is None:
2287 stopiteration = True
2288 stopiteration = True
2288 break
2289 break
2289 elif want(rev):
2290 elif want(rev):
2290 nrevs.append(rev)
2291 nrevs.append(rev)
2291 for rev in sorted(nrevs):
2292 for rev in sorted(nrevs):
2292 fns = fncache.get(rev)
2293 fns = fncache.get(rev)
2293 ctx = change(rev)
2294 ctx = change(rev)
2294 if not fns:
2295 if not fns:
2295 def fns_generator():
2296 def fns_generator():
2296 for f in ctx.files():
2297 for f in ctx.files():
2297 if match(f):
2298 if match(f):
2298 yield f
2299 yield f
2299 fns = fns_generator()
2300 fns = fns_generator()
2300 prepare(ctx, fns)
2301 prepare(ctx, fns)
2301 for rev in nrevs:
2302 for rev in nrevs:
2302 yield change(rev)
2303 yield change(rev)
2303
2304
2304 if stopiteration:
2305 if stopiteration:
2305 break
2306 break
2306
2307
2307 return iterate()
2308 return iterate()
2308
2309
2309 def _makefollowlogfilematcher(repo, files, followfirst):
2310 def _makefollowlogfilematcher(repo, files, followfirst):
2310 # When displaying a revision with --patch --follow FILE, we have
2311 # When displaying a revision with --patch --follow FILE, we have
2311 # to know which file of the revision must be diffed. With
2312 # to know which file of the revision must be diffed. With
2312 # --follow, we want the names of the ancestors of FILE in the
2313 # --follow, we want the names of the ancestors of FILE in the
2313 # revision, stored in "fcache". "fcache" is populated by
2314 # revision, stored in "fcache". "fcache" is populated by
2314 # reproducing the graph traversal already done by --follow revset
2315 # reproducing the graph traversal already done by --follow revset
2315 # and relating revs to file names (which is not "correct" but
2316 # and relating revs to file names (which is not "correct" but
2316 # good enough).
2317 # good enough).
2317 fcache = {}
2318 fcache = {}
2318 fcacheready = [False]
2319 fcacheready = [False]
2319 pctx = repo['.']
2320 pctx = repo['.']
2320
2321
2321 def populate():
2322 def populate():
2322 for fn in files:
2323 for fn in files:
2323 fctx = pctx[fn]
2324 fctx = pctx[fn]
2324 fcache.setdefault(fctx.introrev(), set()).add(fctx.path())
2325 fcache.setdefault(fctx.introrev(), set()).add(fctx.path())
2325 for c in fctx.ancestors(followfirst=followfirst):
2326 for c in fctx.ancestors(followfirst=followfirst):
2326 fcache.setdefault(c.rev(), set()).add(c.path())
2327 fcache.setdefault(c.rev(), set()).add(c.path())
2327
2328
2328 def filematcher(rev):
2329 def filematcher(rev):
2329 if not fcacheready[0]:
2330 if not fcacheready[0]:
2330 # Lazy initialization
2331 # Lazy initialization
2331 fcacheready[0] = True
2332 fcacheready[0] = True
2332 populate()
2333 populate()
2333 return scmutil.matchfiles(repo, fcache.get(rev, []))
2334 return scmutil.matchfiles(repo, fcache.get(rev, []))
2334
2335
2335 return filematcher
2336 return filematcher
2336
2337
2337 def _makenofollowlogfilematcher(repo, pats, opts):
2338 def _makenofollowlogfilematcher(repo, pats, opts):
2338 '''hook for extensions to override the filematcher for non-follow cases'''
2339 '''hook for extensions to override the filematcher for non-follow cases'''
2339 return None
2340 return None
2340
2341
2341 _opt2logrevset = {
2342 _opt2logrevset = {
2342 'no_merges': ('not merge()', None),
2343 'no_merges': ('not merge()', None),
2343 'only_merges': ('merge()', None),
2344 'only_merges': ('merge()', None),
2344 '_ancestors': ('ancestors(%(val)s)', None),
2345 '_ancestors': ('ancestors(%(val)s)', None),
2345 '_fancestors': ('_firstancestors(%(val)s)', None),
2346 '_fancestors': ('_firstancestors(%(val)s)', None),
2346 '_descendants': ('descendants(%(val)s)', None),
2347 '_descendants': ('descendants(%(val)s)', None),
2347 '_fdescendants': ('_firstdescendants(%(val)s)', None),
2348 '_fdescendants': ('_firstdescendants(%(val)s)', None),
2348 '_matchfiles': ('_matchfiles(%(val)s)', None),
2349 '_matchfiles': ('_matchfiles(%(val)s)', None),
2349 'date': ('date(%(val)r)', None),
2350 'date': ('date(%(val)r)', None),
2350 'branch': ('branch(%(val)r)', ' or '),
2351 'branch': ('branch(%(val)r)', '%lr'),
2351 '_patslog': ('filelog(%(val)r)', ' or '),
2352 '_patslog': ('filelog(%(val)r)', '%lr'),
2352 '_patsfollow': ('follow(%(val)r)', ' or '),
2353 '_patsfollow': ('follow(%(val)r)', '%lr'),
2353 '_patsfollowfirst': ('_followfirst(%(val)r)', ' or '),
2354 '_patsfollowfirst': ('_followfirst(%(val)r)', '%lr'),
2354 'keyword': ('keyword(%(val)r)', ' or '),
2355 'keyword': ('keyword(%(val)r)', '%lr'),
2355 'prune': ('not ancestors(%(val)r)', ' and '),
2356 'prune': ('ancestors(%(val)r)', 'not %lr'),
2356 'user': ('user(%(val)r)', ' or '),
2357 'user': ('user(%(val)r)', '%lr'),
2357 }
2358 }
2358
2359
2359 def _makelogrevset(repo, pats, opts, revs):
2360 def _makelogrevset(repo, pats, opts, revs):
2360 """Return (expr, filematcher) where expr is a revset string built
2361 """Return (expr, filematcher) where expr is a revset string built
2361 from log options and file patterns or None. If --stat or --patch
2362 from log options and file patterns or None. If --stat or --patch
2362 are not passed filematcher is None. Otherwise it is a callable
2363 are not passed filematcher is None. Otherwise it is a callable
2363 taking a revision number and returning a match objects filtering
2364 taking a revision number and returning a match objects filtering
2364 the files to be detailed when displaying the revision.
2365 the files to be detailed when displaying the revision.
2365 """
2366 """
2366 opts = dict(opts)
2367 opts = dict(opts)
2367 # follow or not follow?
2368 # follow or not follow?
2368 follow = opts.get('follow') or opts.get('follow_first')
2369 follow = opts.get('follow') or opts.get('follow_first')
2369 if opts.get('follow_first'):
2370 if opts.get('follow_first'):
2370 followfirst = 1
2371 followfirst = 1
2371 else:
2372 else:
2372 followfirst = 0
2373 followfirst = 0
2373 # --follow with FILE behavior depends on revs...
2374 # --follow with FILE behavior depends on revs...
2374 it = iter(revs)
2375 it = iter(revs)
2375 startrev = next(it)
2376 startrev = next(it)
2376 followdescendants = startrev < next(it, startrev)
2377 followdescendants = startrev < next(it, startrev)
2377
2378
2378 # branch and only_branch are really aliases and must be handled at
2379 # branch and only_branch are really aliases and must be handled at
2379 # the same time
2380 # the same time
2380 opts['branch'] = opts.get('branch', []) + opts.get('only_branch', [])
2381 opts['branch'] = opts.get('branch', []) + opts.get('only_branch', [])
2381 opts['branch'] = [repo.lookupbranch(b) for b in opts['branch']]
2382 opts['branch'] = [repo.lookupbranch(b) for b in opts['branch']]
2382 # pats/include/exclude are passed to match.match() directly in
2383 # pats/include/exclude are passed to match.match() directly in
2383 # _matchfiles() revset but walkchangerevs() builds its matcher with
2384 # _matchfiles() revset but walkchangerevs() builds its matcher with
2384 # scmutil.match(). The difference is input pats are globbed on
2385 # scmutil.match(). The difference is input pats are globbed on
2385 # platforms without shell expansion (windows).
2386 # platforms without shell expansion (windows).
2386 wctx = repo[None]
2387 wctx = repo[None]
2387 match, pats = scmutil.matchandpats(wctx, pats, opts)
2388 match, pats = scmutil.matchandpats(wctx, pats, opts)
2388 slowpath = match.anypats() or (not match.always() and opts.get('removed'))
2389 slowpath = match.anypats() or (not match.always() and opts.get('removed'))
2389 if not slowpath:
2390 if not slowpath:
2390 for f in match.files():
2391 for f in match.files():
2391 if follow and f not in wctx:
2392 if follow and f not in wctx:
2392 # If the file exists, it may be a directory, so let it
2393 # If the file exists, it may be a directory, so let it
2393 # take the slow path.
2394 # take the slow path.
2394 if os.path.exists(repo.wjoin(f)):
2395 if os.path.exists(repo.wjoin(f)):
2395 slowpath = True
2396 slowpath = True
2396 continue
2397 continue
2397 else:
2398 else:
2398 raise error.Abort(_('cannot follow file not in parent '
2399 raise error.Abort(_('cannot follow file not in parent '
2399 'revision: "%s"') % f)
2400 'revision: "%s"') % f)
2400 filelog = repo.file(f)
2401 filelog = repo.file(f)
2401 if not filelog:
2402 if not filelog:
2402 # A zero count may be a directory or deleted file, so
2403 # A zero count may be a directory or deleted file, so
2403 # try to find matching entries on the slow path.
2404 # try to find matching entries on the slow path.
2404 if follow:
2405 if follow:
2405 raise error.Abort(
2406 raise error.Abort(
2406 _('cannot follow nonexistent file: "%s"') % f)
2407 _('cannot follow nonexistent file: "%s"') % f)
2407 slowpath = True
2408 slowpath = True
2408
2409
2409 # We decided to fall back to the slowpath because at least one
2410 # We decided to fall back to the slowpath because at least one
2410 # of the paths was not a file. Check to see if at least one of them
2411 # of the paths was not a file. Check to see if at least one of them
2411 # existed in history - in that case, we'll continue down the
2412 # existed in history - in that case, we'll continue down the
2412 # slowpath; otherwise, we can turn off the slowpath
2413 # slowpath; otherwise, we can turn off the slowpath
2413 if slowpath:
2414 if slowpath:
2414 for path in match.files():
2415 for path in match.files():
2415 if path == '.' or path in repo.store:
2416 if path == '.' or path in repo.store:
2416 break
2417 break
2417 else:
2418 else:
2418 slowpath = False
2419 slowpath = False
2419
2420
2420 fpats = ('_patsfollow', '_patsfollowfirst')
2421 fpats = ('_patsfollow', '_patsfollowfirst')
2421 fnopats = (('_ancestors', '_fancestors'),
2422 fnopats = (('_ancestors', '_fancestors'),
2422 ('_descendants', '_fdescendants'))
2423 ('_descendants', '_fdescendants'))
2423 if slowpath:
2424 if slowpath:
2424 # See walkchangerevs() slow path.
2425 # See walkchangerevs() slow path.
2425 #
2426 #
2426 # pats/include/exclude cannot be represented as separate
2427 # pats/include/exclude cannot be represented as separate
2427 # revset expressions as their filtering logic applies at file
2428 # revset expressions as their filtering logic applies at file
2428 # level. For instance "-I a -X a" matches a revision touching
2429 # level. For instance "-I a -X a" matches a revision touching
2429 # "a" and "b" while "file(a) and not file(b)" does
2430 # "a" and "b" while "file(a) and not file(b)" does
2430 # not. Besides, filesets are evaluated against the working
2431 # not. Besides, filesets are evaluated against the working
2431 # directory.
2432 # directory.
2432 matchargs = ['r:', 'd:relpath']
2433 matchargs = ['r:', 'd:relpath']
2433 for p in pats:
2434 for p in pats:
2434 matchargs.append('p:' + p)
2435 matchargs.append('p:' + p)
2435 for p in opts.get('include', []):
2436 for p in opts.get('include', []):
2436 matchargs.append('i:' + p)
2437 matchargs.append('i:' + p)
2437 for p in opts.get('exclude', []):
2438 for p in opts.get('exclude', []):
2438 matchargs.append('x:' + p)
2439 matchargs.append('x:' + p)
2439 matchargs = ','.join(('%r' % p) for p in matchargs)
2440 matchargs = ','.join(('%r' % p) for p in matchargs)
2440 opts['_matchfiles'] = matchargs
2441 opts['_matchfiles'] = matchargs
2441 if follow:
2442 if follow:
2442 opts[fnopats[0][followfirst]] = '.'
2443 opts[fnopats[0][followfirst]] = '.'
2443 else:
2444 else:
2444 if follow:
2445 if follow:
2445 if pats:
2446 if pats:
2446 # follow() revset interprets its file argument as a
2447 # follow() revset interprets its file argument as a
2447 # manifest entry, so use match.files(), not pats.
2448 # manifest entry, so use match.files(), not pats.
2448 opts[fpats[followfirst]] = list(match.files())
2449 opts[fpats[followfirst]] = list(match.files())
2449 else:
2450 else:
2450 op = fnopats[followdescendants][followfirst]
2451 op = fnopats[followdescendants][followfirst]
2451 opts[op] = 'rev(%d)' % startrev
2452 opts[op] = 'rev(%d)' % startrev
2452 else:
2453 else:
2453 opts['_patslog'] = list(pats)
2454 opts['_patslog'] = list(pats)
2454
2455
2455 filematcher = None
2456 filematcher = None
2456 if opts.get('patch') or opts.get('stat'):
2457 if opts.get('patch') or opts.get('stat'):
2457 # When following files, track renames via a special matcher.
2458 # When following files, track renames via a special matcher.
2458 # If we're forced to take the slowpath it means we're following
2459 # If we're forced to take the slowpath it means we're following
2459 # at least one pattern/directory, so don't bother with rename tracking.
2460 # at least one pattern/directory, so don't bother with rename tracking.
2460 if follow and not match.always() and not slowpath:
2461 if follow and not match.always() and not slowpath:
2461 # _makefollowlogfilematcher expects its files argument to be
2462 # _makefollowlogfilematcher expects its files argument to be
2462 # relative to the repo root, so use match.files(), not pats.
2463 # relative to the repo root, so use match.files(), not pats.
2463 filematcher = _makefollowlogfilematcher(repo, match.files(),
2464 filematcher = _makefollowlogfilematcher(repo, match.files(),
2464 followfirst)
2465 followfirst)
2465 else:
2466 else:
2466 filematcher = _makenofollowlogfilematcher(repo, pats, opts)
2467 filematcher = _makenofollowlogfilematcher(repo, pats, opts)
2467 if filematcher is None:
2468 if filematcher is None:
2468 filematcher = lambda rev: match
2469 filematcher = lambda rev: match
2469
2470
2470 expr = []
2471 expr = []
2471 for op, val in sorted(opts.iteritems()):
2472 for op, val in sorted(opts.iteritems()):
2472 if not val:
2473 if not val:
2473 continue
2474 continue
2474 if op not in _opt2logrevset:
2475 if op not in _opt2logrevset:
2475 continue
2476 continue
2476 revop, andor = _opt2logrevset[op]
2477 revop, listop = _opt2logrevset[op]
2477 if '%(val)' not in revop:
2478 if '%(val)' not in revop:
2478 expr.append(revop)
2479 expr.append(revop)
2479 else:
2480 else:
2480 if not isinstance(val, list):
2481 if not listop:
2481 e = revop % {'val': val}
2482 e = revop % {'val': val}
2482 else:
2483 else:
2483 e = '(' + andor.join((revop % {'val': v}) for v in val) + ')'
2484 e = [revop % {'val': v} for v in val]
2485 e = revsetlang.formatspec(listop, e)
2484 expr.append(e)
2486 expr.append(e)
2485
2487
2486 if expr:
2488 if expr:
2487 expr = '(' + ' and '.join(expr) + ')'
2489 expr = '(' + ' and '.join(expr) + ')'
2488 else:
2490 else:
2489 expr = None
2491 expr = None
2490 return expr, filematcher
2492 return expr, filematcher
2491
2493
2492 def _logrevs(repo, opts):
2494 def _logrevs(repo, opts):
2493 # Default --rev value depends on --follow but --follow behavior
2495 # Default --rev value depends on --follow but --follow behavior
2494 # depends on revisions resolved from --rev...
2496 # depends on revisions resolved from --rev...
2495 follow = opts.get('follow') or opts.get('follow_first')
2497 follow = opts.get('follow') or opts.get('follow_first')
2496 if opts.get('rev'):
2498 if opts.get('rev'):
2497 revs = scmutil.revrange(repo, opts['rev'])
2499 revs = scmutil.revrange(repo, opts['rev'])
2498 elif follow and repo.dirstate.p1() == nullid:
2500 elif follow and repo.dirstate.p1() == nullid:
2499 revs = smartset.baseset()
2501 revs = smartset.baseset()
2500 elif follow:
2502 elif follow:
2501 revs = repo.revs('reverse(:.)')
2503 revs = repo.revs('reverse(:.)')
2502 else:
2504 else:
2503 revs = smartset.spanset(repo)
2505 revs = smartset.spanset(repo)
2504 revs.reverse()
2506 revs.reverse()
2505 return revs
2507 return revs
2506
2508
2507 def getlogrevs(repo, pats, opts):
2509 def getlogrevs(repo, pats, opts):
2508 """Return (revs, filematcher) where revs is a smartset
2510 """Return (revs, filematcher) where revs is a smartset
2509
2511
2510 If --stat or --patch is not passed, filematcher is None. Otherwise it
2512 If --stat or --patch is not passed, filematcher is None. Otherwise it
2511 is a callable taking a revision number and returning a match objects
2513 is a callable taking a revision number and returning a match objects
2512 filtering the files to be detailed when displaying the revision.
2514 filtering the files to be detailed when displaying the revision.
2513 """
2515 """
2514 limit = loglimit(opts)
2516 limit = loglimit(opts)
2515 revs = _logrevs(repo, opts)
2517 revs = _logrevs(repo, opts)
2516 if not revs:
2518 if not revs:
2517 return smartset.baseset(), None
2519 return smartset.baseset(), None
2518 expr, filematcher = _makelogrevset(repo, pats, opts, revs)
2520 expr, filematcher = _makelogrevset(repo, pats, opts, revs)
2519 if opts.get('graph') and opts.get('rev'):
2521 if opts.get('graph') and opts.get('rev'):
2520 # User-specified revs might be unsorted, but don't sort before
2522 # User-specified revs might be unsorted, but don't sort before
2521 # _makelogrevset because it might depend on the order of revs
2523 # _makelogrevset because it might depend on the order of revs
2522 if not (revs.isdescending() or revs.istopo()):
2524 if not (revs.isdescending() or revs.istopo()):
2523 revs.sort(reverse=True)
2525 revs.sort(reverse=True)
2524 if expr:
2526 if expr:
2525 matcher = revset.match(None, expr)
2527 matcher = revset.match(None, expr)
2526 revs = matcher(repo, revs)
2528 revs = matcher(repo, revs)
2527 if limit is not None:
2529 if limit is not None:
2528 revs = revs.slice(0, limit)
2530 revs = revs.slice(0, limit)
2529 return revs, filematcher
2531 return revs, filematcher
2530
2532
2531 def _parselinerangelogopt(repo, opts):
2533 def _parselinerangelogopt(repo, opts):
2532 """Parse --line-range log option and return a list of tuples (filename,
2534 """Parse --line-range log option and return a list of tuples (filename,
2533 (fromline, toline)).
2535 (fromline, toline)).
2534 """
2536 """
2535 linerangebyfname = []
2537 linerangebyfname = []
2536 for pat in opts.get('line_range', []):
2538 for pat in opts.get('line_range', []):
2537 try:
2539 try:
2538 pat, linerange = pat.rsplit(',', 1)
2540 pat, linerange = pat.rsplit(',', 1)
2539 except ValueError:
2541 except ValueError:
2540 raise error.Abort(_('malformatted line-range pattern %s') % pat)
2542 raise error.Abort(_('malformatted line-range pattern %s') % pat)
2541 try:
2543 try:
2542 fromline, toline = map(int, linerange.split(':'))
2544 fromline, toline = map(int, linerange.split(':'))
2543 except ValueError:
2545 except ValueError:
2544 raise error.Abort(_("invalid line range for %s") % pat)
2546 raise error.Abort(_("invalid line range for %s") % pat)
2545 msg = _("line range pattern '%s' must match exactly one file") % pat
2547 msg = _("line range pattern '%s' must match exactly one file") % pat
2546 fname = scmutil.parsefollowlinespattern(repo, None, pat, msg)
2548 fname = scmutil.parsefollowlinespattern(repo, None, pat, msg)
2547 linerangebyfname.append(
2549 linerangebyfname.append(
2548 (fname, util.processlinerange(fromline, toline)))
2550 (fname, util.processlinerange(fromline, toline)))
2549 return linerangebyfname
2551 return linerangebyfname
2550
2552
2551 def getloglinerangerevs(repo, userrevs, opts):
2553 def getloglinerangerevs(repo, userrevs, opts):
2552 """Return (revs, filematcher, hunksfilter).
2554 """Return (revs, filematcher, hunksfilter).
2553
2555
2554 "revs" are revisions obtained by processing "line-range" log options and
2556 "revs" are revisions obtained by processing "line-range" log options and
2555 walking block ancestors of each specified file/line-range.
2557 walking block ancestors of each specified file/line-range.
2556
2558
2557 "filematcher(rev) -> match" is a factory function returning a match object
2559 "filematcher(rev) -> match" is a factory function returning a match object
2558 for a given revision for file patterns specified in --line-range option.
2560 for a given revision for file patterns specified in --line-range option.
2559 If neither --stat nor --patch options are passed, "filematcher" is None.
2561 If neither --stat nor --patch options are passed, "filematcher" is None.
2560
2562
2561 "hunksfilter(rev) -> filterfn(fctx, hunks)" is a factory function
2563 "hunksfilter(rev) -> filterfn(fctx, hunks)" is a factory function
2562 returning a hunks filtering function.
2564 returning a hunks filtering function.
2563 If neither --stat nor --patch options are passed, "filterhunks" is None.
2565 If neither --stat nor --patch options are passed, "filterhunks" is None.
2564 """
2566 """
2565 wctx = repo[None]
2567 wctx = repo[None]
2566
2568
2567 # Two-levels map of "rev -> file ctx -> [line range]".
2569 # Two-levels map of "rev -> file ctx -> [line range]".
2568 linerangesbyrev = {}
2570 linerangesbyrev = {}
2569 for fname, (fromline, toline) in _parselinerangelogopt(repo, opts):
2571 for fname, (fromline, toline) in _parselinerangelogopt(repo, opts):
2570 if fname not in wctx:
2572 if fname not in wctx:
2571 raise error.Abort(_('cannot follow file not in parent '
2573 raise error.Abort(_('cannot follow file not in parent '
2572 'revision: "%s"') % fname)
2574 'revision: "%s"') % fname)
2573 fctx = wctx.filectx(fname)
2575 fctx = wctx.filectx(fname)
2574 for fctx, linerange in dagop.blockancestors(fctx, fromline, toline):
2576 for fctx, linerange in dagop.blockancestors(fctx, fromline, toline):
2575 rev = fctx.introrev()
2577 rev = fctx.introrev()
2576 if rev not in userrevs:
2578 if rev not in userrevs:
2577 continue
2579 continue
2578 linerangesbyrev.setdefault(
2580 linerangesbyrev.setdefault(
2579 rev, {}).setdefault(
2581 rev, {}).setdefault(
2580 fctx.path(), []).append(linerange)
2582 fctx.path(), []).append(linerange)
2581
2583
2582 filematcher = None
2584 filematcher = None
2583 hunksfilter = None
2585 hunksfilter = None
2584 if opts.get('patch') or opts.get('stat'):
2586 if opts.get('patch') or opts.get('stat'):
2585
2587
2586 def nofilterhunksfn(fctx, hunks):
2588 def nofilterhunksfn(fctx, hunks):
2587 return hunks
2589 return hunks
2588
2590
2589 def hunksfilter(rev):
2591 def hunksfilter(rev):
2590 fctxlineranges = linerangesbyrev.get(rev)
2592 fctxlineranges = linerangesbyrev.get(rev)
2591 if fctxlineranges is None:
2593 if fctxlineranges is None:
2592 return nofilterhunksfn
2594 return nofilterhunksfn
2593
2595
2594 def filterfn(fctx, hunks):
2596 def filterfn(fctx, hunks):
2595 lineranges = fctxlineranges.get(fctx.path())
2597 lineranges = fctxlineranges.get(fctx.path())
2596 if lineranges is not None:
2598 if lineranges is not None:
2597 for hr, lines in hunks:
2599 for hr, lines in hunks:
2598 if hr is None: # binary
2600 if hr is None: # binary
2599 yield hr, lines
2601 yield hr, lines
2600 continue
2602 continue
2601 if any(mdiff.hunkinrange(hr[2:], lr)
2603 if any(mdiff.hunkinrange(hr[2:], lr)
2602 for lr in lineranges):
2604 for lr in lineranges):
2603 yield hr, lines
2605 yield hr, lines
2604 else:
2606 else:
2605 for hunk in hunks:
2607 for hunk in hunks:
2606 yield hunk
2608 yield hunk
2607
2609
2608 return filterfn
2610 return filterfn
2609
2611
2610 def filematcher(rev):
2612 def filematcher(rev):
2611 files = list(linerangesbyrev.get(rev, []))
2613 files = list(linerangesbyrev.get(rev, []))
2612 return scmutil.matchfiles(repo, files)
2614 return scmutil.matchfiles(repo, files)
2613
2615
2614 revs = sorted(linerangesbyrev, reverse=True)
2616 revs = sorted(linerangesbyrev, reverse=True)
2615
2617
2616 return revs, filematcher, hunksfilter
2618 return revs, filematcher, hunksfilter
2617
2619
2618 def _graphnodeformatter(ui, displayer):
2620 def _graphnodeformatter(ui, displayer):
2619 spec = ui.config('ui', 'graphnodetemplate')
2621 spec = ui.config('ui', 'graphnodetemplate')
2620 if not spec:
2622 if not spec:
2621 return templatekw.showgraphnode # fast path for "{graphnode}"
2623 return templatekw.showgraphnode # fast path for "{graphnode}"
2622
2624
2623 spec = templater.unquotestring(spec)
2625 spec = templater.unquotestring(spec)
2624 tres = formatter.templateresources(ui)
2626 tres = formatter.templateresources(ui)
2625 if isinstance(displayer, changeset_templater):
2627 if isinstance(displayer, changeset_templater):
2626 tres['cache'] = displayer.cache # reuse cache of slow templates
2628 tres['cache'] = displayer.cache # reuse cache of slow templates
2627 templ = formatter.maketemplater(ui, spec, defaults=templatekw.keywords,
2629 templ = formatter.maketemplater(ui, spec, defaults=templatekw.keywords,
2628 resources=tres)
2630 resources=tres)
2629 def formatnode(repo, ctx):
2631 def formatnode(repo, ctx):
2630 props = {'ctx': ctx, 'repo': repo, 'revcache': {}}
2632 props = {'ctx': ctx, 'repo': repo, 'revcache': {}}
2631 return templ.render(props)
2633 return templ.render(props)
2632 return formatnode
2634 return formatnode
2633
2635
2634 def displaygraph(ui, repo, dag, displayer, edgefn, getrenamed=None,
2636 def displaygraph(ui, repo, dag, displayer, edgefn, getrenamed=None,
2635 filematcher=None, props=None):
2637 filematcher=None, props=None):
2636 props = props or {}
2638 props = props or {}
2637 formatnode = _graphnodeformatter(ui, displayer)
2639 formatnode = _graphnodeformatter(ui, displayer)
2638 state = graphmod.asciistate()
2640 state = graphmod.asciistate()
2639 styles = state['styles']
2641 styles = state['styles']
2640
2642
2641 # only set graph styling if HGPLAIN is not set.
2643 # only set graph styling if HGPLAIN is not set.
2642 if ui.plain('graph'):
2644 if ui.plain('graph'):
2643 # set all edge styles to |, the default pre-3.8 behaviour
2645 # set all edge styles to |, the default pre-3.8 behaviour
2644 styles.update(dict.fromkeys(styles, '|'))
2646 styles.update(dict.fromkeys(styles, '|'))
2645 else:
2647 else:
2646 edgetypes = {
2648 edgetypes = {
2647 'parent': graphmod.PARENT,
2649 'parent': graphmod.PARENT,
2648 'grandparent': graphmod.GRANDPARENT,
2650 'grandparent': graphmod.GRANDPARENT,
2649 'missing': graphmod.MISSINGPARENT
2651 'missing': graphmod.MISSINGPARENT
2650 }
2652 }
2651 for name, key in edgetypes.items():
2653 for name, key in edgetypes.items():
2652 # experimental config: experimental.graphstyle.*
2654 # experimental config: experimental.graphstyle.*
2653 styles[key] = ui.config('experimental', 'graphstyle.%s' % name,
2655 styles[key] = ui.config('experimental', 'graphstyle.%s' % name,
2654 styles[key])
2656 styles[key])
2655 if not styles[key]:
2657 if not styles[key]:
2656 styles[key] = None
2658 styles[key] = None
2657
2659
2658 # experimental config: experimental.graphshorten
2660 # experimental config: experimental.graphshorten
2659 state['graphshorten'] = ui.configbool('experimental', 'graphshorten')
2661 state['graphshorten'] = ui.configbool('experimental', 'graphshorten')
2660
2662
2661 for rev, type, ctx, parents in dag:
2663 for rev, type, ctx, parents in dag:
2662 char = formatnode(repo, ctx)
2664 char = formatnode(repo, ctx)
2663 copies = None
2665 copies = None
2664 if getrenamed and ctx.rev():
2666 if getrenamed and ctx.rev():
2665 copies = []
2667 copies = []
2666 for fn in ctx.files():
2668 for fn in ctx.files():
2667 rename = getrenamed(fn, ctx.rev())
2669 rename = getrenamed(fn, ctx.rev())
2668 if rename:
2670 if rename:
2669 copies.append((fn, rename[0]))
2671 copies.append((fn, rename[0]))
2670 revmatchfn = None
2672 revmatchfn = None
2671 if filematcher is not None:
2673 if filematcher is not None:
2672 revmatchfn = filematcher(ctx.rev())
2674 revmatchfn = filematcher(ctx.rev())
2673 edges = edgefn(type, char, state, rev, parents)
2675 edges = edgefn(type, char, state, rev, parents)
2674 firstedge = next(edges)
2676 firstedge = next(edges)
2675 width = firstedge[2]
2677 width = firstedge[2]
2676 displayer.show(ctx, copies=copies, matchfn=revmatchfn,
2678 displayer.show(ctx, copies=copies, matchfn=revmatchfn,
2677 _graphwidth=width, **pycompat.strkwargs(props))
2679 _graphwidth=width, **pycompat.strkwargs(props))
2678 lines = displayer.hunk.pop(rev).split('\n')
2680 lines = displayer.hunk.pop(rev).split('\n')
2679 if not lines[-1]:
2681 if not lines[-1]:
2680 del lines[-1]
2682 del lines[-1]
2681 displayer.flush(ctx)
2683 displayer.flush(ctx)
2682 for type, char, width, coldata in itertools.chain([firstedge], edges):
2684 for type, char, width, coldata in itertools.chain([firstedge], edges):
2683 graphmod.ascii(ui, state, type, char, lines, coldata)
2685 graphmod.ascii(ui, state, type, char, lines, coldata)
2684 lines = []
2686 lines = []
2685 displayer.close()
2687 displayer.close()
2686
2688
2687 def graphlog(ui, repo, revs, filematcher, opts):
2689 def graphlog(ui, repo, revs, filematcher, opts):
2688 # Parameters are identical to log command ones
2690 # Parameters are identical to log command ones
2689 revdag = graphmod.dagwalker(repo, revs)
2691 revdag = graphmod.dagwalker(repo, revs)
2690
2692
2691 getrenamed = None
2693 getrenamed = None
2692 if opts.get('copies'):
2694 if opts.get('copies'):
2693 endrev = None
2695 endrev = None
2694 if opts.get('rev'):
2696 if opts.get('rev'):
2695 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
2697 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
2696 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
2698 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
2697
2699
2698 ui.pager('log')
2700 ui.pager('log')
2699 displayer = show_changeset(ui, repo, opts, buffered=True)
2701 displayer = show_changeset(ui, repo, opts, buffered=True)
2700 displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges, getrenamed,
2702 displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges, getrenamed,
2701 filematcher)
2703 filematcher)
2702
2704
2703 def checkunsupportedgraphflags(pats, opts):
2705 def checkunsupportedgraphflags(pats, opts):
2704 for op in ["newest_first"]:
2706 for op in ["newest_first"]:
2705 if op in opts and opts[op]:
2707 if op in opts and opts[op]:
2706 raise error.Abort(_("-G/--graph option is incompatible with --%s")
2708 raise error.Abort(_("-G/--graph option is incompatible with --%s")
2707 % op.replace("_", "-"))
2709 % op.replace("_", "-"))
2708
2710
2709 def graphrevs(repo, nodes, opts):
2711 def graphrevs(repo, nodes, opts):
2710 limit = loglimit(opts)
2712 limit = loglimit(opts)
2711 nodes.reverse()
2713 nodes.reverse()
2712 if limit is not None:
2714 if limit is not None:
2713 nodes = nodes[:limit]
2715 nodes = nodes[:limit]
2714 return graphmod.nodes(repo, nodes)
2716 return graphmod.nodes(repo, nodes)
2715
2717
2716 def add(ui, repo, match, prefix, explicitonly, **opts):
2718 def add(ui, repo, match, prefix, explicitonly, **opts):
2717 join = lambda f: os.path.join(prefix, f)
2719 join = lambda f: os.path.join(prefix, f)
2718 bad = []
2720 bad = []
2719
2721
2720 badfn = lambda x, y: bad.append(x) or match.bad(x, y)
2722 badfn = lambda x, y: bad.append(x) or match.bad(x, y)
2721 names = []
2723 names = []
2722 wctx = repo[None]
2724 wctx = repo[None]
2723 cca = None
2725 cca = None
2724 abort, warn = scmutil.checkportabilityalert(ui)
2726 abort, warn = scmutil.checkportabilityalert(ui)
2725 if abort or warn:
2727 if abort or warn:
2726 cca = scmutil.casecollisionauditor(ui, abort, repo.dirstate)
2728 cca = scmutil.casecollisionauditor(ui, abort, repo.dirstate)
2727
2729
2728 badmatch = matchmod.badmatch(match, badfn)
2730 badmatch = matchmod.badmatch(match, badfn)
2729 dirstate = repo.dirstate
2731 dirstate = repo.dirstate
2730 # We don't want to just call wctx.walk here, since it would return a lot of
2732 # We don't want to just call wctx.walk here, since it would return a lot of
2731 # clean files, which we aren't interested in and takes time.
2733 # clean files, which we aren't interested in and takes time.
2732 for f in sorted(dirstate.walk(badmatch, subrepos=sorted(wctx.substate),
2734 for f in sorted(dirstate.walk(badmatch, subrepos=sorted(wctx.substate),
2733 unknown=True, ignored=False, full=False)):
2735 unknown=True, ignored=False, full=False)):
2734 exact = match.exact(f)
2736 exact = match.exact(f)
2735 if exact or not explicitonly and f not in wctx and repo.wvfs.lexists(f):
2737 if exact or not explicitonly and f not in wctx and repo.wvfs.lexists(f):
2736 if cca:
2738 if cca:
2737 cca(f)
2739 cca(f)
2738 names.append(f)
2740 names.append(f)
2739 if ui.verbose or not exact:
2741 if ui.verbose or not exact:
2740 ui.status(_('adding %s\n') % match.rel(f))
2742 ui.status(_('adding %s\n') % match.rel(f))
2741
2743
2742 for subpath in sorted(wctx.substate):
2744 for subpath in sorted(wctx.substate):
2743 sub = wctx.sub(subpath)
2745 sub = wctx.sub(subpath)
2744 try:
2746 try:
2745 submatch = matchmod.subdirmatcher(subpath, match)
2747 submatch = matchmod.subdirmatcher(subpath, match)
2746 if opts.get(r'subrepos'):
2748 if opts.get(r'subrepos'):
2747 bad.extend(sub.add(ui, submatch, prefix, False, **opts))
2749 bad.extend(sub.add(ui, submatch, prefix, False, **opts))
2748 else:
2750 else:
2749 bad.extend(sub.add(ui, submatch, prefix, True, **opts))
2751 bad.extend(sub.add(ui, submatch, prefix, True, **opts))
2750 except error.LookupError:
2752 except error.LookupError:
2751 ui.status(_("skipping missing subrepository: %s\n")
2753 ui.status(_("skipping missing subrepository: %s\n")
2752 % join(subpath))
2754 % join(subpath))
2753
2755
2754 if not opts.get(r'dry_run'):
2756 if not opts.get(r'dry_run'):
2755 rejected = wctx.add(names, prefix)
2757 rejected = wctx.add(names, prefix)
2756 bad.extend(f for f in rejected if f in match.files())
2758 bad.extend(f for f in rejected if f in match.files())
2757 return bad
2759 return bad
2758
2760
2759 def addwebdirpath(repo, serverpath, webconf):
2761 def addwebdirpath(repo, serverpath, webconf):
2760 webconf[serverpath] = repo.root
2762 webconf[serverpath] = repo.root
2761 repo.ui.debug('adding %s = %s\n' % (serverpath, repo.root))
2763 repo.ui.debug('adding %s = %s\n' % (serverpath, repo.root))
2762
2764
2763 for r in repo.revs('filelog("path:.hgsub")'):
2765 for r in repo.revs('filelog("path:.hgsub")'):
2764 ctx = repo[r]
2766 ctx = repo[r]
2765 for subpath in ctx.substate:
2767 for subpath in ctx.substate:
2766 ctx.sub(subpath).addwebdirpath(serverpath, webconf)
2768 ctx.sub(subpath).addwebdirpath(serverpath, webconf)
2767
2769
2768 def forget(ui, repo, match, prefix, explicitonly):
2770 def forget(ui, repo, match, prefix, explicitonly):
2769 join = lambda f: os.path.join(prefix, f)
2771 join = lambda f: os.path.join(prefix, f)
2770 bad = []
2772 bad = []
2771 badfn = lambda x, y: bad.append(x) or match.bad(x, y)
2773 badfn = lambda x, y: bad.append(x) or match.bad(x, y)
2772 wctx = repo[None]
2774 wctx = repo[None]
2773 forgot = []
2775 forgot = []
2774
2776
2775 s = repo.status(match=matchmod.badmatch(match, badfn), clean=True)
2777 s = repo.status(match=matchmod.badmatch(match, badfn), clean=True)
2776 forget = sorted(s.modified + s.added + s.deleted + s.clean)
2778 forget = sorted(s.modified + s.added + s.deleted + s.clean)
2777 if explicitonly:
2779 if explicitonly:
2778 forget = [f for f in forget if match.exact(f)]
2780 forget = [f for f in forget if match.exact(f)]
2779
2781
2780 for subpath in sorted(wctx.substate):
2782 for subpath in sorted(wctx.substate):
2781 sub = wctx.sub(subpath)
2783 sub = wctx.sub(subpath)
2782 try:
2784 try:
2783 submatch = matchmod.subdirmatcher(subpath, match)
2785 submatch = matchmod.subdirmatcher(subpath, match)
2784 subbad, subforgot = sub.forget(submatch, prefix)
2786 subbad, subforgot = sub.forget(submatch, prefix)
2785 bad.extend([subpath + '/' + f for f in subbad])
2787 bad.extend([subpath + '/' + f for f in subbad])
2786 forgot.extend([subpath + '/' + f for f in subforgot])
2788 forgot.extend([subpath + '/' + f for f in subforgot])
2787 except error.LookupError:
2789 except error.LookupError:
2788 ui.status(_("skipping missing subrepository: %s\n")
2790 ui.status(_("skipping missing subrepository: %s\n")
2789 % join(subpath))
2791 % join(subpath))
2790
2792
2791 if not explicitonly:
2793 if not explicitonly:
2792 for f in match.files():
2794 for f in match.files():
2793 if f not in repo.dirstate and not repo.wvfs.isdir(f):
2795 if f not in repo.dirstate and not repo.wvfs.isdir(f):
2794 if f not in forgot:
2796 if f not in forgot:
2795 if repo.wvfs.exists(f):
2797 if repo.wvfs.exists(f):
2796 # Don't complain if the exact case match wasn't given.
2798 # Don't complain if the exact case match wasn't given.
2797 # But don't do this until after checking 'forgot', so
2799 # But don't do this until after checking 'forgot', so
2798 # that subrepo files aren't normalized, and this op is
2800 # that subrepo files aren't normalized, and this op is
2799 # purely from data cached by the status walk above.
2801 # purely from data cached by the status walk above.
2800 if repo.dirstate.normalize(f) in repo.dirstate:
2802 if repo.dirstate.normalize(f) in repo.dirstate:
2801 continue
2803 continue
2802 ui.warn(_('not removing %s: '
2804 ui.warn(_('not removing %s: '
2803 'file is already untracked\n')
2805 'file is already untracked\n')
2804 % match.rel(f))
2806 % match.rel(f))
2805 bad.append(f)
2807 bad.append(f)
2806
2808
2807 for f in forget:
2809 for f in forget:
2808 if ui.verbose or not match.exact(f):
2810 if ui.verbose or not match.exact(f):
2809 ui.status(_('removing %s\n') % match.rel(f))
2811 ui.status(_('removing %s\n') % match.rel(f))
2810
2812
2811 rejected = wctx.forget(forget, prefix)
2813 rejected = wctx.forget(forget, prefix)
2812 bad.extend(f for f in rejected if f in match.files())
2814 bad.extend(f for f in rejected if f in match.files())
2813 forgot.extend(f for f in forget if f not in rejected)
2815 forgot.extend(f for f in forget if f not in rejected)
2814 return bad, forgot
2816 return bad, forgot
2815
2817
2816 def files(ui, ctx, m, fm, fmt, subrepos):
2818 def files(ui, ctx, m, fm, fmt, subrepos):
2817 rev = ctx.rev()
2819 rev = ctx.rev()
2818 ret = 1
2820 ret = 1
2819 ds = ctx.repo().dirstate
2821 ds = ctx.repo().dirstate
2820
2822
2821 for f in ctx.matches(m):
2823 for f in ctx.matches(m):
2822 if rev is None and ds[f] == 'r':
2824 if rev is None and ds[f] == 'r':
2823 continue
2825 continue
2824 fm.startitem()
2826 fm.startitem()
2825 if ui.verbose:
2827 if ui.verbose:
2826 fc = ctx[f]
2828 fc = ctx[f]
2827 fm.write('size flags', '% 10d % 1s ', fc.size(), fc.flags())
2829 fm.write('size flags', '% 10d % 1s ', fc.size(), fc.flags())
2828 fm.data(abspath=f)
2830 fm.data(abspath=f)
2829 fm.write('path', fmt, m.rel(f))
2831 fm.write('path', fmt, m.rel(f))
2830 ret = 0
2832 ret = 0
2831
2833
2832 for subpath in sorted(ctx.substate):
2834 for subpath in sorted(ctx.substate):
2833 submatch = matchmod.subdirmatcher(subpath, m)
2835 submatch = matchmod.subdirmatcher(subpath, m)
2834 if (subrepos or m.exact(subpath) or any(submatch.files())):
2836 if (subrepos or m.exact(subpath) or any(submatch.files())):
2835 sub = ctx.sub(subpath)
2837 sub = ctx.sub(subpath)
2836 try:
2838 try:
2837 recurse = m.exact(subpath) or subrepos
2839 recurse = m.exact(subpath) or subrepos
2838 if sub.printfiles(ui, submatch, fm, fmt, recurse) == 0:
2840 if sub.printfiles(ui, submatch, fm, fmt, recurse) == 0:
2839 ret = 0
2841 ret = 0
2840 except error.LookupError:
2842 except error.LookupError:
2841 ui.status(_("skipping missing subrepository: %s\n")
2843 ui.status(_("skipping missing subrepository: %s\n")
2842 % m.abs(subpath))
2844 % m.abs(subpath))
2843
2845
2844 return ret
2846 return ret
2845
2847
2846 def remove(ui, repo, m, prefix, after, force, subrepos, warnings=None):
2848 def remove(ui, repo, m, prefix, after, force, subrepos, warnings=None):
2847 join = lambda f: os.path.join(prefix, f)
2849 join = lambda f: os.path.join(prefix, f)
2848 ret = 0
2850 ret = 0
2849 s = repo.status(match=m, clean=True)
2851 s = repo.status(match=m, clean=True)
2850 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
2852 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
2851
2853
2852 wctx = repo[None]
2854 wctx = repo[None]
2853
2855
2854 if warnings is None:
2856 if warnings is None:
2855 warnings = []
2857 warnings = []
2856 warn = True
2858 warn = True
2857 else:
2859 else:
2858 warn = False
2860 warn = False
2859
2861
2860 subs = sorted(wctx.substate)
2862 subs = sorted(wctx.substate)
2861 total = len(subs)
2863 total = len(subs)
2862 count = 0
2864 count = 0
2863 for subpath in subs:
2865 for subpath in subs:
2864 count += 1
2866 count += 1
2865 submatch = matchmod.subdirmatcher(subpath, m)
2867 submatch = matchmod.subdirmatcher(subpath, m)
2866 if subrepos or m.exact(subpath) or any(submatch.files()):
2868 if subrepos or m.exact(subpath) or any(submatch.files()):
2867 ui.progress(_('searching'), count, total=total, unit=_('subrepos'))
2869 ui.progress(_('searching'), count, total=total, unit=_('subrepos'))
2868 sub = wctx.sub(subpath)
2870 sub = wctx.sub(subpath)
2869 try:
2871 try:
2870 if sub.removefiles(submatch, prefix, after, force, subrepos,
2872 if sub.removefiles(submatch, prefix, after, force, subrepos,
2871 warnings):
2873 warnings):
2872 ret = 1
2874 ret = 1
2873 except error.LookupError:
2875 except error.LookupError:
2874 warnings.append(_("skipping missing subrepository: %s\n")
2876 warnings.append(_("skipping missing subrepository: %s\n")
2875 % join(subpath))
2877 % join(subpath))
2876 ui.progress(_('searching'), None)
2878 ui.progress(_('searching'), None)
2877
2879
2878 # warn about failure to delete explicit files/dirs
2880 # warn about failure to delete explicit files/dirs
2879 deleteddirs = util.dirs(deleted)
2881 deleteddirs = util.dirs(deleted)
2880 files = m.files()
2882 files = m.files()
2881 total = len(files)
2883 total = len(files)
2882 count = 0
2884 count = 0
2883 for f in files:
2885 for f in files:
2884 def insubrepo():
2886 def insubrepo():
2885 for subpath in wctx.substate:
2887 for subpath in wctx.substate:
2886 if f.startswith(subpath + '/'):
2888 if f.startswith(subpath + '/'):
2887 return True
2889 return True
2888 return False
2890 return False
2889
2891
2890 count += 1
2892 count += 1
2891 ui.progress(_('deleting'), count, total=total, unit=_('files'))
2893 ui.progress(_('deleting'), count, total=total, unit=_('files'))
2892 isdir = f in deleteddirs or wctx.hasdir(f)
2894 isdir = f in deleteddirs or wctx.hasdir(f)
2893 if (f in repo.dirstate or isdir or f == '.'
2895 if (f in repo.dirstate or isdir or f == '.'
2894 or insubrepo() or f in subs):
2896 or insubrepo() or f in subs):
2895 continue
2897 continue
2896
2898
2897 if repo.wvfs.exists(f):
2899 if repo.wvfs.exists(f):
2898 if repo.wvfs.isdir(f):
2900 if repo.wvfs.isdir(f):
2899 warnings.append(_('not removing %s: no tracked files\n')
2901 warnings.append(_('not removing %s: no tracked files\n')
2900 % m.rel(f))
2902 % m.rel(f))
2901 else:
2903 else:
2902 warnings.append(_('not removing %s: file is untracked\n')
2904 warnings.append(_('not removing %s: file is untracked\n')
2903 % m.rel(f))
2905 % m.rel(f))
2904 # missing files will generate a warning elsewhere
2906 # missing files will generate a warning elsewhere
2905 ret = 1
2907 ret = 1
2906 ui.progress(_('deleting'), None)
2908 ui.progress(_('deleting'), None)
2907
2909
2908 if force:
2910 if force:
2909 list = modified + deleted + clean + added
2911 list = modified + deleted + clean + added
2910 elif after:
2912 elif after:
2911 list = deleted
2913 list = deleted
2912 remaining = modified + added + clean
2914 remaining = modified + added + clean
2913 total = len(remaining)
2915 total = len(remaining)
2914 count = 0
2916 count = 0
2915 for f in remaining:
2917 for f in remaining:
2916 count += 1
2918 count += 1
2917 ui.progress(_('skipping'), count, total=total, unit=_('files'))
2919 ui.progress(_('skipping'), count, total=total, unit=_('files'))
2918 if ui.verbose or (f in files):
2920 if ui.verbose or (f in files):
2919 warnings.append(_('not removing %s: file still exists\n')
2921 warnings.append(_('not removing %s: file still exists\n')
2920 % m.rel(f))
2922 % m.rel(f))
2921 ret = 1
2923 ret = 1
2922 ui.progress(_('skipping'), None)
2924 ui.progress(_('skipping'), None)
2923 else:
2925 else:
2924 list = deleted + clean
2926 list = deleted + clean
2925 total = len(modified) + len(added)
2927 total = len(modified) + len(added)
2926 count = 0
2928 count = 0
2927 for f in modified:
2929 for f in modified:
2928 count += 1
2930 count += 1
2929 ui.progress(_('skipping'), count, total=total, unit=_('files'))
2931 ui.progress(_('skipping'), count, total=total, unit=_('files'))
2930 warnings.append(_('not removing %s: file is modified (use -f'
2932 warnings.append(_('not removing %s: file is modified (use -f'
2931 ' to force removal)\n') % m.rel(f))
2933 ' to force removal)\n') % m.rel(f))
2932 ret = 1
2934 ret = 1
2933 for f in added:
2935 for f in added:
2934 count += 1
2936 count += 1
2935 ui.progress(_('skipping'), count, total=total, unit=_('files'))
2937 ui.progress(_('skipping'), count, total=total, unit=_('files'))
2936 warnings.append(_("not removing %s: file has been marked for add"
2938 warnings.append(_("not removing %s: file has been marked for add"
2937 " (use 'hg forget' to undo add)\n") % m.rel(f))
2939 " (use 'hg forget' to undo add)\n") % m.rel(f))
2938 ret = 1
2940 ret = 1
2939 ui.progress(_('skipping'), None)
2941 ui.progress(_('skipping'), None)
2940
2942
2941 list = sorted(list)
2943 list = sorted(list)
2942 total = len(list)
2944 total = len(list)
2943 count = 0
2945 count = 0
2944 for f in list:
2946 for f in list:
2945 count += 1
2947 count += 1
2946 if ui.verbose or not m.exact(f):
2948 if ui.verbose or not m.exact(f):
2947 ui.progress(_('deleting'), count, total=total, unit=_('files'))
2949 ui.progress(_('deleting'), count, total=total, unit=_('files'))
2948 ui.status(_('removing %s\n') % m.rel(f))
2950 ui.status(_('removing %s\n') % m.rel(f))
2949 ui.progress(_('deleting'), None)
2951 ui.progress(_('deleting'), None)
2950
2952
2951 with repo.wlock():
2953 with repo.wlock():
2952 if not after:
2954 if not after:
2953 for f in list:
2955 for f in list:
2954 if f in added:
2956 if f in added:
2955 continue # we never unlink added files on remove
2957 continue # we never unlink added files on remove
2956 repo.wvfs.unlinkpath(f, ignoremissing=True)
2958 repo.wvfs.unlinkpath(f, ignoremissing=True)
2957 repo[None].forget(list)
2959 repo[None].forget(list)
2958
2960
2959 if warn:
2961 if warn:
2960 for warning in warnings:
2962 for warning in warnings:
2961 ui.warn(warning)
2963 ui.warn(warning)
2962
2964
2963 return ret
2965 return ret
2964
2966
2965 def cat(ui, repo, ctx, matcher, basefm, fntemplate, prefix, **opts):
2967 def cat(ui, repo, ctx, matcher, basefm, fntemplate, prefix, **opts):
2966 err = 1
2968 err = 1
2967 opts = pycompat.byteskwargs(opts)
2969 opts = pycompat.byteskwargs(opts)
2968
2970
2969 def write(path):
2971 def write(path):
2970 filename = None
2972 filename = None
2971 if fntemplate:
2973 if fntemplate:
2972 filename = makefilename(repo, fntemplate, ctx.node(),
2974 filename = makefilename(repo, fntemplate, ctx.node(),
2973 pathname=os.path.join(prefix, path))
2975 pathname=os.path.join(prefix, path))
2974 # attempt to create the directory if it does not already exist
2976 # attempt to create the directory if it does not already exist
2975 try:
2977 try:
2976 os.makedirs(os.path.dirname(filename))
2978 os.makedirs(os.path.dirname(filename))
2977 except OSError:
2979 except OSError:
2978 pass
2980 pass
2979 with formatter.maybereopen(basefm, filename, opts) as fm:
2981 with formatter.maybereopen(basefm, filename, opts) as fm:
2980 data = ctx[path].data()
2982 data = ctx[path].data()
2981 if opts.get('decode'):
2983 if opts.get('decode'):
2982 data = repo.wwritedata(path, data)
2984 data = repo.wwritedata(path, data)
2983 fm.startitem()
2985 fm.startitem()
2984 fm.write('data', '%s', data)
2986 fm.write('data', '%s', data)
2985 fm.data(abspath=path, path=matcher.rel(path))
2987 fm.data(abspath=path, path=matcher.rel(path))
2986
2988
2987 # Automation often uses hg cat on single files, so special case it
2989 # Automation often uses hg cat on single files, so special case it
2988 # for performance to avoid the cost of parsing the manifest.
2990 # for performance to avoid the cost of parsing the manifest.
2989 if len(matcher.files()) == 1 and not matcher.anypats():
2991 if len(matcher.files()) == 1 and not matcher.anypats():
2990 file = matcher.files()[0]
2992 file = matcher.files()[0]
2991 mfl = repo.manifestlog
2993 mfl = repo.manifestlog
2992 mfnode = ctx.manifestnode()
2994 mfnode = ctx.manifestnode()
2993 try:
2995 try:
2994 if mfnode and mfl[mfnode].find(file)[0]:
2996 if mfnode and mfl[mfnode].find(file)[0]:
2995 write(file)
2997 write(file)
2996 return 0
2998 return 0
2997 except KeyError:
2999 except KeyError:
2998 pass
3000 pass
2999
3001
3000 for abs in ctx.walk(matcher):
3002 for abs in ctx.walk(matcher):
3001 write(abs)
3003 write(abs)
3002 err = 0
3004 err = 0
3003
3005
3004 for subpath in sorted(ctx.substate):
3006 for subpath in sorted(ctx.substate):
3005 sub = ctx.sub(subpath)
3007 sub = ctx.sub(subpath)
3006 try:
3008 try:
3007 submatch = matchmod.subdirmatcher(subpath, matcher)
3009 submatch = matchmod.subdirmatcher(subpath, matcher)
3008
3010
3009 if not sub.cat(submatch, basefm, fntemplate,
3011 if not sub.cat(submatch, basefm, fntemplate,
3010 os.path.join(prefix, sub._path),
3012 os.path.join(prefix, sub._path),
3011 **pycompat.strkwargs(opts)):
3013 **pycompat.strkwargs(opts)):
3012 err = 0
3014 err = 0
3013 except error.RepoLookupError:
3015 except error.RepoLookupError:
3014 ui.status(_("skipping missing subrepository: %s\n")
3016 ui.status(_("skipping missing subrepository: %s\n")
3015 % os.path.join(prefix, subpath))
3017 % os.path.join(prefix, subpath))
3016
3018
3017 return err
3019 return err
3018
3020
3019 def commit(ui, repo, commitfunc, pats, opts):
3021 def commit(ui, repo, commitfunc, pats, opts):
3020 '''commit the specified files or all outstanding changes'''
3022 '''commit the specified files or all outstanding changes'''
3021 date = opts.get('date')
3023 date = opts.get('date')
3022 if date:
3024 if date:
3023 opts['date'] = util.parsedate(date)
3025 opts['date'] = util.parsedate(date)
3024 message = logmessage(ui, opts)
3026 message = logmessage(ui, opts)
3025 matcher = scmutil.match(repo[None], pats, opts)
3027 matcher = scmutil.match(repo[None], pats, opts)
3026
3028
3027 dsguard = None
3029 dsguard = None
3028 # extract addremove carefully -- this function can be called from a command
3030 # extract addremove carefully -- this function can be called from a command
3029 # that doesn't support addremove
3031 # that doesn't support addremove
3030 if opts.get('addremove'):
3032 if opts.get('addremove'):
3031 dsguard = dirstateguard.dirstateguard(repo, 'commit')
3033 dsguard = dirstateguard.dirstateguard(repo, 'commit')
3032 with dsguard or util.nullcontextmanager():
3034 with dsguard or util.nullcontextmanager():
3033 if dsguard:
3035 if dsguard:
3034 if scmutil.addremove(repo, matcher, "", opts) != 0:
3036 if scmutil.addremove(repo, matcher, "", opts) != 0:
3035 raise error.Abort(
3037 raise error.Abort(
3036 _("failed to mark all new/missing files as added/removed"))
3038 _("failed to mark all new/missing files as added/removed"))
3037
3039
3038 return commitfunc(ui, repo, message, matcher, opts)
3040 return commitfunc(ui, repo, message, matcher, opts)
3039
3041
3040 def samefile(f, ctx1, ctx2):
3042 def samefile(f, ctx1, ctx2):
3041 if f in ctx1.manifest():
3043 if f in ctx1.manifest():
3042 a = ctx1.filectx(f)
3044 a = ctx1.filectx(f)
3043 if f in ctx2.manifest():
3045 if f in ctx2.manifest():
3044 b = ctx2.filectx(f)
3046 b = ctx2.filectx(f)
3045 return (not a.cmp(b)
3047 return (not a.cmp(b)
3046 and a.flags() == b.flags())
3048 and a.flags() == b.flags())
3047 else:
3049 else:
3048 return False
3050 return False
3049 else:
3051 else:
3050 return f not in ctx2.manifest()
3052 return f not in ctx2.manifest()
3051
3053
3052 def amend(ui, repo, old, extra, pats, opts):
3054 def amend(ui, repo, old, extra, pats, opts):
3053 # avoid cycle context -> subrepo -> cmdutil
3055 # avoid cycle context -> subrepo -> cmdutil
3054 from . import context
3056 from . import context
3055
3057
3056 # amend will reuse the existing user if not specified, but the obsolete
3058 # amend will reuse the existing user if not specified, but the obsolete
3057 # marker creation requires that the current user's name is specified.
3059 # marker creation requires that the current user's name is specified.
3058 if obsolete.isenabled(repo, obsolete.createmarkersopt):
3060 if obsolete.isenabled(repo, obsolete.createmarkersopt):
3059 ui.username() # raise exception if username not set
3061 ui.username() # raise exception if username not set
3060
3062
3061 ui.note(_('amending changeset %s\n') % old)
3063 ui.note(_('amending changeset %s\n') % old)
3062 base = old.p1()
3064 base = old.p1()
3063
3065
3064 with repo.wlock(), repo.lock(), repo.transaction('amend'):
3066 with repo.wlock(), repo.lock(), repo.transaction('amend'):
3065 # Participating changesets:
3067 # Participating changesets:
3066 #
3068 #
3067 # wctx o - workingctx that contains changes from working copy
3069 # wctx o - workingctx that contains changes from working copy
3068 # | to go into amending commit
3070 # | to go into amending commit
3069 # |
3071 # |
3070 # old o - changeset to amend
3072 # old o - changeset to amend
3071 # |
3073 # |
3072 # base o - first parent of the changeset to amend
3074 # base o - first parent of the changeset to amend
3073 wctx = repo[None]
3075 wctx = repo[None]
3074
3076
3075 # Copy to avoid mutating input
3077 # Copy to avoid mutating input
3076 extra = extra.copy()
3078 extra = extra.copy()
3077 # Update extra dict from amended commit (e.g. to preserve graft
3079 # Update extra dict from amended commit (e.g. to preserve graft
3078 # source)
3080 # source)
3079 extra.update(old.extra())
3081 extra.update(old.extra())
3080
3082
3081 # Also update it from the from the wctx
3083 # Also update it from the from the wctx
3082 extra.update(wctx.extra())
3084 extra.update(wctx.extra())
3083
3085
3084 user = opts.get('user') or old.user()
3086 user = opts.get('user') or old.user()
3085 date = opts.get('date') or old.date()
3087 date = opts.get('date') or old.date()
3086
3088
3087 # Parse the date to allow comparison between date and old.date()
3089 # Parse the date to allow comparison between date and old.date()
3088 date = util.parsedate(date)
3090 date = util.parsedate(date)
3089
3091
3090 if len(old.parents()) > 1:
3092 if len(old.parents()) > 1:
3091 # ctx.files() isn't reliable for merges, so fall back to the
3093 # ctx.files() isn't reliable for merges, so fall back to the
3092 # slower repo.status() method
3094 # slower repo.status() method
3093 files = set([fn for st in repo.status(base, old)[:3]
3095 files = set([fn for st in repo.status(base, old)[:3]
3094 for fn in st])
3096 for fn in st])
3095 else:
3097 else:
3096 files = set(old.files())
3098 files = set(old.files())
3097
3099
3098 # add/remove the files to the working copy if the "addremove" option
3100 # add/remove the files to the working copy if the "addremove" option
3099 # was specified.
3101 # was specified.
3100 matcher = scmutil.match(wctx, pats, opts)
3102 matcher = scmutil.match(wctx, pats, opts)
3101 if (opts.get('addremove')
3103 if (opts.get('addremove')
3102 and scmutil.addremove(repo, matcher, "", opts)):
3104 and scmutil.addremove(repo, matcher, "", opts)):
3103 raise error.Abort(
3105 raise error.Abort(
3104 _("failed to mark all new/missing files as added/removed"))
3106 _("failed to mark all new/missing files as added/removed"))
3105
3107
3106 # Check subrepos. This depends on in-place wctx._status update in
3108 # Check subrepos. This depends on in-place wctx._status update in
3107 # subrepo.precommit(). To minimize the risk of this hack, we do
3109 # subrepo.precommit(). To minimize the risk of this hack, we do
3108 # nothing if .hgsub does not exist.
3110 # nothing if .hgsub does not exist.
3109 if '.hgsub' in wctx or '.hgsub' in old:
3111 if '.hgsub' in wctx or '.hgsub' in old:
3110 from . import subrepo # avoid cycle: cmdutil -> subrepo -> cmdutil
3112 from . import subrepo # avoid cycle: cmdutil -> subrepo -> cmdutil
3111 subs, commitsubs, newsubstate = subrepo.precommit(
3113 subs, commitsubs, newsubstate = subrepo.precommit(
3112 ui, wctx, wctx._status, matcher)
3114 ui, wctx, wctx._status, matcher)
3113 # amend should abort if commitsubrepos is enabled
3115 # amend should abort if commitsubrepos is enabled
3114 assert not commitsubs
3116 assert not commitsubs
3115 if subs:
3117 if subs:
3116 subrepo.writestate(repo, newsubstate)
3118 subrepo.writestate(repo, newsubstate)
3117
3119
3118 filestoamend = set(f for f in wctx.files() if matcher(f))
3120 filestoamend = set(f for f in wctx.files() if matcher(f))
3119
3121
3120 changes = (len(filestoamend) > 0)
3122 changes = (len(filestoamend) > 0)
3121 if changes:
3123 if changes:
3122 # Recompute copies (avoid recording a -> b -> a)
3124 # Recompute copies (avoid recording a -> b -> a)
3123 copied = copies.pathcopies(base, wctx, matcher)
3125 copied = copies.pathcopies(base, wctx, matcher)
3124 if old.p2:
3126 if old.p2:
3125 copied.update(copies.pathcopies(old.p2(), wctx, matcher))
3127 copied.update(copies.pathcopies(old.p2(), wctx, matcher))
3126
3128
3127 # Prune files which were reverted by the updates: if old
3129 # Prune files which were reverted by the updates: if old
3128 # introduced file X and the file was renamed in the working
3130 # introduced file X and the file was renamed in the working
3129 # copy, then those two files are the same and
3131 # copy, then those two files are the same and
3130 # we can discard X from our list of files. Likewise if X
3132 # we can discard X from our list of files. Likewise if X
3131 # was removed, it's no longer relevant. If X is missing (aka
3133 # was removed, it's no longer relevant. If X is missing (aka
3132 # deleted), old X must be preserved.
3134 # deleted), old X must be preserved.
3133 files.update(filestoamend)
3135 files.update(filestoamend)
3134 files = [f for f in files if (not samefile(f, wctx, base)
3136 files = [f for f in files if (not samefile(f, wctx, base)
3135 or f in wctx.deleted())]
3137 or f in wctx.deleted())]
3136
3138
3137 def filectxfn(repo, ctx_, path):
3139 def filectxfn(repo, ctx_, path):
3138 try:
3140 try:
3139 # If the file being considered is not amongst the files
3141 # If the file being considered is not amongst the files
3140 # to be amended, we should return the file context from the
3142 # to be amended, we should return the file context from the
3141 # old changeset. This avoids issues when only some files in
3143 # old changeset. This avoids issues when only some files in
3142 # the working copy are being amended but there are also
3144 # the working copy are being amended but there are also
3143 # changes to other files from the old changeset.
3145 # changes to other files from the old changeset.
3144 if path not in filestoamend:
3146 if path not in filestoamend:
3145 return old.filectx(path)
3147 return old.filectx(path)
3146
3148
3147 # Return None for removed files.
3149 # Return None for removed files.
3148 if path in wctx.removed():
3150 if path in wctx.removed():
3149 return None
3151 return None
3150
3152
3151 fctx = wctx[path]
3153 fctx = wctx[path]
3152 flags = fctx.flags()
3154 flags = fctx.flags()
3153 mctx = context.memfilectx(repo, ctx_,
3155 mctx = context.memfilectx(repo, ctx_,
3154 fctx.path(), fctx.data(),
3156 fctx.path(), fctx.data(),
3155 islink='l' in flags,
3157 islink='l' in flags,
3156 isexec='x' in flags,
3158 isexec='x' in flags,
3157 copied=copied.get(path))
3159 copied=copied.get(path))
3158 return mctx
3160 return mctx
3159 except KeyError:
3161 except KeyError:
3160 return None
3162 return None
3161 else:
3163 else:
3162 ui.note(_('copying changeset %s to %s\n') % (old, base))
3164 ui.note(_('copying changeset %s to %s\n') % (old, base))
3163
3165
3164 # Use version of files as in the old cset
3166 # Use version of files as in the old cset
3165 def filectxfn(repo, ctx_, path):
3167 def filectxfn(repo, ctx_, path):
3166 try:
3168 try:
3167 return old.filectx(path)
3169 return old.filectx(path)
3168 except KeyError:
3170 except KeyError:
3169 return None
3171 return None
3170
3172
3171 # See if we got a message from -m or -l, if not, open the editor with
3173 # See if we got a message from -m or -l, if not, open the editor with
3172 # the message of the changeset to amend.
3174 # the message of the changeset to amend.
3173 message = logmessage(ui, opts)
3175 message = logmessage(ui, opts)
3174
3176
3175 editform = mergeeditform(old, 'commit.amend')
3177 editform = mergeeditform(old, 'commit.amend')
3176 editor = getcommiteditor(editform=editform,
3178 editor = getcommiteditor(editform=editform,
3177 **pycompat.strkwargs(opts))
3179 **pycompat.strkwargs(opts))
3178
3180
3179 if not message:
3181 if not message:
3180 editor = getcommiteditor(edit=True, editform=editform)
3182 editor = getcommiteditor(edit=True, editform=editform)
3181 message = old.description()
3183 message = old.description()
3182
3184
3183 pureextra = extra.copy()
3185 pureextra = extra.copy()
3184 extra['amend_source'] = old.hex()
3186 extra['amend_source'] = old.hex()
3185
3187
3186 new = context.memctx(repo,
3188 new = context.memctx(repo,
3187 parents=[base.node(), old.p2().node()],
3189 parents=[base.node(), old.p2().node()],
3188 text=message,
3190 text=message,
3189 files=files,
3191 files=files,
3190 filectxfn=filectxfn,
3192 filectxfn=filectxfn,
3191 user=user,
3193 user=user,
3192 date=date,
3194 date=date,
3193 extra=extra,
3195 extra=extra,
3194 editor=editor)
3196 editor=editor)
3195
3197
3196 newdesc = changelog.stripdesc(new.description())
3198 newdesc = changelog.stripdesc(new.description())
3197 if ((not changes)
3199 if ((not changes)
3198 and newdesc == old.description()
3200 and newdesc == old.description()
3199 and user == old.user()
3201 and user == old.user()
3200 and date == old.date()
3202 and date == old.date()
3201 and pureextra == old.extra()):
3203 and pureextra == old.extra()):
3202 # nothing changed. continuing here would create a new node
3204 # nothing changed. continuing here would create a new node
3203 # anyway because of the amend_source noise.
3205 # anyway because of the amend_source noise.
3204 #
3206 #
3205 # This not what we expect from amend.
3207 # This not what we expect from amend.
3206 return old.node()
3208 return old.node()
3207
3209
3208 if opts.get('secret'):
3210 if opts.get('secret'):
3209 commitphase = 'secret'
3211 commitphase = 'secret'
3210 else:
3212 else:
3211 commitphase = old.phase()
3213 commitphase = old.phase()
3212 overrides = {('phases', 'new-commit'): commitphase}
3214 overrides = {('phases', 'new-commit'): commitphase}
3213 with ui.configoverride(overrides, 'amend'):
3215 with ui.configoverride(overrides, 'amend'):
3214 newid = repo.commitctx(new)
3216 newid = repo.commitctx(new)
3215
3217
3216 # Reroute the working copy parent to the new changeset
3218 # Reroute the working copy parent to the new changeset
3217 repo.setparents(newid, nullid)
3219 repo.setparents(newid, nullid)
3218 mapping = {old.node(): (newid,)}
3220 mapping = {old.node(): (newid,)}
3219 obsmetadata = None
3221 obsmetadata = None
3220 if opts.get('note'):
3222 if opts.get('note'):
3221 obsmetadata = {'note': opts['note']}
3223 obsmetadata = {'note': opts['note']}
3222 scmutil.cleanupnodes(repo, mapping, 'amend', metadata=obsmetadata)
3224 scmutil.cleanupnodes(repo, mapping, 'amend', metadata=obsmetadata)
3223
3225
3224 # Fixing the dirstate because localrepo.commitctx does not update
3226 # Fixing the dirstate because localrepo.commitctx does not update
3225 # it. This is rather convenient because we did not need to update
3227 # it. This is rather convenient because we did not need to update
3226 # the dirstate for all the files in the new commit which commitctx
3228 # the dirstate for all the files in the new commit which commitctx
3227 # could have done if it updated the dirstate. Now, we can
3229 # could have done if it updated the dirstate. Now, we can
3228 # selectively update the dirstate only for the amended files.
3230 # selectively update the dirstate only for the amended files.
3229 dirstate = repo.dirstate
3231 dirstate = repo.dirstate
3230
3232
3231 # Update the state of the files which were added and
3233 # Update the state of the files which were added and
3232 # and modified in the amend to "normal" in the dirstate.
3234 # and modified in the amend to "normal" in the dirstate.
3233 normalfiles = set(wctx.modified() + wctx.added()) & filestoamend
3235 normalfiles = set(wctx.modified() + wctx.added()) & filestoamend
3234 for f in normalfiles:
3236 for f in normalfiles:
3235 dirstate.normal(f)
3237 dirstate.normal(f)
3236
3238
3237 # Update the state of files which were removed in the amend
3239 # Update the state of files which were removed in the amend
3238 # to "removed" in the dirstate.
3240 # to "removed" in the dirstate.
3239 removedfiles = set(wctx.removed()) & filestoamend
3241 removedfiles = set(wctx.removed()) & filestoamend
3240 for f in removedfiles:
3242 for f in removedfiles:
3241 dirstate.drop(f)
3243 dirstate.drop(f)
3242
3244
3243 return newid
3245 return newid
3244
3246
3245 def commiteditor(repo, ctx, subs, editform=''):
3247 def commiteditor(repo, ctx, subs, editform=''):
3246 if ctx.description():
3248 if ctx.description():
3247 return ctx.description()
3249 return ctx.description()
3248 return commitforceeditor(repo, ctx, subs, editform=editform,
3250 return commitforceeditor(repo, ctx, subs, editform=editform,
3249 unchangedmessagedetection=True)
3251 unchangedmessagedetection=True)
3250
3252
3251 def commitforceeditor(repo, ctx, subs, finishdesc=None, extramsg=None,
3253 def commitforceeditor(repo, ctx, subs, finishdesc=None, extramsg=None,
3252 editform='', unchangedmessagedetection=False):
3254 editform='', unchangedmessagedetection=False):
3253 if not extramsg:
3255 if not extramsg:
3254 extramsg = _("Leave message empty to abort commit.")
3256 extramsg = _("Leave message empty to abort commit.")
3255
3257
3256 forms = [e for e in editform.split('.') if e]
3258 forms = [e for e in editform.split('.') if e]
3257 forms.insert(0, 'changeset')
3259 forms.insert(0, 'changeset')
3258 templatetext = None
3260 templatetext = None
3259 while forms:
3261 while forms:
3260 ref = '.'.join(forms)
3262 ref = '.'.join(forms)
3261 if repo.ui.config('committemplate', ref):
3263 if repo.ui.config('committemplate', ref):
3262 templatetext = committext = buildcommittemplate(
3264 templatetext = committext = buildcommittemplate(
3263 repo, ctx, subs, extramsg, ref)
3265 repo, ctx, subs, extramsg, ref)
3264 break
3266 break
3265 forms.pop()
3267 forms.pop()
3266 else:
3268 else:
3267 committext = buildcommittext(repo, ctx, subs, extramsg)
3269 committext = buildcommittext(repo, ctx, subs, extramsg)
3268
3270
3269 # run editor in the repository root
3271 # run editor in the repository root
3270 olddir = pycompat.getcwd()
3272 olddir = pycompat.getcwd()
3271 os.chdir(repo.root)
3273 os.chdir(repo.root)
3272
3274
3273 # make in-memory changes visible to external process
3275 # make in-memory changes visible to external process
3274 tr = repo.currenttransaction()
3276 tr = repo.currenttransaction()
3275 repo.dirstate.write(tr)
3277 repo.dirstate.write(tr)
3276 pending = tr and tr.writepending() and repo.root
3278 pending = tr and tr.writepending() and repo.root
3277
3279
3278 editortext = repo.ui.edit(committext, ctx.user(), ctx.extra(),
3280 editortext = repo.ui.edit(committext, ctx.user(), ctx.extra(),
3279 editform=editform, pending=pending,
3281 editform=editform, pending=pending,
3280 repopath=repo.path, action='commit')
3282 repopath=repo.path, action='commit')
3281 text = editortext
3283 text = editortext
3282
3284
3283 # strip away anything below this special string (used for editors that want
3285 # strip away anything below this special string (used for editors that want
3284 # to display the diff)
3286 # to display the diff)
3285 stripbelow = re.search(_linebelow, text, flags=re.MULTILINE)
3287 stripbelow = re.search(_linebelow, text, flags=re.MULTILINE)
3286 if stripbelow:
3288 if stripbelow:
3287 text = text[:stripbelow.start()]
3289 text = text[:stripbelow.start()]
3288
3290
3289 text = re.sub("(?m)^HG:.*(\n|$)", "", text)
3291 text = re.sub("(?m)^HG:.*(\n|$)", "", text)
3290 os.chdir(olddir)
3292 os.chdir(olddir)
3291
3293
3292 if finishdesc:
3294 if finishdesc:
3293 text = finishdesc(text)
3295 text = finishdesc(text)
3294 if not text.strip():
3296 if not text.strip():
3295 raise error.Abort(_("empty commit message"))
3297 raise error.Abort(_("empty commit message"))
3296 if unchangedmessagedetection and editortext == templatetext:
3298 if unchangedmessagedetection and editortext == templatetext:
3297 raise error.Abort(_("commit message unchanged"))
3299 raise error.Abort(_("commit message unchanged"))
3298
3300
3299 return text
3301 return text
3300
3302
3301 def buildcommittemplate(repo, ctx, subs, extramsg, ref):
3303 def buildcommittemplate(repo, ctx, subs, extramsg, ref):
3302 ui = repo.ui
3304 ui = repo.ui
3303 spec = formatter.templatespec(ref, None, None)
3305 spec = formatter.templatespec(ref, None, None)
3304 t = changeset_templater(ui, repo, spec, None, {}, False)
3306 t = changeset_templater(ui, repo, spec, None, {}, False)
3305 t.t.cache.update((k, templater.unquotestring(v))
3307 t.t.cache.update((k, templater.unquotestring(v))
3306 for k, v in repo.ui.configitems('committemplate'))
3308 for k, v in repo.ui.configitems('committemplate'))
3307
3309
3308 if not extramsg:
3310 if not extramsg:
3309 extramsg = '' # ensure that extramsg is string
3311 extramsg = '' # ensure that extramsg is string
3310
3312
3311 ui.pushbuffer()
3313 ui.pushbuffer()
3312 t.show(ctx, extramsg=extramsg)
3314 t.show(ctx, extramsg=extramsg)
3313 return ui.popbuffer()
3315 return ui.popbuffer()
3314
3316
3315 def hgprefix(msg):
3317 def hgprefix(msg):
3316 return "\n".join(["HG: %s" % a for a in msg.split("\n") if a])
3318 return "\n".join(["HG: %s" % a for a in msg.split("\n") if a])
3317
3319
3318 def buildcommittext(repo, ctx, subs, extramsg):
3320 def buildcommittext(repo, ctx, subs, extramsg):
3319 edittext = []
3321 edittext = []
3320 modified, added, removed = ctx.modified(), ctx.added(), ctx.removed()
3322 modified, added, removed = ctx.modified(), ctx.added(), ctx.removed()
3321 if ctx.description():
3323 if ctx.description():
3322 edittext.append(ctx.description())
3324 edittext.append(ctx.description())
3323 edittext.append("")
3325 edittext.append("")
3324 edittext.append("") # Empty line between message and comments.
3326 edittext.append("") # Empty line between message and comments.
3325 edittext.append(hgprefix(_("Enter commit message."
3327 edittext.append(hgprefix(_("Enter commit message."
3326 " Lines beginning with 'HG:' are removed.")))
3328 " Lines beginning with 'HG:' are removed.")))
3327 edittext.append(hgprefix(extramsg))
3329 edittext.append(hgprefix(extramsg))
3328 edittext.append("HG: --")
3330 edittext.append("HG: --")
3329 edittext.append(hgprefix(_("user: %s") % ctx.user()))
3331 edittext.append(hgprefix(_("user: %s") % ctx.user()))
3330 if ctx.p2():
3332 if ctx.p2():
3331 edittext.append(hgprefix(_("branch merge")))
3333 edittext.append(hgprefix(_("branch merge")))
3332 if ctx.branch():
3334 if ctx.branch():
3333 edittext.append(hgprefix(_("branch '%s'") % ctx.branch()))
3335 edittext.append(hgprefix(_("branch '%s'") % ctx.branch()))
3334 if bookmarks.isactivewdirparent(repo):
3336 if bookmarks.isactivewdirparent(repo):
3335 edittext.append(hgprefix(_("bookmark '%s'") % repo._activebookmark))
3337 edittext.append(hgprefix(_("bookmark '%s'") % repo._activebookmark))
3336 edittext.extend([hgprefix(_("subrepo %s") % s) for s in subs])
3338 edittext.extend([hgprefix(_("subrepo %s") % s) for s in subs])
3337 edittext.extend([hgprefix(_("added %s") % f) for f in added])
3339 edittext.extend([hgprefix(_("added %s") % f) for f in added])
3338 edittext.extend([hgprefix(_("changed %s") % f) for f in modified])
3340 edittext.extend([hgprefix(_("changed %s") % f) for f in modified])
3339 edittext.extend([hgprefix(_("removed %s") % f) for f in removed])
3341 edittext.extend([hgprefix(_("removed %s") % f) for f in removed])
3340 if not added and not modified and not removed:
3342 if not added and not modified and not removed:
3341 edittext.append(hgprefix(_("no files changed")))
3343 edittext.append(hgprefix(_("no files changed")))
3342 edittext.append("")
3344 edittext.append("")
3343
3345
3344 return "\n".join(edittext)
3346 return "\n".join(edittext)
3345
3347
3346 def commitstatus(repo, node, branch, bheads=None, opts=None):
3348 def commitstatus(repo, node, branch, bheads=None, opts=None):
3347 if opts is None:
3349 if opts is None:
3348 opts = {}
3350 opts = {}
3349 ctx = repo[node]
3351 ctx = repo[node]
3350 parents = ctx.parents()
3352 parents = ctx.parents()
3351
3353
3352 if (not opts.get('amend') and bheads and node not in bheads and not
3354 if (not opts.get('amend') and bheads and node not in bheads and not
3353 [x for x in parents if x.node() in bheads and x.branch() == branch]):
3355 [x for x in parents if x.node() in bheads and x.branch() == branch]):
3354 repo.ui.status(_('created new head\n'))
3356 repo.ui.status(_('created new head\n'))
3355 # The message is not printed for initial roots. For the other
3357 # The message is not printed for initial roots. For the other
3356 # changesets, it is printed in the following situations:
3358 # changesets, it is printed in the following situations:
3357 #
3359 #
3358 # Par column: for the 2 parents with ...
3360 # Par column: for the 2 parents with ...
3359 # N: null or no parent
3361 # N: null or no parent
3360 # B: parent is on another named branch
3362 # B: parent is on another named branch
3361 # C: parent is a regular non head changeset
3363 # C: parent is a regular non head changeset
3362 # H: parent was a branch head of the current branch
3364 # H: parent was a branch head of the current branch
3363 # Msg column: whether we print "created new head" message
3365 # Msg column: whether we print "created new head" message
3364 # In the following, it is assumed that there already exists some
3366 # In the following, it is assumed that there already exists some
3365 # initial branch heads of the current branch, otherwise nothing is
3367 # initial branch heads of the current branch, otherwise nothing is
3366 # printed anyway.
3368 # printed anyway.
3367 #
3369 #
3368 # Par Msg Comment
3370 # Par Msg Comment
3369 # N N y additional topo root
3371 # N N y additional topo root
3370 #
3372 #
3371 # B N y additional branch root
3373 # B N y additional branch root
3372 # C N y additional topo head
3374 # C N y additional topo head
3373 # H N n usual case
3375 # H N n usual case
3374 #
3376 #
3375 # B B y weird additional branch root
3377 # B B y weird additional branch root
3376 # C B y branch merge
3378 # C B y branch merge
3377 # H B n merge with named branch
3379 # H B n merge with named branch
3378 #
3380 #
3379 # C C y additional head from merge
3381 # C C y additional head from merge
3380 # C H n merge with a head
3382 # C H n merge with a head
3381 #
3383 #
3382 # H H n head merge: head count decreases
3384 # H H n head merge: head count decreases
3383
3385
3384 if not opts.get('close_branch'):
3386 if not opts.get('close_branch'):
3385 for r in parents:
3387 for r in parents:
3386 if r.closesbranch() and r.branch() == branch:
3388 if r.closesbranch() and r.branch() == branch:
3387 repo.ui.status(_('reopening closed branch head %d\n') % r)
3389 repo.ui.status(_('reopening closed branch head %d\n') % r)
3388
3390
3389 if repo.ui.debugflag:
3391 if repo.ui.debugflag:
3390 repo.ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
3392 repo.ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
3391 elif repo.ui.verbose:
3393 elif repo.ui.verbose:
3392 repo.ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
3394 repo.ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
3393
3395
3394 def postcommitstatus(repo, pats, opts):
3396 def postcommitstatus(repo, pats, opts):
3395 return repo.status(match=scmutil.match(repo[None], pats, opts))
3397 return repo.status(match=scmutil.match(repo[None], pats, opts))
3396
3398
3397 def revert(ui, repo, ctx, parents, *pats, **opts):
3399 def revert(ui, repo, ctx, parents, *pats, **opts):
3398 opts = pycompat.byteskwargs(opts)
3400 opts = pycompat.byteskwargs(opts)
3399 parent, p2 = parents
3401 parent, p2 = parents
3400 node = ctx.node()
3402 node = ctx.node()
3401
3403
3402 mf = ctx.manifest()
3404 mf = ctx.manifest()
3403 if node == p2:
3405 if node == p2:
3404 parent = p2
3406 parent = p2
3405
3407
3406 # need all matching names in dirstate and manifest of target rev,
3408 # need all matching names in dirstate and manifest of target rev,
3407 # so have to walk both. do not print errors if files exist in one
3409 # so have to walk both. do not print errors if files exist in one
3408 # but not other. in both cases, filesets should be evaluated against
3410 # but not other. in both cases, filesets should be evaluated against
3409 # workingctx to get consistent result (issue4497). this means 'set:**'
3411 # workingctx to get consistent result (issue4497). this means 'set:**'
3410 # cannot be used to select missing files from target rev.
3412 # cannot be used to select missing files from target rev.
3411
3413
3412 # `names` is a mapping for all elements in working copy and target revision
3414 # `names` is a mapping for all elements in working copy and target revision
3413 # The mapping is in the form:
3415 # The mapping is in the form:
3414 # <asb path in repo> -> (<path from CWD>, <exactly specified by matcher?>)
3416 # <asb path in repo> -> (<path from CWD>, <exactly specified by matcher?>)
3415 names = {}
3417 names = {}
3416
3418
3417 with repo.wlock():
3419 with repo.wlock():
3418 ## filling of the `names` mapping
3420 ## filling of the `names` mapping
3419 # walk dirstate to fill `names`
3421 # walk dirstate to fill `names`
3420
3422
3421 interactive = opts.get('interactive', False)
3423 interactive = opts.get('interactive', False)
3422 wctx = repo[None]
3424 wctx = repo[None]
3423 m = scmutil.match(wctx, pats, opts)
3425 m = scmutil.match(wctx, pats, opts)
3424
3426
3425 # we'll need this later
3427 # we'll need this later
3426 targetsubs = sorted(s for s in wctx.substate if m(s))
3428 targetsubs = sorted(s for s in wctx.substate if m(s))
3427
3429
3428 if not m.always():
3430 if not m.always():
3429 matcher = matchmod.badmatch(m, lambda x, y: False)
3431 matcher = matchmod.badmatch(m, lambda x, y: False)
3430 for abs in wctx.walk(matcher):
3432 for abs in wctx.walk(matcher):
3431 names[abs] = m.rel(abs), m.exact(abs)
3433 names[abs] = m.rel(abs), m.exact(abs)
3432
3434
3433 # walk target manifest to fill `names`
3435 # walk target manifest to fill `names`
3434
3436
3435 def badfn(path, msg):
3437 def badfn(path, msg):
3436 if path in names:
3438 if path in names:
3437 return
3439 return
3438 if path in ctx.substate:
3440 if path in ctx.substate:
3439 return
3441 return
3440 path_ = path + '/'
3442 path_ = path + '/'
3441 for f in names:
3443 for f in names:
3442 if f.startswith(path_):
3444 if f.startswith(path_):
3443 return
3445 return
3444 ui.warn("%s: %s\n" % (m.rel(path), msg))
3446 ui.warn("%s: %s\n" % (m.rel(path), msg))
3445
3447
3446 for abs in ctx.walk(matchmod.badmatch(m, badfn)):
3448 for abs in ctx.walk(matchmod.badmatch(m, badfn)):
3447 if abs not in names:
3449 if abs not in names:
3448 names[abs] = m.rel(abs), m.exact(abs)
3450 names[abs] = m.rel(abs), m.exact(abs)
3449
3451
3450 # Find status of all file in `names`.
3452 # Find status of all file in `names`.
3451 m = scmutil.matchfiles(repo, names)
3453 m = scmutil.matchfiles(repo, names)
3452
3454
3453 changes = repo.status(node1=node, match=m,
3455 changes = repo.status(node1=node, match=m,
3454 unknown=True, ignored=True, clean=True)
3456 unknown=True, ignored=True, clean=True)
3455 else:
3457 else:
3456 changes = repo.status(node1=node, match=m)
3458 changes = repo.status(node1=node, match=m)
3457 for kind in changes:
3459 for kind in changes:
3458 for abs in kind:
3460 for abs in kind:
3459 names[abs] = m.rel(abs), m.exact(abs)
3461 names[abs] = m.rel(abs), m.exact(abs)
3460
3462
3461 m = scmutil.matchfiles(repo, names)
3463 m = scmutil.matchfiles(repo, names)
3462
3464
3463 modified = set(changes.modified)
3465 modified = set(changes.modified)
3464 added = set(changes.added)
3466 added = set(changes.added)
3465 removed = set(changes.removed)
3467 removed = set(changes.removed)
3466 _deleted = set(changes.deleted)
3468 _deleted = set(changes.deleted)
3467 unknown = set(changes.unknown)
3469 unknown = set(changes.unknown)
3468 unknown.update(changes.ignored)
3470 unknown.update(changes.ignored)
3469 clean = set(changes.clean)
3471 clean = set(changes.clean)
3470 modadded = set()
3472 modadded = set()
3471
3473
3472 # We need to account for the state of the file in the dirstate,
3474 # We need to account for the state of the file in the dirstate,
3473 # even when we revert against something else than parent. This will
3475 # even when we revert against something else than parent. This will
3474 # slightly alter the behavior of revert (doing back up or not, delete
3476 # slightly alter the behavior of revert (doing back up or not, delete
3475 # or just forget etc).
3477 # or just forget etc).
3476 if parent == node:
3478 if parent == node:
3477 dsmodified = modified
3479 dsmodified = modified
3478 dsadded = added
3480 dsadded = added
3479 dsremoved = removed
3481 dsremoved = removed
3480 # store all local modifications, useful later for rename detection
3482 # store all local modifications, useful later for rename detection
3481 localchanges = dsmodified | dsadded
3483 localchanges = dsmodified | dsadded
3482 modified, added, removed = set(), set(), set()
3484 modified, added, removed = set(), set(), set()
3483 else:
3485 else:
3484 changes = repo.status(node1=parent, match=m)
3486 changes = repo.status(node1=parent, match=m)
3485 dsmodified = set(changes.modified)
3487 dsmodified = set(changes.modified)
3486 dsadded = set(changes.added)
3488 dsadded = set(changes.added)
3487 dsremoved = set(changes.removed)
3489 dsremoved = set(changes.removed)
3488 # store all local modifications, useful later for rename detection
3490 # store all local modifications, useful later for rename detection
3489 localchanges = dsmodified | dsadded
3491 localchanges = dsmodified | dsadded
3490
3492
3491 # only take into account for removes between wc and target
3493 # only take into account for removes between wc and target
3492 clean |= dsremoved - removed
3494 clean |= dsremoved - removed
3493 dsremoved &= removed
3495 dsremoved &= removed
3494 # distinct between dirstate remove and other
3496 # distinct between dirstate remove and other
3495 removed -= dsremoved
3497 removed -= dsremoved
3496
3498
3497 modadded = added & dsmodified
3499 modadded = added & dsmodified
3498 added -= modadded
3500 added -= modadded
3499
3501
3500 # tell newly modified apart.
3502 # tell newly modified apart.
3501 dsmodified &= modified
3503 dsmodified &= modified
3502 dsmodified |= modified & dsadded # dirstate added may need backup
3504 dsmodified |= modified & dsadded # dirstate added may need backup
3503 modified -= dsmodified
3505 modified -= dsmodified
3504
3506
3505 # We need to wait for some post-processing to update this set
3507 # We need to wait for some post-processing to update this set
3506 # before making the distinction. The dirstate will be used for
3508 # before making the distinction. The dirstate will be used for
3507 # that purpose.
3509 # that purpose.
3508 dsadded = added
3510 dsadded = added
3509
3511
3510 # in case of merge, files that are actually added can be reported as
3512 # in case of merge, files that are actually added can be reported as
3511 # modified, we need to post process the result
3513 # modified, we need to post process the result
3512 if p2 != nullid:
3514 if p2 != nullid:
3513 mergeadd = set(dsmodified)
3515 mergeadd = set(dsmodified)
3514 for path in dsmodified:
3516 for path in dsmodified:
3515 if path in mf:
3517 if path in mf:
3516 mergeadd.remove(path)
3518 mergeadd.remove(path)
3517 dsadded |= mergeadd
3519 dsadded |= mergeadd
3518 dsmodified -= mergeadd
3520 dsmodified -= mergeadd
3519
3521
3520 # if f is a rename, update `names` to also revert the source
3522 # if f is a rename, update `names` to also revert the source
3521 cwd = repo.getcwd()
3523 cwd = repo.getcwd()
3522 for f in localchanges:
3524 for f in localchanges:
3523 src = repo.dirstate.copied(f)
3525 src = repo.dirstate.copied(f)
3524 # XXX should we check for rename down to target node?
3526 # XXX should we check for rename down to target node?
3525 if src and src not in names and repo.dirstate[src] == 'r':
3527 if src and src not in names and repo.dirstate[src] == 'r':
3526 dsremoved.add(src)
3528 dsremoved.add(src)
3527 names[src] = (repo.pathto(src, cwd), True)
3529 names[src] = (repo.pathto(src, cwd), True)
3528
3530
3529 # determine the exact nature of the deleted changesets
3531 # determine the exact nature of the deleted changesets
3530 deladded = set(_deleted)
3532 deladded = set(_deleted)
3531 for path in _deleted:
3533 for path in _deleted:
3532 if path in mf:
3534 if path in mf:
3533 deladded.remove(path)
3535 deladded.remove(path)
3534 deleted = _deleted - deladded
3536 deleted = _deleted - deladded
3535
3537
3536 # distinguish between file to forget and the other
3538 # distinguish between file to forget and the other
3537 added = set()
3539 added = set()
3538 for abs in dsadded:
3540 for abs in dsadded:
3539 if repo.dirstate[abs] != 'a':
3541 if repo.dirstate[abs] != 'a':
3540 added.add(abs)
3542 added.add(abs)
3541 dsadded -= added
3543 dsadded -= added
3542
3544
3543 for abs in deladded:
3545 for abs in deladded:
3544 if repo.dirstate[abs] == 'a':
3546 if repo.dirstate[abs] == 'a':
3545 dsadded.add(abs)
3547 dsadded.add(abs)
3546 deladded -= dsadded
3548 deladded -= dsadded
3547
3549
3548 # For files marked as removed, we check if an unknown file is present at
3550 # For files marked as removed, we check if an unknown file is present at
3549 # the same path. If a such file exists it may need to be backed up.
3551 # the same path. If a such file exists it may need to be backed up.
3550 # Making the distinction at this stage helps have simpler backup
3552 # Making the distinction at this stage helps have simpler backup
3551 # logic.
3553 # logic.
3552 removunk = set()
3554 removunk = set()
3553 for abs in removed:
3555 for abs in removed:
3554 target = repo.wjoin(abs)
3556 target = repo.wjoin(abs)
3555 if os.path.lexists(target):
3557 if os.path.lexists(target):
3556 removunk.add(abs)
3558 removunk.add(abs)
3557 removed -= removunk
3559 removed -= removunk
3558
3560
3559 dsremovunk = set()
3561 dsremovunk = set()
3560 for abs in dsremoved:
3562 for abs in dsremoved:
3561 target = repo.wjoin(abs)
3563 target = repo.wjoin(abs)
3562 if os.path.lexists(target):
3564 if os.path.lexists(target):
3563 dsremovunk.add(abs)
3565 dsremovunk.add(abs)
3564 dsremoved -= dsremovunk
3566 dsremoved -= dsremovunk
3565
3567
3566 # action to be actually performed by revert
3568 # action to be actually performed by revert
3567 # (<list of file>, message>) tuple
3569 # (<list of file>, message>) tuple
3568 actions = {'revert': ([], _('reverting %s\n')),
3570 actions = {'revert': ([], _('reverting %s\n')),
3569 'add': ([], _('adding %s\n')),
3571 'add': ([], _('adding %s\n')),
3570 'remove': ([], _('removing %s\n')),
3572 'remove': ([], _('removing %s\n')),
3571 'drop': ([], _('removing %s\n')),
3573 'drop': ([], _('removing %s\n')),
3572 'forget': ([], _('forgetting %s\n')),
3574 'forget': ([], _('forgetting %s\n')),
3573 'undelete': ([], _('undeleting %s\n')),
3575 'undelete': ([], _('undeleting %s\n')),
3574 'noop': (None, _('no changes needed to %s\n')),
3576 'noop': (None, _('no changes needed to %s\n')),
3575 'unknown': (None, _('file not managed: %s\n')),
3577 'unknown': (None, _('file not managed: %s\n')),
3576 }
3578 }
3577
3579
3578 # "constant" that convey the backup strategy.
3580 # "constant" that convey the backup strategy.
3579 # All set to `discard` if `no-backup` is set do avoid checking
3581 # All set to `discard` if `no-backup` is set do avoid checking
3580 # no_backup lower in the code.
3582 # no_backup lower in the code.
3581 # These values are ordered for comparison purposes
3583 # These values are ordered for comparison purposes
3582 backupinteractive = 3 # do backup if interactively modified
3584 backupinteractive = 3 # do backup if interactively modified
3583 backup = 2 # unconditionally do backup
3585 backup = 2 # unconditionally do backup
3584 check = 1 # check if the existing file differs from target
3586 check = 1 # check if the existing file differs from target
3585 discard = 0 # never do backup
3587 discard = 0 # never do backup
3586 if opts.get('no_backup'):
3588 if opts.get('no_backup'):
3587 backupinteractive = backup = check = discard
3589 backupinteractive = backup = check = discard
3588 if interactive:
3590 if interactive:
3589 dsmodifiedbackup = backupinteractive
3591 dsmodifiedbackup = backupinteractive
3590 else:
3592 else:
3591 dsmodifiedbackup = backup
3593 dsmodifiedbackup = backup
3592 tobackup = set()
3594 tobackup = set()
3593
3595
3594 backupanddel = actions['remove']
3596 backupanddel = actions['remove']
3595 if not opts.get('no_backup'):
3597 if not opts.get('no_backup'):
3596 backupanddel = actions['drop']
3598 backupanddel = actions['drop']
3597
3599
3598 disptable = (
3600 disptable = (
3599 # dispatch table:
3601 # dispatch table:
3600 # file state
3602 # file state
3601 # action
3603 # action
3602 # make backup
3604 # make backup
3603
3605
3604 ## Sets that results that will change file on disk
3606 ## Sets that results that will change file on disk
3605 # Modified compared to target, no local change
3607 # Modified compared to target, no local change
3606 (modified, actions['revert'], discard),
3608 (modified, actions['revert'], discard),
3607 # Modified compared to target, but local file is deleted
3609 # Modified compared to target, but local file is deleted
3608 (deleted, actions['revert'], discard),
3610 (deleted, actions['revert'], discard),
3609 # Modified compared to target, local change
3611 # Modified compared to target, local change
3610 (dsmodified, actions['revert'], dsmodifiedbackup),
3612 (dsmodified, actions['revert'], dsmodifiedbackup),
3611 # Added since target
3613 # Added since target
3612 (added, actions['remove'], discard),
3614 (added, actions['remove'], discard),
3613 # Added in working directory
3615 # Added in working directory
3614 (dsadded, actions['forget'], discard),
3616 (dsadded, actions['forget'], discard),
3615 # Added since target, have local modification
3617 # Added since target, have local modification
3616 (modadded, backupanddel, backup),
3618 (modadded, backupanddel, backup),
3617 # Added since target but file is missing in working directory
3619 # Added since target but file is missing in working directory
3618 (deladded, actions['drop'], discard),
3620 (deladded, actions['drop'], discard),
3619 # Removed since target, before working copy parent
3621 # Removed since target, before working copy parent
3620 (removed, actions['add'], discard),
3622 (removed, actions['add'], discard),
3621 # Same as `removed` but an unknown file exists at the same path
3623 # Same as `removed` but an unknown file exists at the same path
3622 (removunk, actions['add'], check),
3624 (removunk, actions['add'], check),
3623 # Removed since targe, marked as such in working copy parent
3625 # Removed since targe, marked as such in working copy parent
3624 (dsremoved, actions['undelete'], discard),
3626 (dsremoved, actions['undelete'], discard),
3625 # Same as `dsremoved` but an unknown file exists at the same path
3627 # Same as `dsremoved` but an unknown file exists at the same path
3626 (dsremovunk, actions['undelete'], check),
3628 (dsremovunk, actions['undelete'], check),
3627 ## the following sets does not result in any file changes
3629 ## the following sets does not result in any file changes
3628 # File with no modification
3630 # File with no modification
3629 (clean, actions['noop'], discard),
3631 (clean, actions['noop'], discard),
3630 # Existing file, not tracked anywhere
3632 # Existing file, not tracked anywhere
3631 (unknown, actions['unknown'], discard),
3633 (unknown, actions['unknown'], discard),
3632 )
3634 )
3633
3635
3634 for abs, (rel, exact) in sorted(names.items()):
3636 for abs, (rel, exact) in sorted(names.items()):
3635 # target file to be touch on disk (relative to cwd)
3637 # target file to be touch on disk (relative to cwd)
3636 target = repo.wjoin(abs)
3638 target = repo.wjoin(abs)
3637 # search the entry in the dispatch table.
3639 # search the entry in the dispatch table.
3638 # if the file is in any of these sets, it was touched in the working
3640 # if the file is in any of these sets, it was touched in the working
3639 # directory parent and we are sure it needs to be reverted.
3641 # directory parent and we are sure it needs to be reverted.
3640 for table, (xlist, msg), dobackup in disptable:
3642 for table, (xlist, msg), dobackup in disptable:
3641 if abs not in table:
3643 if abs not in table:
3642 continue
3644 continue
3643 if xlist is not None:
3645 if xlist is not None:
3644 xlist.append(abs)
3646 xlist.append(abs)
3645 if dobackup:
3647 if dobackup:
3646 # If in interactive mode, don't automatically create
3648 # If in interactive mode, don't automatically create
3647 # .orig files (issue4793)
3649 # .orig files (issue4793)
3648 if dobackup == backupinteractive:
3650 if dobackup == backupinteractive:
3649 tobackup.add(abs)
3651 tobackup.add(abs)
3650 elif (backup <= dobackup or wctx[abs].cmp(ctx[abs])):
3652 elif (backup <= dobackup or wctx[abs].cmp(ctx[abs])):
3651 bakname = scmutil.origpath(ui, repo, rel)
3653 bakname = scmutil.origpath(ui, repo, rel)
3652 ui.note(_('saving current version of %s as %s\n') %
3654 ui.note(_('saving current version of %s as %s\n') %
3653 (rel, bakname))
3655 (rel, bakname))
3654 if not opts.get('dry_run'):
3656 if not opts.get('dry_run'):
3655 if interactive:
3657 if interactive:
3656 util.copyfile(target, bakname)
3658 util.copyfile(target, bakname)
3657 else:
3659 else:
3658 util.rename(target, bakname)
3660 util.rename(target, bakname)
3659 if ui.verbose or not exact:
3661 if ui.verbose or not exact:
3660 if not isinstance(msg, bytes):
3662 if not isinstance(msg, bytes):
3661 msg = msg(abs)
3663 msg = msg(abs)
3662 ui.status(msg % rel)
3664 ui.status(msg % rel)
3663 elif exact:
3665 elif exact:
3664 ui.warn(msg % rel)
3666 ui.warn(msg % rel)
3665 break
3667 break
3666
3668
3667 if not opts.get('dry_run'):
3669 if not opts.get('dry_run'):
3668 needdata = ('revert', 'add', 'undelete')
3670 needdata = ('revert', 'add', 'undelete')
3669 _revertprefetch(repo, ctx, *[actions[name][0] for name in needdata])
3671 _revertprefetch(repo, ctx, *[actions[name][0] for name in needdata])
3670 _performrevert(repo, parents, ctx, actions, interactive, tobackup)
3672 _performrevert(repo, parents, ctx, actions, interactive, tobackup)
3671
3673
3672 if targetsubs:
3674 if targetsubs:
3673 # Revert the subrepos on the revert list
3675 # Revert the subrepos on the revert list
3674 for sub in targetsubs:
3676 for sub in targetsubs:
3675 try:
3677 try:
3676 wctx.sub(sub).revert(ctx.substate[sub], *pats,
3678 wctx.sub(sub).revert(ctx.substate[sub], *pats,
3677 **pycompat.strkwargs(opts))
3679 **pycompat.strkwargs(opts))
3678 except KeyError:
3680 except KeyError:
3679 raise error.Abort("subrepository '%s' does not exist in %s!"
3681 raise error.Abort("subrepository '%s' does not exist in %s!"
3680 % (sub, short(ctx.node())))
3682 % (sub, short(ctx.node())))
3681
3683
3682 def _revertprefetch(repo, ctx, *files):
3684 def _revertprefetch(repo, ctx, *files):
3683 """Let extension changing the storage layer prefetch content"""
3685 """Let extension changing the storage layer prefetch content"""
3684
3686
3685 def _performrevert(repo, parents, ctx, actions, interactive=False,
3687 def _performrevert(repo, parents, ctx, actions, interactive=False,
3686 tobackup=None):
3688 tobackup=None):
3687 """function that actually perform all the actions computed for revert
3689 """function that actually perform all the actions computed for revert
3688
3690
3689 This is an independent function to let extension to plug in and react to
3691 This is an independent function to let extension to plug in and react to
3690 the imminent revert.
3692 the imminent revert.
3691
3693
3692 Make sure you have the working directory locked when calling this function.
3694 Make sure you have the working directory locked when calling this function.
3693 """
3695 """
3694 parent, p2 = parents
3696 parent, p2 = parents
3695 node = ctx.node()
3697 node = ctx.node()
3696 excluded_files = []
3698 excluded_files = []
3697 matcher_opts = {"exclude": excluded_files}
3699 matcher_opts = {"exclude": excluded_files}
3698
3700
3699 def checkout(f):
3701 def checkout(f):
3700 fc = ctx[f]
3702 fc = ctx[f]
3701 repo.wwrite(f, fc.data(), fc.flags())
3703 repo.wwrite(f, fc.data(), fc.flags())
3702
3704
3703 def doremove(f):
3705 def doremove(f):
3704 try:
3706 try:
3705 repo.wvfs.unlinkpath(f)
3707 repo.wvfs.unlinkpath(f)
3706 except OSError:
3708 except OSError:
3707 pass
3709 pass
3708 repo.dirstate.remove(f)
3710 repo.dirstate.remove(f)
3709
3711
3710 audit_path = pathutil.pathauditor(repo.root, cached=True)
3712 audit_path = pathutil.pathauditor(repo.root, cached=True)
3711 for f in actions['forget'][0]:
3713 for f in actions['forget'][0]:
3712 if interactive:
3714 if interactive:
3713 choice = repo.ui.promptchoice(
3715 choice = repo.ui.promptchoice(
3714 _("forget added file %s (Yn)?$$ &Yes $$ &No") % f)
3716 _("forget added file %s (Yn)?$$ &Yes $$ &No") % f)
3715 if choice == 0:
3717 if choice == 0:
3716 repo.dirstate.drop(f)
3718 repo.dirstate.drop(f)
3717 else:
3719 else:
3718 excluded_files.append(repo.wjoin(f))
3720 excluded_files.append(repo.wjoin(f))
3719 else:
3721 else:
3720 repo.dirstate.drop(f)
3722 repo.dirstate.drop(f)
3721 for f in actions['remove'][0]:
3723 for f in actions['remove'][0]:
3722 audit_path(f)
3724 audit_path(f)
3723 if interactive:
3725 if interactive:
3724 choice = repo.ui.promptchoice(
3726 choice = repo.ui.promptchoice(
3725 _("remove added file %s (Yn)?$$ &Yes $$ &No") % f)
3727 _("remove added file %s (Yn)?$$ &Yes $$ &No") % f)
3726 if choice == 0:
3728 if choice == 0:
3727 doremove(f)
3729 doremove(f)
3728 else:
3730 else:
3729 excluded_files.append(repo.wjoin(f))
3731 excluded_files.append(repo.wjoin(f))
3730 else:
3732 else:
3731 doremove(f)
3733 doremove(f)
3732 for f in actions['drop'][0]:
3734 for f in actions['drop'][0]:
3733 audit_path(f)
3735 audit_path(f)
3734 repo.dirstate.remove(f)
3736 repo.dirstate.remove(f)
3735
3737
3736 normal = None
3738 normal = None
3737 if node == parent:
3739 if node == parent:
3738 # We're reverting to our parent. If possible, we'd like status
3740 # We're reverting to our parent. If possible, we'd like status
3739 # to report the file as clean. We have to use normallookup for
3741 # to report the file as clean. We have to use normallookup for
3740 # merges to avoid losing information about merged/dirty files.
3742 # merges to avoid losing information about merged/dirty files.
3741 if p2 != nullid:
3743 if p2 != nullid:
3742 normal = repo.dirstate.normallookup
3744 normal = repo.dirstate.normallookup
3743 else:
3745 else:
3744 normal = repo.dirstate.normal
3746 normal = repo.dirstate.normal
3745
3747
3746 newlyaddedandmodifiedfiles = set()
3748 newlyaddedandmodifiedfiles = set()
3747 if interactive:
3749 if interactive:
3748 # Prompt the user for changes to revert
3750 # Prompt the user for changes to revert
3749 torevert = [repo.wjoin(f) for f in actions['revert'][0]]
3751 torevert = [repo.wjoin(f) for f in actions['revert'][0]]
3750 m = scmutil.match(ctx, torevert, matcher_opts)
3752 m = scmutil.match(ctx, torevert, matcher_opts)
3751 diffopts = patch.difffeatureopts(repo.ui, whitespace=True)
3753 diffopts = patch.difffeatureopts(repo.ui, whitespace=True)
3752 diffopts.nodates = True
3754 diffopts.nodates = True
3753 diffopts.git = True
3755 diffopts.git = True
3754 operation = 'discard'
3756 operation = 'discard'
3755 reversehunks = True
3757 reversehunks = True
3756 if node != parent:
3758 if node != parent:
3757 operation = 'apply'
3759 operation = 'apply'
3758 reversehunks = False
3760 reversehunks = False
3759 if reversehunks:
3761 if reversehunks:
3760 diff = patch.diff(repo, ctx.node(), None, m, opts=diffopts)
3762 diff = patch.diff(repo, ctx.node(), None, m, opts=diffopts)
3761 else:
3763 else:
3762 diff = patch.diff(repo, None, ctx.node(), m, opts=diffopts)
3764 diff = patch.diff(repo, None, ctx.node(), m, opts=diffopts)
3763 originalchunks = patch.parsepatch(diff)
3765 originalchunks = patch.parsepatch(diff)
3764
3766
3765 try:
3767 try:
3766
3768
3767 chunks, opts = recordfilter(repo.ui, originalchunks,
3769 chunks, opts = recordfilter(repo.ui, originalchunks,
3768 operation=operation)
3770 operation=operation)
3769 if reversehunks:
3771 if reversehunks:
3770 chunks = patch.reversehunks(chunks)
3772 chunks = patch.reversehunks(chunks)
3771
3773
3772 except error.PatchError as err:
3774 except error.PatchError as err:
3773 raise error.Abort(_('error parsing patch: %s') % err)
3775 raise error.Abort(_('error parsing patch: %s') % err)
3774
3776
3775 newlyaddedandmodifiedfiles = newandmodified(chunks, originalchunks)
3777 newlyaddedandmodifiedfiles = newandmodified(chunks, originalchunks)
3776 if tobackup is None:
3778 if tobackup is None:
3777 tobackup = set()
3779 tobackup = set()
3778 # Apply changes
3780 # Apply changes
3779 fp = stringio()
3781 fp = stringio()
3780 for c in chunks:
3782 for c in chunks:
3781 # Create a backup file only if this hunk should be backed up
3783 # Create a backup file only if this hunk should be backed up
3782 if ishunk(c) and c.header.filename() in tobackup:
3784 if ishunk(c) and c.header.filename() in tobackup:
3783 abs = c.header.filename()
3785 abs = c.header.filename()
3784 target = repo.wjoin(abs)
3786 target = repo.wjoin(abs)
3785 bakname = scmutil.origpath(repo.ui, repo, m.rel(abs))
3787 bakname = scmutil.origpath(repo.ui, repo, m.rel(abs))
3786 util.copyfile(target, bakname)
3788 util.copyfile(target, bakname)
3787 tobackup.remove(abs)
3789 tobackup.remove(abs)
3788 c.write(fp)
3790 c.write(fp)
3789 dopatch = fp.tell()
3791 dopatch = fp.tell()
3790 fp.seek(0)
3792 fp.seek(0)
3791 if dopatch:
3793 if dopatch:
3792 try:
3794 try:
3793 patch.internalpatch(repo.ui, repo, fp, 1, eolmode=None)
3795 patch.internalpatch(repo.ui, repo, fp, 1, eolmode=None)
3794 except error.PatchError as err:
3796 except error.PatchError as err:
3795 raise error.Abort(str(err))
3797 raise error.Abort(str(err))
3796 del fp
3798 del fp
3797 else:
3799 else:
3798 for f in actions['revert'][0]:
3800 for f in actions['revert'][0]:
3799 checkout(f)
3801 checkout(f)
3800 if normal:
3802 if normal:
3801 normal(f)
3803 normal(f)
3802
3804
3803 for f in actions['add'][0]:
3805 for f in actions['add'][0]:
3804 # Don't checkout modified files, they are already created by the diff
3806 # Don't checkout modified files, they are already created by the diff
3805 if f not in newlyaddedandmodifiedfiles:
3807 if f not in newlyaddedandmodifiedfiles:
3806 checkout(f)
3808 checkout(f)
3807 repo.dirstate.add(f)
3809 repo.dirstate.add(f)
3808
3810
3809 normal = repo.dirstate.normallookup
3811 normal = repo.dirstate.normallookup
3810 if node == parent and p2 == nullid:
3812 if node == parent and p2 == nullid:
3811 normal = repo.dirstate.normal
3813 normal = repo.dirstate.normal
3812 for f in actions['undelete'][0]:
3814 for f in actions['undelete'][0]:
3813 checkout(f)
3815 checkout(f)
3814 normal(f)
3816 normal(f)
3815
3817
3816 copied = copies.pathcopies(repo[parent], ctx)
3818 copied = copies.pathcopies(repo[parent], ctx)
3817
3819
3818 for f in actions['add'][0] + actions['undelete'][0] + actions['revert'][0]:
3820 for f in actions['add'][0] + actions['undelete'][0] + actions['revert'][0]:
3819 if f in copied:
3821 if f in copied:
3820 repo.dirstate.copy(copied[f], f)
3822 repo.dirstate.copy(copied[f], f)
3821
3823
3822 class command(registrar.command):
3824 class command(registrar.command):
3823 """deprecated: used registrar.command instead"""
3825 """deprecated: used registrar.command instead"""
3824 def _doregister(self, func, name, *args, **kwargs):
3826 def _doregister(self, func, name, *args, **kwargs):
3825 func._deprecatedregistrar = True # flag for deprecwarn in extensions.py
3827 func._deprecatedregistrar = True # flag for deprecwarn in extensions.py
3826 return super(command, self)._doregister(func, name, *args, **kwargs)
3828 return super(command, self)._doregister(func, name, *args, **kwargs)
3827
3829
3828 # a list of (ui, repo, otherpeer, opts, missing) functions called by
3830 # a list of (ui, repo, otherpeer, opts, missing) functions called by
3829 # commands.outgoing. "missing" is "missing" of the result of
3831 # commands.outgoing. "missing" is "missing" of the result of
3830 # "findcommonoutgoing()"
3832 # "findcommonoutgoing()"
3831 outgoinghooks = util.hooks()
3833 outgoinghooks = util.hooks()
3832
3834
3833 # a list of (ui, repo) functions called by commands.summary
3835 # a list of (ui, repo) functions called by commands.summary
3834 summaryhooks = util.hooks()
3836 summaryhooks = util.hooks()
3835
3837
3836 # a list of (ui, repo, opts, changes) functions called by commands.summary.
3838 # a list of (ui, repo, opts, changes) functions called by commands.summary.
3837 #
3839 #
3838 # functions should return tuple of booleans below, if 'changes' is None:
3840 # functions should return tuple of booleans below, if 'changes' is None:
3839 # (whether-incomings-are-needed, whether-outgoings-are-needed)
3841 # (whether-incomings-are-needed, whether-outgoings-are-needed)
3840 #
3842 #
3841 # otherwise, 'changes' is a tuple of tuples below:
3843 # otherwise, 'changes' is a tuple of tuples below:
3842 # - (sourceurl, sourcebranch, sourcepeer, incoming)
3844 # - (sourceurl, sourcebranch, sourcepeer, incoming)
3843 # - (desturl, destbranch, destpeer, outgoing)
3845 # - (desturl, destbranch, destpeer, outgoing)
3844 summaryremotehooks = util.hooks()
3846 summaryremotehooks = util.hooks()
3845
3847
3846 # A list of state files kept by multistep operations like graft.
3848 # A list of state files kept by multistep operations like graft.
3847 # Since graft cannot be aborted, it is considered 'clearable' by update.
3849 # Since graft cannot be aborted, it is considered 'clearable' by update.
3848 # note: bisect is intentionally excluded
3850 # note: bisect is intentionally excluded
3849 # (state file, clearable, allowcommit, error, hint)
3851 # (state file, clearable, allowcommit, error, hint)
3850 unfinishedstates = [
3852 unfinishedstates = [
3851 ('graftstate', True, False, _('graft in progress'),
3853 ('graftstate', True, False, _('graft in progress'),
3852 _("use 'hg graft --continue' or 'hg update' to abort")),
3854 _("use 'hg graft --continue' or 'hg update' to abort")),
3853 ('updatestate', True, False, _('last update was interrupted'),
3855 ('updatestate', True, False, _('last update was interrupted'),
3854 _("use 'hg update' to get a consistent checkout"))
3856 _("use 'hg update' to get a consistent checkout"))
3855 ]
3857 ]
3856
3858
3857 def checkunfinished(repo, commit=False):
3859 def checkunfinished(repo, commit=False):
3858 '''Look for an unfinished multistep operation, like graft, and abort
3860 '''Look for an unfinished multistep operation, like graft, and abort
3859 if found. It's probably good to check this right before
3861 if found. It's probably good to check this right before
3860 bailifchanged().
3862 bailifchanged().
3861 '''
3863 '''
3862 for f, clearable, allowcommit, msg, hint in unfinishedstates:
3864 for f, clearable, allowcommit, msg, hint in unfinishedstates:
3863 if commit and allowcommit:
3865 if commit and allowcommit:
3864 continue
3866 continue
3865 if repo.vfs.exists(f):
3867 if repo.vfs.exists(f):
3866 raise error.Abort(msg, hint=hint)
3868 raise error.Abort(msg, hint=hint)
3867
3869
3868 def clearunfinished(repo):
3870 def clearunfinished(repo):
3869 '''Check for unfinished operations (as above), and clear the ones
3871 '''Check for unfinished operations (as above), and clear the ones
3870 that are clearable.
3872 that are clearable.
3871 '''
3873 '''
3872 for f, clearable, allowcommit, msg, hint in unfinishedstates:
3874 for f, clearable, allowcommit, msg, hint in unfinishedstates:
3873 if not clearable and repo.vfs.exists(f):
3875 if not clearable and repo.vfs.exists(f):
3874 raise error.Abort(msg, hint=hint)
3876 raise error.Abort(msg, hint=hint)
3875 for f, clearable, allowcommit, msg, hint in unfinishedstates:
3877 for f, clearable, allowcommit, msg, hint in unfinishedstates:
3876 if clearable and repo.vfs.exists(f):
3878 if clearable and repo.vfs.exists(f):
3877 util.unlink(repo.vfs.join(f))
3879 util.unlink(repo.vfs.join(f))
3878
3880
3879 afterresolvedstates = [
3881 afterresolvedstates = [
3880 ('graftstate',
3882 ('graftstate',
3881 _('hg graft --continue')),
3883 _('hg graft --continue')),
3882 ]
3884 ]
3883
3885
3884 def howtocontinue(repo):
3886 def howtocontinue(repo):
3885 '''Check for an unfinished operation and return the command to finish
3887 '''Check for an unfinished operation and return the command to finish
3886 it.
3888 it.
3887
3889
3888 afterresolvedstates tuples define a .hg/{file} and the corresponding
3890 afterresolvedstates tuples define a .hg/{file} and the corresponding
3889 command needed to finish it.
3891 command needed to finish it.
3890
3892
3891 Returns a (msg, warning) tuple. 'msg' is a string and 'warning' is
3893 Returns a (msg, warning) tuple. 'msg' is a string and 'warning' is
3892 a boolean.
3894 a boolean.
3893 '''
3895 '''
3894 contmsg = _("continue: %s")
3896 contmsg = _("continue: %s")
3895 for f, msg in afterresolvedstates:
3897 for f, msg in afterresolvedstates:
3896 if repo.vfs.exists(f):
3898 if repo.vfs.exists(f):
3897 return contmsg % msg, True
3899 return contmsg % msg, True
3898 if repo[None].dirty(missing=True, merge=False, branch=False):
3900 if repo[None].dirty(missing=True, merge=False, branch=False):
3899 return contmsg % _("hg commit"), False
3901 return contmsg % _("hg commit"), False
3900 return None, None
3902 return None, None
3901
3903
3902 def checkafterresolved(repo):
3904 def checkafterresolved(repo):
3903 '''Inform the user about the next action after completing hg resolve
3905 '''Inform the user about the next action after completing hg resolve
3904
3906
3905 If there's a matching afterresolvedstates, howtocontinue will yield
3907 If there's a matching afterresolvedstates, howtocontinue will yield
3906 repo.ui.warn as the reporter.
3908 repo.ui.warn as the reporter.
3907
3909
3908 Otherwise, it will yield repo.ui.note.
3910 Otherwise, it will yield repo.ui.note.
3909 '''
3911 '''
3910 msg, warning = howtocontinue(repo)
3912 msg, warning = howtocontinue(repo)
3911 if msg is not None:
3913 if msg is not None:
3912 if warning:
3914 if warning:
3913 repo.ui.warn("%s\n" % msg)
3915 repo.ui.warn("%s\n" % msg)
3914 else:
3916 else:
3915 repo.ui.note("%s\n" % msg)
3917 repo.ui.note("%s\n" % msg)
3916
3918
3917 def wrongtooltocontinue(repo, task):
3919 def wrongtooltocontinue(repo, task):
3918 '''Raise an abort suggesting how to properly continue if there is an
3920 '''Raise an abort suggesting how to properly continue if there is an
3919 active task.
3921 active task.
3920
3922
3921 Uses howtocontinue() to find the active task.
3923 Uses howtocontinue() to find the active task.
3922
3924
3923 If there's no task (repo.ui.note for 'hg commit'), it does not offer
3925 If there's no task (repo.ui.note for 'hg commit'), it does not offer
3924 a hint.
3926 a hint.
3925 '''
3927 '''
3926 after = howtocontinue(repo)
3928 after = howtocontinue(repo)
3927 hint = None
3929 hint = None
3928 if after[1]:
3930 if after[1]:
3929 hint = after[0]
3931 hint = after[0]
3930 raise error.Abort(_('no %s in progress') % task, hint=hint)
3932 raise error.Abort(_('no %s in progress') % task, hint=hint)
@@ -1,3560 +1,3561 b''
1 @ (34) head
1 @ (34) head
2 |
2 |
3 | o (33) head
3 | o (33) head
4 | |
4 | |
5 o | (32) expand
5 o | (32) expand
6 |\ \
6 |\ \
7 | o \ (31) expand
7 | o \ (31) expand
8 | |\ \
8 | |\ \
9 | | o \ (30) expand
9 | | o \ (30) expand
10 | | |\ \
10 | | |\ \
11 | | | o | (29) regular commit
11 | | | o | (29) regular commit
12 | | | | |
12 | | | | |
13 | | o | | (28) merge zero known
13 | | o | | (28) merge zero known
14 | | |\ \ \
14 | | |\ \ \
15 o | | | | | (27) collapse
15 o | | | | | (27) collapse
16 |/ / / / /
16 |/ / / / /
17 | | o---+ (26) merge one known; far right
17 | | o---+ (26) merge one known; far right
18 | | | | |
18 | | | | |
19 +---o | | (25) merge one known; far left
19 +---o | | (25) merge one known; far left
20 | | | | |
20 | | | | |
21 | | o | | (24) merge one known; immediate right
21 | | o | | (24) merge one known; immediate right
22 | | |\| |
22 | | |\| |
23 | | o | | (23) merge one known; immediate left
23 | | o | | (23) merge one known; immediate left
24 | |/| | |
24 | |/| | |
25 +---o---+ (22) merge two known; one far left, one far right
25 +---o---+ (22) merge two known; one far left, one far right
26 | | / /
26 | | / /
27 o | | | (21) expand
27 o | | | (21) expand
28 |\ \ \ \
28 |\ \ \ \
29 | o---+-+ (20) merge two known; two far right
29 | o---+-+ (20) merge two known; two far right
30 | / / /
30 | / / /
31 o | | | (19) expand
31 o | | | (19) expand
32 |\ \ \ \
32 |\ \ \ \
33 +---+---o (18) merge two known; two far left
33 +---+---o (18) merge two known; two far left
34 | | | |
34 | | | |
35 | o | | (17) expand
35 | o | | (17) expand
36 | |\ \ \
36 | |\ \ \
37 | | o---+ (16) merge two known; one immediate right, one near right
37 | | o---+ (16) merge two known; one immediate right, one near right
38 | | |/ /
38 | | |/ /
39 o | | | (15) expand
39 o | | | (15) expand
40 |\ \ \ \
40 |\ \ \ \
41 | o-----+ (14) merge two known; one immediate right, one far right
41 | o-----+ (14) merge two known; one immediate right, one far right
42 | |/ / /
42 | |/ / /
43 o | | | (13) expand
43 o | | | (13) expand
44 |\ \ \ \
44 |\ \ \ \
45 +---o | | (12) merge two known; one immediate right, one far left
45 +---o | | (12) merge two known; one immediate right, one far left
46 | | |/ /
46 | | |/ /
47 | o | | (11) expand
47 | o | | (11) expand
48 | |\ \ \
48 | |\ \ \
49 | | o---+ (10) merge two known; one immediate left, one near right
49 | | o---+ (10) merge two known; one immediate left, one near right
50 | |/ / /
50 | |/ / /
51 o | | | (9) expand
51 o | | | (9) expand
52 |\ \ \ \
52 |\ \ \ \
53 | o-----+ (8) merge two known; one immediate left, one far right
53 | o-----+ (8) merge two known; one immediate left, one far right
54 |/ / / /
54 |/ / / /
55 o | | | (7) expand
55 o | | | (7) expand
56 |\ \ \ \
56 |\ \ \ \
57 +---o | | (6) merge two known; one immediate left, one far left
57 +---o | | (6) merge two known; one immediate left, one far left
58 | |/ / /
58 | |/ / /
59 | o | | (5) expand
59 | o | | (5) expand
60 | |\ \ \
60 | |\ \ \
61 | | o | | (4) merge two known; one immediate left, one immediate right
61 | | o | | (4) merge two known; one immediate left, one immediate right
62 | |/|/ /
62 | |/|/ /
63 | o / / (3) collapse
63 | o / / (3) collapse
64 |/ / /
64 |/ / /
65 o / / (2) collapse
65 o / / (2) collapse
66 |/ /
66 |/ /
67 o / (1) collapse
67 o / (1) collapse
68 |/
68 |/
69 o (0) root
69 o (0) root
70
70
71
71
72 $ commit()
72 $ commit()
73 > {
73 > {
74 > rev=$1
74 > rev=$1
75 > msg=$2
75 > msg=$2
76 > shift 2
76 > shift 2
77 > if [ "$#" -gt 0 ]; then
77 > if [ "$#" -gt 0 ]; then
78 > hg debugsetparents "$@"
78 > hg debugsetparents "$@"
79 > fi
79 > fi
80 > echo $rev > a
80 > echo $rev > a
81 > hg commit -Aqd "$rev 0" -m "($rev) $msg"
81 > hg commit -Aqd "$rev 0" -m "($rev) $msg"
82 > }
82 > }
83
83
84 $ cat > printrevset.py <<EOF
84 $ cat > printrevset.py <<EOF
85 > from __future__ import absolute_import
85 > from __future__ import absolute_import
86 > from mercurial import (
86 > from mercurial import (
87 > cmdutil,
87 > cmdutil,
88 > commands,
88 > commands,
89 > extensions,
89 > extensions,
90 > revsetlang,
90 > revsetlang,
91 > smartset,
91 > smartset,
92 > )
92 > )
93 >
93 >
94 > def logrevset(repo, pats, opts):
94 > def logrevset(repo, pats, opts):
95 > revs = cmdutil._logrevs(repo, opts)
95 > revs = cmdutil._logrevs(repo, opts)
96 > if not revs:
96 > if not revs:
97 > return None
97 > return None
98 > return cmdutil._makelogrevset(repo, pats, opts, revs)[0]
98 > return cmdutil._makelogrevset(repo, pats, opts, revs)[0]
99 >
99 >
100 > def uisetup(ui):
100 > def uisetup(ui):
101 > def printrevset(orig, repo, pats, opts):
101 > def printrevset(orig, repo, pats, opts):
102 > revs, filematcher = orig(repo, pats, opts)
102 > revs, filematcher = orig(repo, pats, opts)
103 > if opts.get('print_revset'):
103 > if opts.get('print_revset'):
104 > expr = logrevset(repo, pats, opts)
104 > expr = logrevset(repo, pats, opts)
105 > if expr:
105 > if expr:
106 > tree = revsetlang.parse(expr)
106 > tree = revsetlang.parse(expr)
107 > tree = revsetlang.analyze(tree)
107 > tree = revsetlang.analyze(tree)
108 > else:
108 > else:
109 > tree = []
109 > tree = []
110 > ui = repo.ui
110 > ui = repo.ui
111 > ui.write('%r\n' % (opts.get('rev', []),))
111 > ui.write('%r\n' % (opts.get('rev', []),))
112 > ui.write(revsetlang.prettyformat(tree) + '\n')
112 > ui.write(revsetlang.prettyformat(tree) + '\n')
113 > ui.write(smartset.prettyformat(revs) + '\n')
113 > ui.write(smartset.prettyformat(revs) + '\n')
114 > revs = smartset.baseset() # display no revisions
114 > revs = smartset.baseset() # display no revisions
115 > return revs, filematcher
115 > return revs, filematcher
116 > extensions.wrapfunction(cmdutil, 'getlogrevs', printrevset)
116 > extensions.wrapfunction(cmdutil, 'getlogrevs', printrevset)
117 > aliases, entry = cmdutil.findcmd('log', commands.table)
117 > aliases, entry = cmdutil.findcmd('log', commands.table)
118 > entry[1].append(('', 'print-revset', False,
118 > entry[1].append(('', 'print-revset', False,
119 > 'print generated revset and exit (DEPRECATED)'))
119 > 'print generated revset and exit (DEPRECATED)'))
120 > EOF
120 > EOF
121
121
122 $ echo "[extensions]" >> $HGRCPATH
122 $ echo "[extensions]" >> $HGRCPATH
123 $ echo "printrevset=`pwd`/printrevset.py" >> $HGRCPATH
123 $ echo "printrevset=`pwd`/printrevset.py" >> $HGRCPATH
124
124
125 $ hg init repo
125 $ hg init repo
126 $ cd repo
126 $ cd repo
127
127
128 Empty repo:
128 Empty repo:
129
129
130 $ hg log -G
130 $ hg log -G
131
131
132
132
133 Building DAG:
133 Building DAG:
134
134
135 $ commit 0 "root"
135 $ commit 0 "root"
136 $ commit 1 "collapse" 0
136 $ commit 1 "collapse" 0
137 $ commit 2 "collapse" 1
137 $ commit 2 "collapse" 1
138 $ commit 3 "collapse" 2
138 $ commit 3 "collapse" 2
139 $ commit 4 "merge two known; one immediate left, one immediate right" 1 3
139 $ commit 4 "merge two known; one immediate left, one immediate right" 1 3
140 $ commit 5 "expand" 3 4
140 $ commit 5 "expand" 3 4
141 $ commit 6 "merge two known; one immediate left, one far left" 2 5
141 $ commit 6 "merge two known; one immediate left, one far left" 2 5
142 $ commit 7 "expand" 2 5
142 $ commit 7 "expand" 2 5
143 $ commit 8 "merge two known; one immediate left, one far right" 0 7
143 $ commit 8 "merge two known; one immediate left, one far right" 0 7
144 $ commit 9 "expand" 7 8
144 $ commit 9 "expand" 7 8
145 $ commit 10 "merge two known; one immediate left, one near right" 0 6
145 $ commit 10 "merge two known; one immediate left, one near right" 0 6
146 $ commit 11 "expand" 6 10
146 $ commit 11 "expand" 6 10
147 $ commit 12 "merge two known; one immediate right, one far left" 1 9
147 $ commit 12 "merge two known; one immediate right, one far left" 1 9
148 $ commit 13 "expand" 9 11
148 $ commit 13 "expand" 9 11
149 $ commit 14 "merge two known; one immediate right, one far right" 0 12
149 $ commit 14 "merge two known; one immediate right, one far right" 0 12
150 $ commit 15 "expand" 13 14
150 $ commit 15 "expand" 13 14
151 $ commit 16 "merge two known; one immediate right, one near right" 0 1
151 $ commit 16 "merge two known; one immediate right, one near right" 0 1
152 $ commit 17 "expand" 12 16
152 $ commit 17 "expand" 12 16
153 $ commit 18 "merge two known; two far left" 1 15
153 $ commit 18 "merge two known; two far left" 1 15
154 $ commit 19 "expand" 15 17
154 $ commit 19 "expand" 15 17
155 $ commit 20 "merge two known; two far right" 0 18
155 $ commit 20 "merge two known; two far right" 0 18
156 $ commit 21 "expand" 19 20
156 $ commit 21 "expand" 19 20
157 $ commit 22 "merge two known; one far left, one far right" 18 21
157 $ commit 22 "merge two known; one far left, one far right" 18 21
158 $ commit 23 "merge one known; immediate left" 1 22
158 $ commit 23 "merge one known; immediate left" 1 22
159 $ commit 24 "merge one known; immediate right" 0 23
159 $ commit 24 "merge one known; immediate right" 0 23
160 $ commit 25 "merge one known; far left" 21 24
160 $ commit 25 "merge one known; far left" 21 24
161 $ commit 26 "merge one known; far right" 18 25
161 $ commit 26 "merge one known; far right" 18 25
162 $ commit 27 "collapse" 21
162 $ commit 27 "collapse" 21
163 $ commit 28 "merge zero known" 1 26
163 $ commit 28 "merge zero known" 1 26
164 $ commit 29 "regular commit" 0
164 $ commit 29 "regular commit" 0
165 $ commit 30 "expand" 28 29
165 $ commit 30 "expand" 28 29
166 $ commit 31 "expand" 21 30
166 $ commit 31 "expand" 21 30
167 $ commit 32 "expand" 27 31
167 $ commit 32 "expand" 27 31
168 $ commit 33 "head" 18
168 $ commit 33 "head" 18
169 $ commit 34 "head" 32
169 $ commit 34 "head" 32
170
170
171
171
172 $ hg log -G -q
172 $ hg log -G -q
173 @ 34:fea3ac5810e0
173 @ 34:fea3ac5810e0
174 |
174 |
175 | o 33:68608f5145f9
175 | o 33:68608f5145f9
176 | |
176 | |
177 o | 32:d06dffa21a31
177 o | 32:d06dffa21a31
178 |\ \
178 |\ \
179 | o \ 31:621d83e11f67
179 | o \ 31:621d83e11f67
180 | |\ \
180 | |\ \
181 | | o \ 30:6e11cd4b648f
181 | | o \ 30:6e11cd4b648f
182 | | |\ \
182 | | |\ \
183 | | | o | 29:cd9bb2be7593
183 | | | o | 29:cd9bb2be7593
184 | | | | |
184 | | | | |
185 | | o | | 28:44ecd0b9ae99
185 | | o | | 28:44ecd0b9ae99
186 | | |\ \ \
186 | | |\ \ \
187 o | | | | | 27:886ed638191b
187 o | | | | | 27:886ed638191b
188 |/ / / / /
188 |/ / / / /
189 | | o---+ 26:7f25b6c2f0b9
189 | | o---+ 26:7f25b6c2f0b9
190 | | | | |
190 | | | | |
191 +---o | | 25:91da8ed57247
191 +---o | | 25:91da8ed57247
192 | | | | |
192 | | | | |
193 | | o | | 24:a9c19a3d96b7
193 | | o | | 24:a9c19a3d96b7
194 | | |\| |
194 | | |\| |
195 | | o | | 23:a01cddf0766d
195 | | o | | 23:a01cddf0766d
196 | |/| | |
196 | |/| | |
197 +---o---+ 22:e0d9cccacb5d
197 +---o---+ 22:e0d9cccacb5d
198 | | / /
198 | | / /
199 o | | | 21:d42a756af44d
199 o | | | 21:d42a756af44d
200 |\ \ \ \
200 |\ \ \ \
201 | o---+-+ 20:d30ed6450e32
201 | o---+-+ 20:d30ed6450e32
202 | / / /
202 | / / /
203 o | | | 19:31ddc2c1573b
203 o | | | 19:31ddc2c1573b
204 |\ \ \ \
204 |\ \ \ \
205 +---+---o 18:1aa84d96232a
205 +---+---o 18:1aa84d96232a
206 | | | |
206 | | | |
207 | o | | 17:44765d7c06e0
207 | o | | 17:44765d7c06e0
208 | |\ \ \
208 | |\ \ \
209 | | o---+ 16:3677d192927d
209 | | o---+ 16:3677d192927d
210 | | |/ /
210 | | |/ /
211 o | | | 15:1dda3f72782d
211 o | | | 15:1dda3f72782d
212 |\ \ \ \
212 |\ \ \ \
213 | o-----+ 14:8eac370358ef
213 | o-----+ 14:8eac370358ef
214 | |/ / /
214 | |/ / /
215 o | | | 13:22d8966a97e3
215 o | | | 13:22d8966a97e3
216 |\ \ \ \
216 |\ \ \ \
217 +---o | | 12:86b91144a6e9
217 +---o | | 12:86b91144a6e9
218 | | |/ /
218 | | |/ /
219 | o | | 11:832d76e6bdf2
219 | o | | 11:832d76e6bdf2
220 | |\ \ \
220 | |\ \ \
221 | | o---+ 10:74c64d036d72
221 | | o---+ 10:74c64d036d72
222 | |/ / /
222 | |/ / /
223 o | | | 9:7010c0af0a35
223 o | | | 9:7010c0af0a35
224 |\ \ \ \
224 |\ \ \ \
225 | o-----+ 8:7a0b11f71937
225 | o-----+ 8:7a0b11f71937
226 |/ / / /
226 |/ / / /
227 o | | | 7:b632bb1b1224
227 o | | | 7:b632bb1b1224
228 |\ \ \ \
228 |\ \ \ \
229 +---o | | 6:b105a072e251
229 +---o | | 6:b105a072e251
230 | |/ / /
230 | |/ / /
231 | o | | 5:4409d547b708
231 | o | | 5:4409d547b708
232 | |\ \ \
232 | |\ \ \
233 | | o | | 4:26a8bac39d9f
233 | | o | | 4:26a8bac39d9f
234 | |/|/ /
234 | |/|/ /
235 | o / / 3:27eef8ed80b4
235 | o / / 3:27eef8ed80b4
236 |/ / /
236 |/ / /
237 o / / 2:3d9a33b8d1e1
237 o / / 2:3d9a33b8d1e1
238 |/ /
238 |/ /
239 o / 1:6db2ef61d156
239 o / 1:6db2ef61d156
240 |/
240 |/
241 o 0:e6eb3150255d
241 o 0:e6eb3150255d
242
242
243
243
244 $ hg log -G
244 $ hg log -G
245 @ changeset: 34:fea3ac5810e0
245 @ changeset: 34:fea3ac5810e0
246 | tag: tip
246 | tag: tip
247 | parent: 32:d06dffa21a31
247 | parent: 32:d06dffa21a31
248 | user: test
248 | user: test
249 | date: Thu Jan 01 00:00:34 1970 +0000
249 | date: Thu Jan 01 00:00:34 1970 +0000
250 | summary: (34) head
250 | summary: (34) head
251 |
251 |
252 | o changeset: 33:68608f5145f9
252 | o changeset: 33:68608f5145f9
253 | | parent: 18:1aa84d96232a
253 | | parent: 18:1aa84d96232a
254 | | user: test
254 | | user: test
255 | | date: Thu Jan 01 00:00:33 1970 +0000
255 | | date: Thu Jan 01 00:00:33 1970 +0000
256 | | summary: (33) head
256 | | summary: (33) head
257 | |
257 | |
258 o | changeset: 32:d06dffa21a31
258 o | changeset: 32:d06dffa21a31
259 |\ \ parent: 27:886ed638191b
259 |\ \ parent: 27:886ed638191b
260 | | | parent: 31:621d83e11f67
260 | | | parent: 31:621d83e11f67
261 | | | user: test
261 | | | user: test
262 | | | date: Thu Jan 01 00:00:32 1970 +0000
262 | | | date: Thu Jan 01 00:00:32 1970 +0000
263 | | | summary: (32) expand
263 | | | summary: (32) expand
264 | | |
264 | | |
265 | o | changeset: 31:621d83e11f67
265 | o | changeset: 31:621d83e11f67
266 | |\ \ parent: 21:d42a756af44d
266 | |\ \ parent: 21:d42a756af44d
267 | | | | parent: 30:6e11cd4b648f
267 | | | | parent: 30:6e11cd4b648f
268 | | | | user: test
268 | | | | user: test
269 | | | | date: Thu Jan 01 00:00:31 1970 +0000
269 | | | | date: Thu Jan 01 00:00:31 1970 +0000
270 | | | | summary: (31) expand
270 | | | | summary: (31) expand
271 | | | |
271 | | | |
272 | | o | changeset: 30:6e11cd4b648f
272 | | o | changeset: 30:6e11cd4b648f
273 | | |\ \ parent: 28:44ecd0b9ae99
273 | | |\ \ parent: 28:44ecd0b9ae99
274 | | | | | parent: 29:cd9bb2be7593
274 | | | | | parent: 29:cd9bb2be7593
275 | | | | | user: test
275 | | | | | user: test
276 | | | | | date: Thu Jan 01 00:00:30 1970 +0000
276 | | | | | date: Thu Jan 01 00:00:30 1970 +0000
277 | | | | | summary: (30) expand
277 | | | | | summary: (30) expand
278 | | | | |
278 | | | | |
279 | | | o | changeset: 29:cd9bb2be7593
279 | | | o | changeset: 29:cd9bb2be7593
280 | | | | | parent: 0:e6eb3150255d
280 | | | | | parent: 0:e6eb3150255d
281 | | | | | user: test
281 | | | | | user: test
282 | | | | | date: Thu Jan 01 00:00:29 1970 +0000
282 | | | | | date: Thu Jan 01 00:00:29 1970 +0000
283 | | | | | summary: (29) regular commit
283 | | | | | summary: (29) regular commit
284 | | | | |
284 | | | | |
285 | | o | | changeset: 28:44ecd0b9ae99
285 | | o | | changeset: 28:44ecd0b9ae99
286 | | |\ \ \ parent: 1:6db2ef61d156
286 | | |\ \ \ parent: 1:6db2ef61d156
287 | | | | | | parent: 26:7f25b6c2f0b9
287 | | | | | | parent: 26:7f25b6c2f0b9
288 | | | | | | user: test
288 | | | | | | user: test
289 | | | | | | date: Thu Jan 01 00:00:28 1970 +0000
289 | | | | | | date: Thu Jan 01 00:00:28 1970 +0000
290 | | | | | | summary: (28) merge zero known
290 | | | | | | summary: (28) merge zero known
291 | | | | | |
291 | | | | | |
292 o | | | | | changeset: 27:886ed638191b
292 o | | | | | changeset: 27:886ed638191b
293 |/ / / / / parent: 21:d42a756af44d
293 |/ / / / / parent: 21:d42a756af44d
294 | | | | | user: test
294 | | | | | user: test
295 | | | | | date: Thu Jan 01 00:00:27 1970 +0000
295 | | | | | date: Thu Jan 01 00:00:27 1970 +0000
296 | | | | | summary: (27) collapse
296 | | | | | summary: (27) collapse
297 | | | | |
297 | | | | |
298 | | o---+ changeset: 26:7f25b6c2f0b9
298 | | o---+ changeset: 26:7f25b6c2f0b9
299 | | | | | parent: 18:1aa84d96232a
299 | | | | | parent: 18:1aa84d96232a
300 | | | | | parent: 25:91da8ed57247
300 | | | | | parent: 25:91da8ed57247
301 | | | | | user: test
301 | | | | | user: test
302 | | | | | date: Thu Jan 01 00:00:26 1970 +0000
302 | | | | | date: Thu Jan 01 00:00:26 1970 +0000
303 | | | | | summary: (26) merge one known; far right
303 | | | | | summary: (26) merge one known; far right
304 | | | | |
304 | | | | |
305 +---o | | changeset: 25:91da8ed57247
305 +---o | | changeset: 25:91da8ed57247
306 | | | | | parent: 21:d42a756af44d
306 | | | | | parent: 21:d42a756af44d
307 | | | | | parent: 24:a9c19a3d96b7
307 | | | | | parent: 24:a9c19a3d96b7
308 | | | | | user: test
308 | | | | | user: test
309 | | | | | date: Thu Jan 01 00:00:25 1970 +0000
309 | | | | | date: Thu Jan 01 00:00:25 1970 +0000
310 | | | | | summary: (25) merge one known; far left
310 | | | | | summary: (25) merge one known; far left
311 | | | | |
311 | | | | |
312 | | o | | changeset: 24:a9c19a3d96b7
312 | | o | | changeset: 24:a9c19a3d96b7
313 | | |\| | parent: 0:e6eb3150255d
313 | | |\| | parent: 0:e6eb3150255d
314 | | | | | parent: 23:a01cddf0766d
314 | | | | | parent: 23:a01cddf0766d
315 | | | | | user: test
315 | | | | | user: test
316 | | | | | date: Thu Jan 01 00:00:24 1970 +0000
316 | | | | | date: Thu Jan 01 00:00:24 1970 +0000
317 | | | | | summary: (24) merge one known; immediate right
317 | | | | | summary: (24) merge one known; immediate right
318 | | | | |
318 | | | | |
319 | | o | | changeset: 23:a01cddf0766d
319 | | o | | changeset: 23:a01cddf0766d
320 | |/| | | parent: 1:6db2ef61d156
320 | |/| | | parent: 1:6db2ef61d156
321 | | | | | parent: 22:e0d9cccacb5d
321 | | | | | parent: 22:e0d9cccacb5d
322 | | | | | user: test
322 | | | | | user: test
323 | | | | | date: Thu Jan 01 00:00:23 1970 +0000
323 | | | | | date: Thu Jan 01 00:00:23 1970 +0000
324 | | | | | summary: (23) merge one known; immediate left
324 | | | | | summary: (23) merge one known; immediate left
325 | | | | |
325 | | | | |
326 +---o---+ changeset: 22:e0d9cccacb5d
326 +---o---+ changeset: 22:e0d9cccacb5d
327 | | | | parent: 18:1aa84d96232a
327 | | | | parent: 18:1aa84d96232a
328 | | / / parent: 21:d42a756af44d
328 | | / / parent: 21:d42a756af44d
329 | | | | user: test
329 | | | | user: test
330 | | | | date: Thu Jan 01 00:00:22 1970 +0000
330 | | | | date: Thu Jan 01 00:00:22 1970 +0000
331 | | | | summary: (22) merge two known; one far left, one far right
331 | | | | summary: (22) merge two known; one far left, one far right
332 | | | |
332 | | | |
333 o | | | changeset: 21:d42a756af44d
333 o | | | changeset: 21:d42a756af44d
334 |\ \ \ \ parent: 19:31ddc2c1573b
334 |\ \ \ \ parent: 19:31ddc2c1573b
335 | | | | | parent: 20:d30ed6450e32
335 | | | | | parent: 20:d30ed6450e32
336 | | | | | user: test
336 | | | | | user: test
337 | | | | | date: Thu Jan 01 00:00:21 1970 +0000
337 | | | | | date: Thu Jan 01 00:00:21 1970 +0000
338 | | | | | summary: (21) expand
338 | | | | | summary: (21) expand
339 | | | | |
339 | | | | |
340 | o---+-+ changeset: 20:d30ed6450e32
340 | o---+-+ changeset: 20:d30ed6450e32
341 | | | | parent: 0:e6eb3150255d
341 | | | | parent: 0:e6eb3150255d
342 | / / / parent: 18:1aa84d96232a
342 | / / / parent: 18:1aa84d96232a
343 | | | | user: test
343 | | | | user: test
344 | | | | date: Thu Jan 01 00:00:20 1970 +0000
344 | | | | date: Thu Jan 01 00:00:20 1970 +0000
345 | | | | summary: (20) merge two known; two far right
345 | | | | summary: (20) merge two known; two far right
346 | | | |
346 | | | |
347 o | | | changeset: 19:31ddc2c1573b
347 o | | | changeset: 19:31ddc2c1573b
348 |\ \ \ \ parent: 15:1dda3f72782d
348 |\ \ \ \ parent: 15:1dda3f72782d
349 | | | | | parent: 17:44765d7c06e0
349 | | | | | parent: 17:44765d7c06e0
350 | | | | | user: test
350 | | | | | user: test
351 | | | | | date: Thu Jan 01 00:00:19 1970 +0000
351 | | | | | date: Thu Jan 01 00:00:19 1970 +0000
352 | | | | | summary: (19) expand
352 | | | | | summary: (19) expand
353 | | | | |
353 | | | | |
354 +---+---o changeset: 18:1aa84d96232a
354 +---+---o changeset: 18:1aa84d96232a
355 | | | | parent: 1:6db2ef61d156
355 | | | | parent: 1:6db2ef61d156
356 | | | | parent: 15:1dda3f72782d
356 | | | | parent: 15:1dda3f72782d
357 | | | | user: test
357 | | | | user: test
358 | | | | date: Thu Jan 01 00:00:18 1970 +0000
358 | | | | date: Thu Jan 01 00:00:18 1970 +0000
359 | | | | summary: (18) merge two known; two far left
359 | | | | summary: (18) merge two known; two far left
360 | | | |
360 | | | |
361 | o | | changeset: 17:44765d7c06e0
361 | o | | changeset: 17:44765d7c06e0
362 | |\ \ \ parent: 12:86b91144a6e9
362 | |\ \ \ parent: 12:86b91144a6e9
363 | | | | | parent: 16:3677d192927d
363 | | | | | parent: 16:3677d192927d
364 | | | | | user: test
364 | | | | | user: test
365 | | | | | date: Thu Jan 01 00:00:17 1970 +0000
365 | | | | | date: Thu Jan 01 00:00:17 1970 +0000
366 | | | | | summary: (17) expand
366 | | | | | summary: (17) expand
367 | | | | |
367 | | | | |
368 | | o---+ changeset: 16:3677d192927d
368 | | o---+ changeset: 16:3677d192927d
369 | | | | | parent: 0:e6eb3150255d
369 | | | | | parent: 0:e6eb3150255d
370 | | |/ / parent: 1:6db2ef61d156
370 | | |/ / parent: 1:6db2ef61d156
371 | | | | user: test
371 | | | | user: test
372 | | | | date: Thu Jan 01 00:00:16 1970 +0000
372 | | | | date: Thu Jan 01 00:00:16 1970 +0000
373 | | | | summary: (16) merge two known; one immediate right, one near right
373 | | | | summary: (16) merge two known; one immediate right, one near right
374 | | | |
374 | | | |
375 o | | | changeset: 15:1dda3f72782d
375 o | | | changeset: 15:1dda3f72782d
376 |\ \ \ \ parent: 13:22d8966a97e3
376 |\ \ \ \ parent: 13:22d8966a97e3
377 | | | | | parent: 14:8eac370358ef
377 | | | | | parent: 14:8eac370358ef
378 | | | | | user: test
378 | | | | | user: test
379 | | | | | date: Thu Jan 01 00:00:15 1970 +0000
379 | | | | | date: Thu Jan 01 00:00:15 1970 +0000
380 | | | | | summary: (15) expand
380 | | | | | summary: (15) expand
381 | | | | |
381 | | | | |
382 | o-----+ changeset: 14:8eac370358ef
382 | o-----+ changeset: 14:8eac370358ef
383 | | | | | parent: 0:e6eb3150255d
383 | | | | | parent: 0:e6eb3150255d
384 | |/ / / parent: 12:86b91144a6e9
384 | |/ / / parent: 12:86b91144a6e9
385 | | | | user: test
385 | | | | user: test
386 | | | | date: Thu Jan 01 00:00:14 1970 +0000
386 | | | | date: Thu Jan 01 00:00:14 1970 +0000
387 | | | | summary: (14) merge two known; one immediate right, one far right
387 | | | | summary: (14) merge two known; one immediate right, one far right
388 | | | |
388 | | | |
389 o | | | changeset: 13:22d8966a97e3
389 o | | | changeset: 13:22d8966a97e3
390 |\ \ \ \ parent: 9:7010c0af0a35
390 |\ \ \ \ parent: 9:7010c0af0a35
391 | | | | | parent: 11:832d76e6bdf2
391 | | | | | parent: 11:832d76e6bdf2
392 | | | | | user: test
392 | | | | | user: test
393 | | | | | date: Thu Jan 01 00:00:13 1970 +0000
393 | | | | | date: Thu Jan 01 00:00:13 1970 +0000
394 | | | | | summary: (13) expand
394 | | | | | summary: (13) expand
395 | | | | |
395 | | | | |
396 +---o | | changeset: 12:86b91144a6e9
396 +---o | | changeset: 12:86b91144a6e9
397 | | |/ / parent: 1:6db2ef61d156
397 | | |/ / parent: 1:6db2ef61d156
398 | | | | parent: 9:7010c0af0a35
398 | | | | parent: 9:7010c0af0a35
399 | | | | user: test
399 | | | | user: test
400 | | | | date: Thu Jan 01 00:00:12 1970 +0000
400 | | | | date: Thu Jan 01 00:00:12 1970 +0000
401 | | | | summary: (12) merge two known; one immediate right, one far left
401 | | | | summary: (12) merge two known; one immediate right, one far left
402 | | | |
402 | | | |
403 | o | | changeset: 11:832d76e6bdf2
403 | o | | changeset: 11:832d76e6bdf2
404 | |\ \ \ parent: 6:b105a072e251
404 | |\ \ \ parent: 6:b105a072e251
405 | | | | | parent: 10:74c64d036d72
405 | | | | | parent: 10:74c64d036d72
406 | | | | | user: test
406 | | | | | user: test
407 | | | | | date: Thu Jan 01 00:00:11 1970 +0000
407 | | | | | date: Thu Jan 01 00:00:11 1970 +0000
408 | | | | | summary: (11) expand
408 | | | | | summary: (11) expand
409 | | | | |
409 | | | | |
410 | | o---+ changeset: 10:74c64d036d72
410 | | o---+ changeset: 10:74c64d036d72
411 | | | | | parent: 0:e6eb3150255d
411 | | | | | parent: 0:e6eb3150255d
412 | |/ / / parent: 6:b105a072e251
412 | |/ / / parent: 6:b105a072e251
413 | | | | user: test
413 | | | | user: test
414 | | | | date: Thu Jan 01 00:00:10 1970 +0000
414 | | | | date: Thu Jan 01 00:00:10 1970 +0000
415 | | | | summary: (10) merge two known; one immediate left, one near right
415 | | | | summary: (10) merge two known; one immediate left, one near right
416 | | | |
416 | | | |
417 o | | | changeset: 9:7010c0af0a35
417 o | | | changeset: 9:7010c0af0a35
418 |\ \ \ \ parent: 7:b632bb1b1224
418 |\ \ \ \ parent: 7:b632bb1b1224
419 | | | | | parent: 8:7a0b11f71937
419 | | | | | parent: 8:7a0b11f71937
420 | | | | | user: test
420 | | | | | user: test
421 | | | | | date: Thu Jan 01 00:00:09 1970 +0000
421 | | | | | date: Thu Jan 01 00:00:09 1970 +0000
422 | | | | | summary: (9) expand
422 | | | | | summary: (9) expand
423 | | | | |
423 | | | | |
424 | o-----+ changeset: 8:7a0b11f71937
424 | o-----+ changeset: 8:7a0b11f71937
425 | | | | | parent: 0:e6eb3150255d
425 | | | | | parent: 0:e6eb3150255d
426 |/ / / / parent: 7:b632bb1b1224
426 |/ / / / parent: 7:b632bb1b1224
427 | | | | user: test
427 | | | | user: test
428 | | | | date: Thu Jan 01 00:00:08 1970 +0000
428 | | | | date: Thu Jan 01 00:00:08 1970 +0000
429 | | | | summary: (8) merge two known; one immediate left, one far right
429 | | | | summary: (8) merge two known; one immediate left, one far right
430 | | | |
430 | | | |
431 o | | | changeset: 7:b632bb1b1224
431 o | | | changeset: 7:b632bb1b1224
432 |\ \ \ \ parent: 2:3d9a33b8d1e1
432 |\ \ \ \ parent: 2:3d9a33b8d1e1
433 | | | | | parent: 5:4409d547b708
433 | | | | | parent: 5:4409d547b708
434 | | | | | user: test
434 | | | | | user: test
435 | | | | | date: Thu Jan 01 00:00:07 1970 +0000
435 | | | | | date: Thu Jan 01 00:00:07 1970 +0000
436 | | | | | summary: (7) expand
436 | | | | | summary: (7) expand
437 | | | | |
437 | | | | |
438 +---o | | changeset: 6:b105a072e251
438 +---o | | changeset: 6:b105a072e251
439 | |/ / / parent: 2:3d9a33b8d1e1
439 | |/ / / parent: 2:3d9a33b8d1e1
440 | | | | parent: 5:4409d547b708
440 | | | | parent: 5:4409d547b708
441 | | | | user: test
441 | | | | user: test
442 | | | | date: Thu Jan 01 00:00:06 1970 +0000
442 | | | | date: Thu Jan 01 00:00:06 1970 +0000
443 | | | | summary: (6) merge two known; one immediate left, one far left
443 | | | | summary: (6) merge two known; one immediate left, one far left
444 | | | |
444 | | | |
445 | o | | changeset: 5:4409d547b708
445 | o | | changeset: 5:4409d547b708
446 | |\ \ \ parent: 3:27eef8ed80b4
446 | |\ \ \ parent: 3:27eef8ed80b4
447 | | | | | parent: 4:26a8bac39d9f
447 | | | | | parent: 4:26a8bac39d9f
448 | | | | | user: test
448 | | | | | user: test
449 | | | | | date: Thu Jan 01 00:00:05 1970 +0000
449 | | | | | date: Thu Jan 01 00:00:05 1970 +0000
450 | | | | | summary: (5) expand
450 | | | | | summary: (5) expand
451 | | | | |
451 | | | | |
452 | | o | | changeset: 4:26a8bac39d9f
452 | | o | | changeset: 4:26a8bac39d9f
453 | |/|/ / parent: 1:6db2ef61d156
453 | |/|/ / parent: 1:6db2ef61d156
454 | | | | parent: 3:27eef8ed80b4
454 | | | | parent: 3:27eef8ed80b4
455 | | | | user: test
455 | | | | user: test
456 | | | | date: Thu Jan 01 00:00:04 1970 +0000
456 | | | | date: Thu Jan 01 00:00:04 1970 +0000
457 | | | | summary: (4) merge two known; one immediate left, one immediate right
457 | | | | summary: (4) merge two known; one immediate left, one immediate right
458 | | | |
458 | | | |
459 | o | | changeset: 3:27eef8ed80b4
459 | o | | changeset: 3:27eef8ed80b4
460 |/ / / user: test
460 |/ / / user: test
461 | | | date: Thu Jan 01 00:00:03 1970 +0000
461 | | | date: Thu Jan 01 00:00:03 1970 +0000
462 | | | summary: (3) collapse
462 | | | summary: (3) collapse
463 | | |
463 | | |
464 o | | changeset: 2:3d9a33b8d1e1
464 o | | changeset: 2:3d9a33b8d1e1
465 |/ / user: test
465 |/ / user: test
466 | | date: Thu Jan 01 00:00:02 1970 +0000
466 | | date: Thu Jan 01 00:00:02 1970 +0000
467 | | summary: (2) collapse
467 | | summary: (2) collapse
468 | |
468 | |
469 o | changeset: 1:6db2ef61d156
469 o | changeset: 1:6db2ef61d156
470 |/ user: test
470 |/ user: test
471 | date: Thu Jan 01 00:00:01 1970 +0000
471 | date: Thu Jan 01 00:00:01 1970 +0000
472 | summary: (1) collapse
472 | summary: (1) collapse
473 |
473 |
474 o changeset: 0:e6eb3150255d
474 o changeset: 0:e6eb3150255d
475 user: test
475 user: test
476 date: Thu Jan 01 00:00:00 1970 +0000
476 date: Thu Jan 01 00:00:00 1970 +0000
477 summary: (0) root
477 summary: (0) root
478
478
479
479
480 File glog:
480 File glog:
481 $ hg log -G a
481 $ hg log -G a
482 @ changeset: 34:fea3ac5810e0
482 @ changeset: 34:fea3ac5810e0
483 | tag: tip
483 | tag: tip
484 | parent: 32:d06dffa21a31
484 | parent: 32:d06dffa21a31
485 | user: test
485 | user: test
486 | date: Thu Jan 01 00:00:34 1970 +0000
486 | date: Thu Jan 01 00:00:34 1970 +0000
487 | summary: (34) head
487 | summary: (34) head
488 |
488 |
489 | o changeset: 33:68608f5145f9
489 | o changeset: 33:68608f5145f9
490 | | parent: 18:1aa84d96232a
490 | | parent: 18:1aa84d96232a
491 | | user: test
491 | | user: test
492 | | date: Thu Jan 01 00:00:33 1970 +0000
492 | | date: Thu Jan 01 00:00:33 1970 +0000
493 | | summary: (33) head
493 | | summary: (33) head
494 | |
494 | |
495 o | changeset: 32:d06dffa21a31
495 o | changeset: 32:d06dffa21a31
496 |\ \ parent: 27:886ed638191b
496 |\ \ parent: 27:886ed638191b
497 | | | parent: 31:621d83e11f67
497 | | | parent: 31:621d83e11f67
498 | | | user: test
498 | | | user: test
499 | | | date: Thu Jan 01 00:00:32 1970 +0000
499 | | | date: Thu Jan 01 00:00:32 1970 +0000
500 | | | summary: (32) expand
500 | | | summary: (32) expand
501 | | |
501 | | |
502 | o | changeset: 31:621d83e11f67
502 | o | changeset: 31:621d83e11f67
503 | |\ \ parent: 21:d42a756af44d
503 | |\ \ parent: 21:d42a756af44d
504 | | | | parent: 30:6e11cd4b648f
504 | | | | parent: 30:6e11cd4b648f
505 | | | | user: test
505 | | | | user: test
506 | | | | date: Thu Jan 01 00:00:31 1970 +0000
506 | | | | date: Thu Jan 01 00:00:31 1970 +0000
507 | | | | summary: (31) expand
507 | | | | summary: (31) expand
508 | | | |
508 | | | |
509 | | o | changeset: 30:6e11cd4b648f
509 | | o | changeset: 30:6e11cd4b648f
510 | | |\ \ parent: 28:44ecd0b9ae99
510 | | |\ \ parent: 28:44ecd0b9ae99
511 | | | | | parent: 29:cd9bb2be7593
511 | | | | | parent: 29:cd9bb2be7593
512 | | | | | user: test
512 | | | | | user: test
513 | | | | | date: Thu Jan 01 00:00:30 1970 +0000
513 | | | | | date: Thu Jan 01 00:00:30 1970 +0000
514 | | | | | summary: (30) expand
514 | | | | | summary: (30) expand
515 | | | | |
515 | | | | |
516 | | | o | changeset: 29:cd9bb2be7593
516 | | | o | changeset: 29:cd9bb2be7593
517 | | | | | parent: 0:e6eb3150255d
517 | | | | | parent: 0:e6eb3150255d
518 | | | | | user: test
518 | | | | | user: test
519 | | | | | date: Thu Jan 01 00:00:29 1970 +0000
519 | | | | | date: Thu Jan 01 00:00:29 1970 +0000
520 | | | | | summary: (29) regular commit
520 | | | | | summary: (29) regular commit
521 | | | | |
521 | | | | |
522 | | o | | changeset: 28:44ecd0b9ae99
522 | | o | | changeset: 28:44ecd0b9ae99
523 | | |\ \ \ parent: 1:6db2ef61d156
523 | | |\ \ \ parent: 1:6db2ef61d156
524 | | | | | | parent: 26:7f25b6c2f0b9
524 | | | | | | parent: 26:7f25b6c2f0b9
525 | | | | | | user: test
525 | | | | | | user: test
526 | | | | | | date: Thu Jan 01 00:00:28 1970 +0000
526 | | | | | | date: Thu Jan 01 00:00:28 1970 +0000
527 | | | | | | summary: (28) merge zero known
527 | | | | | | summary: (28) merge zero known
528 | | | | | |
528 | | | | | |
529 o | | | | | changeset: 27:886ed638191b
529 o | | | | | changeset: 27:886ed638191b
530 |/ / / / / parent: 21:d42a756af44d
530 |/ / / / / parent: 21:d42a756af44d
531 | | | | | user: test
531 | | | | | user: test
532 | | | | | date: Thu Jan 01 00:00:27 1970 +0000
532 | | | | | date: Thu Jan 01 00:00:27 1970 +0000
533 | | | | | summary: (27) collapse
533 | | | | | summary: (27) collapse
534 | | | | |
534 | | | | |
535 | | o---+ changeset: 26:7f25b6c2f0b9
535 | | o---+ changeset: 26:7f25b6c2f0b9
536 | | | | | parent: 18:1aa84d96232a
536 | | | | | parent: 18:1aa84d96232a
537 | | | | | parent: 25:91da8ed57247
537 | | | | | parent: 25:91da8ed57247
538 | | | | | user: test
538 | | | | | user: test
539 | | | | | date: Thu Jan 01 00:00:26 1970 +0000
539 | | | | | date: Thu Jan 01 00:00:26 1970 +0000
540 | | | | | summary: (26) merge one known; far right
540 | | | | | summary: (26) merge one known; far right
541 | | | | |
541 | | | | |
542 +---o | | changeset: 25:91da8ed57247
542 +---o | | changeset: 25:91da8ed57247
543 | | | | | parent: 21:d42a756af44d
543 | | | | | parent: 21:d42a756af44d
544 | | | | | parent: 24:a9c19a3d96b7
544 | | | | | parent: 24:a9c19a3d96b7
545 | | | | | user: test
545 | | | | | user: test
546 | | | | | date: Thu Jan 01 00:00:25 1970 +0000
546 | | | | | date: Thu Jan 01 00:00:25 1970 +0000
547 | | | | | summary: (25) merge one known; far left
547 | | | | | summary: (25) merge one known; far left
548 | | | | |
548 | | | | |
549 | | o | | changeset: 24:a9c19a3d96b7
549 | | o | | changeset: 24:a9c19a3d96b7
550 | | |\| | parent: 0:e6eb3150255d
550 | | |\| | parent: 0:e6eb3150255d
551 | | | | | parent: 23:a01cddf0766d
551 | | | | | parent: 23:a01cddf0766d
552 | | | | | user: test
552 | | | | | user: test
553 | | | | | date: Thu Jan 01 00:00:24 1970 +0000
553 | | | | | date: Thu Jan 01 00:00:24 1970 +0000
554 | | | | | summary: (24) merge one known; immediate right
554 | | | | | summary: (24) merge one known; immediate right
555 | | | | |
555 | | | | |
556 | | o | | changeset: 23:a01cddf0766d
556 | | o | | changeset: 23:a01cddf0766d
557 | |/| | | parent: 1:6db2ef61d156
557 | |/| | | parent: 1:6db2ef61d156
558 | | | | | parent: 22:e0d9cccacb5d
558 | | | | | parent: 22:e0d9cccacb5d
559 | | | | | user: test
559 | | | | | user: test
560 | | | | | date: Thu Jan 01 00:00:23 1970 +0000
560 | | | | | date: Thu Jan 01 00:00:23 1970 +0000
561 | | | | | summary: (23) merge one known; immediate left
561 | | | | | summary: (23) merge one known; immediate left
562 | | | | |
562 | | | | |
563 +---o---+ changeset: 22:e0d9cccacb5d
563 +---o---+ changeset: 22:e0d9cccacb5d
564 | | | | parent: 18:1aa84d96232a
564 | | | | parent: 18:1aa84d96232a
565 | | / / parent: 21:d42a756af44d
565 | | / / parent: 21:d42a756af44d
566 | | | | user: test
566 | | | | user: test
567 | | | | date: Thu Jan 01 00:00:22 1970 +0000
567 | | | | date: Thu Jan 01 00:00:22 1970 +0000
568 | | | | summary: (22) merge two known; one far left, one far right
568 | | | | summary: (22) merge two known; one far left, one far right
569 | | | |
569 | | | |
570 o | | | changeset: 21:d42a756af44d
570 o | | | changeset: 21:d42a756af44d
571 |\ \ \ \ parent: 19:31ddc2c1573b
571 |\ \ \ \ parent: 19:31ddc2c1573b
572 | | | | | parent: 20:d30ed6450e32
572 | | | | | parent: 20:d30ed6450e32
573 | | | | | user: test
573 | | | | | user: test
574 | | | | | date: Thu Jan 01 00:00:21 1970 +0000
574 | | | | | date: Thu Jan 01 00:00:21 1970 +0000
575 | | | | | summary: (21) expand
575 | | | | | summary: (21) expand
576 | | | | |
576 | | | | |
577 | o---+-+ changeset: 20:d30ed6450e32
577 | o---+-+ changeset: 20:d30ed6450e32
578 | | | | parent: 0:e6eb3150255d
578 | | | | parent: 0:e6eb3150255d
579 | / / / parent: 18:1aa84d96232a
579 | / / / parent: 18:1aa84d96232a
580 | | | | user: test
580 | | | | user: test
581 | | | | date: Thu Jan 01 00:00:20 1970 +0000
581 | | | | date: Thu Jan 01 00:00:20 1970 +0000
582 | | | | summary: (20) merge two known; two far right
582 | | | | summary: (20) merge two known; two far right
583 | | | |
583 | | | |
584 o | | | changeset: 19:31ddc2c1573b
584 o | | | changeset: 19:31ddc2c1573b
585 |\ \ \ \ parent: 15:1dda3f72782d
585 |\ \ \ \ parent: 15:1dda3f72782d
586 | | | | | parent: 17:44765d7c06e0
586 | | | | | parent: 17:44765d7c06e0
587 | | | | | user: test
587 | | | | | user: test
588 | | | | | date: Thu Jan 01 00:00:19 1970 +0000
588 | | | | | date: Thu Jan 01 00:00:19 1970 +0000
589 | | | | | summary: (19) expand
589 | | | | | summary: (19) expand
590 | | | | |
590 | | | | |
591 +---+---o changeset: 18:1aa84d96232a
591 +---+---o changeset: 18:1aa84d96232a
592 | | | | parent: 1:6db2ef61d156
592 | | | | parent: 1:6db2ef61d156
593 | | | | parent: 15:1dda3f72782d
593 | | | | parent: 15:1dda3f72782d
594 | | | | user: test
594 | | | | user: test
595 | | | | date: Thu Jan 01 00:00:18 1970 +0000
595 | | | | date: Thu Jan 01 00:00:18 1970 +0000
596 | | | | summary: (18) merge two known; two far left
596 | | | | summary: (18) merge two known; two far left
597 | | | |
597 | | | |
598 | o | | changeset: 17:44765d7c06e0
598 | o | | changeset: 17:44765d7c06e0
599 | |\ \ \ parent: 12:86b91144a6e9
599 | |\ \ \ parent: 12:86b91144a6e9
600 | | | | | parent: 16:3677d192927d
600 | | | | | parent: 16:3677d192927d
601 | | | | | user: test
601 | | | | | user: test
602 | | | | | date: Thu Jan 01 00:00:17 1970 +0000
602 | | | | | date: Thu Jan 01 00:00:17 1970 +0000
603 | | | | | summary: (17) expand
603 | | | | | summary: (17) expand
604 | | | | |
604 | | | | |
605 | | o---+ changeset: 16:3677d192927d
605 | | o---+ changeset: 16:3677d192927d
606 | | | | | parent: 0:e6eb3150255d
606 | | | | | parent: 0:e6eb3150255d
607 | | |/ / parent: 1:6db2ef61d156
607 | | |/ / parent: 1:6db2ef61d156
608 | | | | user: test
608 | | | | user: test
609 | | | | date: Thu Jan 01 00:00:16 1970 +0000
609 | | | | date: Thu Jan 01 00:00:16 1970 +0000
610 | | | | summary: (16) merge two known; one immediate right, one near right
610 | | | | summary: (16) merge two known; one immediate right, one near right
611 | | | |
611 | | | |
612 o | | | changeset: 15:1dda3f72782d
612 o | | | changeset: 15:1dda3f72782d
613 |\ \ \ \ parent: 13:22d8966a97e3
613 |\ \ \ \ parent: 13:22d8966a97e3
614 | | | | | parent: 14:8eac370358ef
614 | | | | | parent: 14:8eac370358ef
615 | | | | | user: test
615 | | | | | user: test
616 | | | | | date: Thu Jan 01 00:00:15 1970 +0000
616 | | | | | date: Thu Jan 01 00:00:15 1970 +0000
617 | | | | | summary: (15) expand
617 | | | | | summary: (15) expand
618 | | | | |
618 | | | | |
619 | o-----+ changeset: 14:8eac370358ef
619 | o-----+ changeset: 14:8eac370358ef
620 | | | | | parent: 0:e6eb3150255d
620 | | | | | parent: 0:e6eb3150255d
621 | |/ / / parent: 12:86b91144a6e9
621 | |/ / / parent: 12:86b91144a6e9
622 | | | | user: test
622 | | | | user: test
623 | | | | date: Thu Jan 01 00:00:14 1970 +0000
623 | | | | date: Thu Jan 01 00:00:14 1970 +0000
624 | | | | summary: (14) merge two known; one immediate right, one far right
624 | | | | summary: (14) merge two known; one immediate right, one far right
625 | | | |
625 | | | |
626 o | | | changeset: 13:22d8966a97e3
626 o | | | changeset: 13:22d8966a97e3
627 |\ \ \ \ parent: 9:7010c0af0a35
627 |\ \ \ \ parent: 9:7010c0af0a35
628 | | | | | parent: 11:832d76e6bdf2
628 | | | | | parent: 11:832d76e6bdf2
629 | | | | | user: test
629 | | | | | user: test
630 | | | | | date: Thu Jan 01 00:00:13 1970 +0000
630 | | | | | date: Thu Jan 01 00:00:13 1970 +0000
631 | | | | | summary: (13) expand
631 | | | | | summary: (13) expand
632 | | | | |
632 | | | | |
633 +---o | | changeset: 12:86b91144a6e9
633 +---o | | changeset: 12:86b91144a6e9
634 | | |/ / parent: 1:6db2ef61d156
634 | | |/ / parent: 1:6db2ef61d156
635 | | | | parent: 9:7010c0af0a35
635 | | | | parent: 9:7010c0af0a35
636 | | | | user: test
636 | | | | user: test
637 | | | | date: Thu Jan 01 00:00:12 1970 +0000
637 | | | | date: Thu Jan 01 00:00:12 1970 +0000
638 | | | | summary: (12) merge two known; one immediate right, one far left
638 | | | | summary: (12) merge two known; one immediate right, one far left
639 | | | |
639 | | | |
640 | o | | changeset: 11:832d76e6bdf2
640 | o | | changeset: 11:832d76e6bdf2
641 | |\ \ \ parent: 6:b105a072e251
641 | |\ \ \ parent: 6:b105a072e251
642 | | | | | parent: 10:74c64d036d72
642 | | | | | parent: 10:74c64d036d72
643 | | | | | user: test
643 | | | | | user: test
644 | | | | | date: Thu Jan 01 00:00:11 1970 +0000
644 | | | | | date: Thu Jan 01 00:00:11 1970 +0000
645 | | | | | summary: (11) expand
645 | | | | | summary: (11) expand
646 | | | | |
646 | | | | |
647 | | o---+ changeset: 10:74c64d036d72
647 | | o---+ changeset: 10:74c64d036d72
648 | | | | | parent: 0:e6eb3150255d
648 | | | | | parent: 0:e6eb3150255d
649 | |/ / / parent: 6:b105a072e251
649 | |/ / / parent: 6:b105a072e251
650 | | | | user: test
650 | | | | user: test
651 | | | | date: Thu Jan 01 00:00:10 1970 +0000
651 | | | | date: Thu Jan 01 00:00:10 1970 +0000
652 | | | | summary: (10) merge two known; one immediate left, one near right
652 | | | | summary: (10) merge two known; one immediate left, one near right
653 | | | |
653 | | | |
654 o | | | changeset: 9:7010c0af0a35
654 o | | | changeset: 9:7010c0af0a35
655 |\ \ \ \ parent: 7:b632bb1b1224
655 |\ \ \ \ parent: 7:b632bb1b1224
656 | | | | | parent: 8:7a0b11f71937
656 | | | | | parent: 8:7a0b11f71937
657 | | | | | user: test
657 | | | | | user: test
658 | | | | | date: Thu Jan 01 00:00:09 1970 +0000
658 | | | | | date: Thu Jan 01 00:00:09 1970 +0000
659 | | | | | summary: (9) expand
659 | | | | | summary: (9) expand
660 | | | | |
660 | | | | |
661 | o-----+ changeset: 8:7a0b11f71937
661 | o-----+ changeset: 8:7a0b11f71937
662 | | | | | parent: 0:e6eb3150255d
662 | | | | | parent: 0:e6eb3150255d
663 |/ / / / parent: 7:b632bb1b1224
663 |/ / / / parent: 7:b632bb1b1224
664 | | | | user: test
664 | | | | user: test
665 | | | | date: Thu Jan 01 00:00:08 1970 +0000
665 | | | | date: Thu Jan 01 00:00:08 1970 +0000
666 | | | | summary: (8) merge two known; one immediate left, one far right
666 | | | | summary: (8) merge two known; one immediate left, one far right
667 | | | |
667 | | | |
668 o | | | changeset: 7:b632bb1b1224
668 o | | | changeset: 7:b632bb1b1224
669 |\ \ \ \ parent: 2:3d9a33b8d1e1
669 |\ \ \ \ parent: 2:3d9a33b8d1e1
670 | | | | | parent: 5:4409d547b708
670 | | | | | parent: 5:4409d547b708
671 | | | | | user: test
671 | | | | | user: test
672 | | | | | date: Thu Jan 01 00:00:07 1970 +0000
672 | | | | | date: Thu Jan 01 00:00:07 1970 +0000
673 | | | | | summary: (7) expand
673 | | | | | summary: (7) expand
674 | | | | |
674 | | | | |
675 +---o | | changeset: 6:b105a072e251
675 +---o | | changeset: 6:b105a072e251
676 | |/ / / parent: 2:3d9a33b8d1e1
676 | |/ / / parent: 2:3d9a33b8d1e1
677 | | | | parent: 5:4409d547b708
677 | | | | parent: 5:4409d547b708
678 | | | | user: test
678 | | | | user: test
679 | | | | date: Thu Jan 01 00:00:06 1970 +0000
679 | | | | date: Thu Jan 01 00:00:06 1970 +0000
680 | | | | summary: (6) merge two known; one immediate left, one far left
680 | | | | summary: (6) merge two known; one immediate left, one far left
681 | | | |
681 | | | |
682 | o | | changeset: 5:4409d547b708
682 | o | | changeset: 5:4409d547b708
683 | |\ \ \ parent: 3:27eef8ed80b4
683 | |\ \ \ parent: 3:27eef8ed80b4
684 | | | | | parent: 4:26a8bac39d9f
684 | | | | | parent: 4:26a8bac39d9f
685 | | | | | user: test
685 | | | | | user: test
686 | | | | | date: Thu Jan 01 00:00:05 1970 +0000
686 | | | | | date: Thu Jan 01 00:00:05 1970 +0000
687 | | | | | summary: (5) expand
687 | | | | | summary: (5) expand
688 | | | | |
688 | | | | |
689 | | o | | changeset: 4:26a8bac39d9f
689 | | o | | changeset: 4:26a8bac39d9f
690 | |/|/ / parent: 1:6db2ef61d156
690 | |/|/ / parent: 1:6db2ef61d156
691 | | | | parent: 3:27eef8ed80b4
691 | | | | parent: 3:27eef8ed80b4
692 | | | | user: test
692 | | | | user: test
693 | | | | date: Thu Jan 01 00:00:04 1970 +0000
693 | | | | date: Thu Jan 01 00:00:04 1970 +0000
694 | | | | summary: (4) merge two known; one immediate left, one immediate right
694 | | | | summary: (4) merge two known; one immediate left, one immediate right
695 | | | |
695 | | | |
696 | o | | changeset: 3:27eef8ed80b4
696 | o | | changeset: 3:27eef8ed80b4
697 |/ / / user: test
697 |/ / / user: test
698 | | | date: Thu Jan 01 00:00:03 1970 +0000
698 | | | date: Thu Jan 01 00:00:03 1970 +0000
699 | | | summary: (3) collapse
699 | | | summary: (3) collapse
700 | | |
700 | | |
701 o | | changeset: 2:3d9a33b8d1e1
701 o | | changeset: 2:3d9a33b8d1e1
702 |/ / user: test
702 |/ / user: test
703 | | date: Thu Jan 01 00:00:02 1970 +0000
703 | | date: Thu Jan 01 00:00:02 1970 +0000
704 | | summary: (2) collapse
704 | | summary: (2) collapse
705 | |
705 | |
706 o | changeset: 1:6db2ef61d156
706 o | changeset: 1:6db2ef61d156
707 |/ user: test
707 |/ user: test
708 | date: Thu Jan 01 00:00:01 1970 +0000
708 | date: Thu Jan 01 00:00:01 1970 +0000
709 | summary: (1) collapse
709 | summary: (1) collapse
710 |
710 |
711 o changeset: 0:e6eb3150255d
711 o changeset: 0:e6eb3150255d
712 user: test
712 user: test
713 date: Thu Jan 01 00:00:00 1970 +0000
713 date: Thu Jan 01 00:00:00 1970 +0000
714 summary: (0) root
714 summary: (0) root
715
715
716
716
717 File glog per revset:
717 File glog per revset:
718
718
719 $ hg log -G -r 'file("a")'
719 $ hg log -G -r 'file("a")'
720 @ changeset: 34:fea3ac5810e0
720 @ changeset: 34:fea3ac5810e0
721 | tag: tip
721 | tag: tip
722 | parent: 32:d06dffa21a31
722 | parent: 32:d06dffa21a31
723 | user: test
723 | user: test
724 | date: Thu Jan 01 00:00:34 1970 +0000
724 | date: Thu Jan 01 00:00:34 1970 +0000
725 | summary: (34) head
725 | summary: (34) head
726 |
726 |
727 | o changeset: 33:68608f5145f9
727 | o changeset: 33:68608f5145f9
728 | | parent: 18:1aa84d96232a
728 | | parent: 18:1aa84d96232a
729 | | user: test
729 | | user: test
730 | | date: Thu Jan 01 00:00:33 1970 +0000
730 | | date: Thu Jan 01 00:00:33 1970 +0000
731 | | summary: (33) head
731 | | summary: (33) head
732 | |
732 | |
733 o | changeset: 32:d06dffa21a31
733 o | changeset: 32:d06dffa21a31
734 |\ \ parent: 27:886ed638191b
734 |\ \ parent: 27:886ed638191b
735 | | | parent: 31:621d83e11f67
735 | | | parent: 31:621d83e11f67
736 | | | user: test
736 | | | user: test
737 | | | date: Thu Jan 01 00:00:32 1970 +0000
737 | | | date: Thu Jan 01 00:00:32 1970 +0000
738 | | | summary: (32) expand
738 | | | summary: (32) expand
739 | | |
739 | | |
740 | o | changeset: 31:621d83e11f67
740 | o | changeset: 31:621d83e11f67
741 | |\ \ parent: 21:d42a756af44d
741 | |\ \ parent: 21:d42a756af44d
742 | | | | parent: 30:6e11cd4b648f
742 | | | | parent: 30:6e11cd4b648f
743 | | | | user: test
743 | | | | user: test
744 | | | | date: Thu Jan 01 00:00:31 1970 +0000
744 | | | | date: Thu Jan 01 00:00:31 1970 +0000
745 | | | | summary: (31) expand
745 | | | | summary: (31) expand
746 | | | |
746 | | | |
747 | | o | changeset: 30:6e11cd4b648f
747 | | o | changeset: 30:6e11cd4b648f
748 | | |\ \ parent: 28:44ecd0b9ae99
748 | | |\ \ parent: 28:44ecd0b9ae99
749 | | | | | parent: 29:cd9bb2be7593
749 | | | | | parent: 29:cd9bb2be7593
750 | | | | | user: test
750 | | | | | user: test
751 | | | | | date: Thu Jan 01 00:00:30 1970 +0000
751 | | | | | date: Thu Jan 01 00:00:30 1970 +0000
752 | | | | | summary: (30) expand
752 | | | | | summary: (30) expand
753 | | | | |
753 | | | | |
754 | | | o | changeset: 29:cd9bb2be7593
754 | | | o | changeset: 29:cd9bb2be7593
755 | | | | | parent: 0:e6eb3150255d
755 | | | | | parent: 0:e6eb3150255d
756 | | | | | user: test
756 | | | | | user: test
757 | | | | | date: Thu Jan 01 00:00:29 1970 +0000
757 | | | | | date: Thu Jan 01 00:00:29 1970 +0000
758 | | | | | summary: (29) regular commit
758 | | | | | summary: (29) regular commit
759 | | | | |
759 | | | | |
760 | | o | | changeset: 28:44ecd0b9ae99
760 | | o | | changeset: 28:44ecd0b9ae99
761 | | |\ \ \ parent: 1:6db2ef61d156
761 | | |\ \ \ parent: 1:6db2ef61d156
762 | | | | | | parent: 26:7f25b6c2f0b9
762 | | | | | | parent: 26:7f25b6c2f0b9
763 | | | | | | user: test
763 | | | | | | user: test
764 | | | | | | date: Thu Jan 01 00:00:28 1970 +0000
764 | | | | | | date: Thu Jan 01 00:00:28 1970 +0000
765 | | | | | | summary: (28) merge zero known
765 | | | | | | summary: (28) merge zero known
766 | | | | | |
766 | | | | | |
767 o | | | | | changeset: 27:886ed638191b
767 o | | | | | changeset: 27:886ed638191b
768 |/ / / / / parent: 21:d42a756af44d
768 |/ / / / / parent: 21:d42a756af44d
769 | | | | | user: test
769 | | | | | user: test
770 | | | | | date: Thu Jan 01 00:00:27 1970 +0000
770 | | | | | date: Thu Jan 01 00:00:27 1970 +0000
771 | | | | | summary: (27) collapse
771 | | | | | summary: (27) collapse
772 | | | | |
772 | | | | |
773 | | o---+ changeset: 26:7f25b6c2f0b9
773 | | o---+ changeset: 26:7f25b6c2f0b9
774 | | | | | parent: 18:1aa84d96232a
774 | | | | | parent: 18:1aa84d96232a
775 | | | | | parent: 25:91da8ed57247
775 | | | | | parent: 25:91da8ed57247
776 | | | | | user: test
776 | | | | | user: test
777 | | | | | date: Thu Jan 01 00:00:26 1970 +0000
777 | | | | | date: Thu Jan 01 00:00:26 1970 +0000
778 | | | | | summary: (26) merge one known; far right
778 | | | | | summary: (26) merge one known; far right
779 | | | | |
779 | | | | |
780 +---o | | changeset: 25:91da8ed57247
780 +---o | | changeset: 25:91da8ed57247
781 | | | | | parent: 21:d42a756af44d
781 | | | | | parent: 21:d42a756af44d
782 | | | | | parent: 24:a9c19a3d96b7
782 | | | | | parent: 24:a9c19a3d96b7
783 | | | | | user: test
783 | | | | | user: test
784 | | | | | date: Thu Jan 01 00:00:25 1970 +0000
784 | | | | | date: Thu Jan 01 00:00:25 1970 +0000
785 | | | | | summary: (25) merge one known; far left
785 | | | | | summary: (25) merge one known; far left
786 | | | | |
786 | | | | |
787 | | o | | changeset: 24:a9c19a3d96b7
787 | | o | | changeset: 24:a9c19a3d96b7
788 | | |\| | parent: 0:e6eb3150255d
788 | | |\| | parent: 0:e6eb3150255d
789 | | | | | parent: 23:a01cddf0766d
789 | | | | | parent: 23:a01cddf0766d
790 | | | | | user: test
790 | | | | | user: test
791 | | | | | date: Thu Jan 01 00:00:24 1970 +0000
791 | | | | | date: Thu Jan 01 00:00:24 1970 +0000
792 | | | | | summary: (24) merge one known; immediate right
792 | | | | | summary: (24) merge one known; immediate right
793 | | | | |
793 | | | | |
794 | | o | | changeset: 23:a01cddf0766d
794 | | o | | changeset: 23:a01cddf0766d
795 | |/| | | parent: 1:6db2ef61d156
795 | |/| | | parent: 1:6db2ef61d156
796 | | | | | parent: 22:e0d9cccacb5d
796 | | | | | parent: 22:e0d9cccacb5d
797 | | | | | user: test
797 | | | | | user: test
798 | | | | | date: Thu Jan 01 00:00:23 1970 +0000
798 | | | | | date: Thu Jan 01 00:00:23 1970 +0000
799 | | | | | summary: (23) merge one known; immediate left
799 | | | | | summary: (23) merge one known; immediate left
800 | | | | |
800 | | | | |
801 +---o---+ changeset: 22:e0d9cccacb5d
801 +---o---+ changeset: 22:e0d9cccacb5d
802 | | | | parent: 18:1aa84d96232a
802 | | | | parent: 18:1aa84d96232a
803 | | / / parent: 21:d42a756af44d
803 | | / / parent: 21:d42a756af44d
804 | | | | user: test
804 | | | | user: test
805 | | | | date: Thu Jan 01 00:00:22 1970 +0000
805 | | | | date: Thu Jan 01 00:00:22 1970 +0000
806 | | | | summary: (22) merge two known; one far left, one far right
806 | | | | summary: (22) merge two known; one far left, one far right
807 | | | |
807 | | | |
808 o | | | changeset: 21:d42a756af44d
808 o | | | changeset: 21:d42a756af44d
809 |\ \ \ \ parent: 19:31ddc2c1573b
809 |\ \ \ \ parent: 19:31ddc2c1573b
810 | | | | | parent: 20:d30ed6450e32
810 | | | | | parent: 20:d30ed6450e32
811 | | | | | user: test
811 | | | | | user: test
812 | | | | | date: Thu Jan 01 00:00:21 1970 +0000
812 | | | | | date: Thu Jan 01 00:00:21 1970 +0000
813 | | | | | summary: (21) expand
813 | | | | | summary: (21) expand
814 | | | | |
814 | | | | |
815 | o---+-+ changeset: 20:d30ed6450e32
815 | o---+-+ changeset: 20:d30ed6450e32
816 | | | | parent: 0:e6eb3150255d
816 | | | | parent: 0:e6eb3150255d
817 | / / / parent: 18:1aa84d96232a
817 | / / / parent: 18:1aa84d96232a
818 | | | | user: test
818 | | | | user: test
819 | | | | date: Thu Jan 01 00:00:20 1970 +0000
819 | | | | date: Thu Jan 01 00:00:20 1970 +0000
820 | | | | summary: (20) merge two known; two far right
820 | | | | summary: (20) merge two known; two far right
821 | | | |
821 | | | |
822 o | | | changeset: 19:31ddc2c1573b
822 o | | | changeset: 19:31ddc2c1573b
823 |\ \ \ \ parent: 15:1dda3f72782d
823 |\ \ \ \ parent: 15:1dda3f72782d
824 | | | | | parent: 17:44765d7c06e0
824 | | | | | parent: 17:44765d7c06e0
825 | | | | | user: test
825 | | | | | user: test
826 | | | | | date: Thu Jan 01 00:00:19 1970 +0000
826 | | | | | date: Thu Jan 01 00:00:19 1970 +0000
827 | | | | | summary: (19) expand
827 | | | | | summary: (19) expand
828 | | | | |
828 | | | | |
829 +---+---o changeset: 18:1aa84d96232a
829 +---+---o changeset: 18:1aa84d96232a
830 | | | | parent: 1:6db2ef61d156
830 | | | | parent: 1:6db2ef61d156
831 | | | | parent: 15:1dda3f72782d
831 | | | | parent: 15:1dda3f72782d
832 | | | | user: test
832 | | | | user: test
833 | | | | date: Thu Jan 01 00:00:18 1970 +0000
833 | | | | date: Thu Jan 01 00:00:18 1970 +0000
834 | | | | summary: (18) merge two known; two far left
834 | | | | summary: (18) merge two known; two far left
835 | | | |
835 | | | |
836 | o | | changeset: 17:44765d7c06e0
836 | o | | changeset: 17:44765d7c06e0
837 | |\ \ \ parent: 12:86b91144a6e9
837 | |\ \ \ parent: 12:86b91144a6e9
838 | | | | | parent: 16:3677d192927d
838 | | | | | parent: 16:3677d192927d
839 | | | | | user: test
839 | | | | | user: test
840 | | | | | date: Thu Jan 01 00:00:17 1970 +0000
840 | | | | | date: Thu Jan 01 00:00:17 1970 +0000
841 | | | | | summary: (17) expand
841 | | | | | summary: (17) expand
842 | | | | |
842 | | | | |
843 | | o---+ changeset: 16:3677d192927d
843 | | o---+ changeset: 16:3677d192927d
844 | | | | | parent: 0:e6eb3150255d
844 | | | | | parent: 0:e6eb3150255d
845 | | |/ / parent: 1:6db2ef61d156
845 | | |/ / parent: 1:6db2ef61d156
846 | | | | user: test
846 | | | | user: test
847 | | | | date: Thu Jan 01 00:00:16 1970 +0000
847 | | | | date: Thu Jan 01 00:00:16 1970 +0000
848 | | | | summary: (16) merge two known; one immediate right, one near right
848 | | | | summary: (16) merge two known; one immediate right, one near right
849 | | | |
849 | | | |
850 o | | | changeset: 15:1dda3f72782d
850 o | | | changeset: 15:1dda3f72782d
851 |\ \ \ \ parent: 13:22d8966a97e3
851 |\ \ \ \ parent: 13:22d8966a97e3
852 | | | | | parent: 14:8eac370358ef
852 | | | | | parent: 14:8eac370358ef
853 | | | | | user: test
853 | | | | | user: test
854 | | | | | date: Thu Jan 01 00:00:15 1970 +0000
854 | | | | | date: Thu Jan 01 00:00:15 1970 +0000
855 | | | | | summary: (15) expand
855 | | | | | summary: (15) expand
856 | | | | |
856 | | | | |
857 | o-----+ changeset: 14:8eac370358ef
857 | o-----+ changeset: 14:8eac370358ef
858 | | | | | parent: 0:e6eb3150255d
858 | | | | | parent: 0:e6eb3150255d
859 | |/ / / parent: 12:86b91144a6e9
859 | |/ / / parent: 12:86b91144a6e9
860 | | | | user: test
860 | | | | user: test
861 | | | | date: Thu Jan 01 00:00:14 1970 +0000
861 | | | | date: Thu Jan 01 00:00:14 1970 +0000
862 | | | | summary: (14) merge two known; one immediate right, one far right
862 | | | | summary: (14) merge two known; one immediate right, one far right
863 | | | |
863 | | | |
864 o | | | changeset: 13:22d8966a97e3
864 o | | | changeset: 13:22d8966a97e3
865 |\ \ \ \ parent: 9:7010c0af0a35
865 |\ \ \ \ parent: 9:7010c0af0a35
866 | | | | | parent: 11:832d76e6bdf2
866 | | | | | parent: 11:832d76e6bdf2
867 | | | | | user: test
867 | | | | | user: test
868 | | | | | date: Thu Jan 01 00:00:13 1970 +0000
868 | | | | | date: Thu Jan 01 00:00:13 1970 +0000
869 | | | | | summary: (13) expand
869 | | | | | summary: (13) expand
870 | | | | |
870 | | | | |
871 +---o | | changeset: 12:86b91144a6e9
871 +---o | | changeset: 12:86b91144a6e9
872 | | |/ / parent: 1:6db2ef61d156
872 | | |/ / parent: 1:6db2ef61d156
873 | | | | parent: 9:7010c0af0a35
873 | | | | parent: 9:7010c0af0a35
874 | | | | user: test
874 | | | | user: test
875 | | | | date: Thu Jan 01 00:00:12 1970 +0000
875 | | | | date: Thu Jan 01 00:00:12 1970 +0000
876 | | | | summary: (12) merge two known; one immediate right, one far left
876 | | | | summary: (12) merge two known; one immediate right, one far left
877 | | | |
877 | | | |
878 | o | | changeset: 11:832d76e6bdf2
878 | o | | changeset: 11:832d76e6bdf2
879 | |\ \ \ parent: 6:b105a072e251
879 | |\ \ \ parent: 6:b105a072e251
880 | | | | | parent: 10:74c64d036d72
880 | | | | | parent: 10:74c64d036d72
881 | | | | | user: test
881 | | | | | user: test
882 | | | | | date: Thu Jan 01 00:00:11 1970 +0000
882 | | | | | date: Thu Jan 01 00:00:11 1970 +0000
883 | | | | | summary: (11) expand
883 | | | | | summary: (11) expand
884 | | | | |
884 | | | | |
885 | | o---+ changeset: 10:74c64d036d72
885 | | o---+ changeset: 10:74c64d036d72
886 | | | | | parent: 0:e6eb3150255d
886 | | | | | parent: 0:e6eb3150255d
887 | |/ / / parent: 6:b105a072e251
887 | |/ / / parent: 6:b105a072e251
888 | | | | user: test
888 | | | | user: test
889 | | | | date: Thu Jan 01 00:00:10 1970 +0000
889 | | | | date: Thu Jan 01 00:00:10 1970 +0000
890 | | | | summary: (10) merge two known; one immediate left, one near right
890 | | | | summary: (10) merge two known; one immediate left, one near right
891 | | | |
891 | | | |
892 o | | | changeset: 9:7010c0af0a35
892 o | | | changeset: 9:7010c0af0a35
893 |\ \ \ \ parent: 7:b632bb1b1224
893 |\ \ \ \ parent: 7:b632bb1b1224
894 | | | | | parent: 8:7a0b11f71937
894 | | | | | parent: 8:7a0b11f71937
895 | | | | | user: test
895 | | | | | user: test
896 | | | | | date: Thu Jan 01 00:00:09 1970 +0000
896 | | | | | date: Thu Jan 01 00:00:09 1970 +0000
897 | | | | | summary: (9) expand
897 | | | | | summary: (9) expand
898 | | | | |
898 | | | | |
899 | o-----+ changeset: 8:7a0b11f71937
899 | o-----+ changeset: 8:7a0b11f71937
900 | | | | | parent: 0:e6eb3150255d
900 | | | | | parent: 0:e6eb3150255d
901 |/ / / / parent: 7:b632bb1b1224
901 |/ / / / parent: 7:b632bb1b1224
902 | | | | user: test
902 | | | | user: test
903 | | | | date: Thu Jan 01 00:00:08 1970 +0000
903 | | | | date: Thu Jan 01 00:00:08 1970 +0000
904 | | | | summary: (8) merge two known; one immediate left, one far right
904 | | | | summary: (8) merge two known; one immediate left, one far right
905 | | | |
905 | | | |
906 o | | | changeset: 7:b632bb1b1224
906 o | | | changeset: 7:b632bb1b1224
907 |\ \ \ \ parent: 2:3d9a33b8d1e1
907 |\ \ \ \ parent: 2:3d9a33b8d1e1
908 | | | | | parent: 5:4409d547b708
908 | | | | | parent: 5:4409d547b708
909 | | | | | user: test
909 | | | | | user: test
910 | | | | | date: Thu Jan 01 00:00:07 1970 +0000
910 | | | | | date: Thu Jan 01 00:00:07 1970 +0000
911 | | | | | summary: (7) expand
911 | | | | | summary: (7) expand
912 | | | | |
912 | | | | |
913 +---o | | changeset: 6:b105a072e251
913 +---o | | changeset: 6:b105a072e251
914 | |/ / / parent: 2:3d9a33b8d1e1
914 | |/ / / parent: 2:3d9a33b8d1e1
915 | | | | parent: 5:4409d547b708
915 | | | | parent: 5:4409d547b708
916 | | | | user: test
916 | | | | user: test
917 | | | | date: Thu Jan 01 00:00:06 1970 +0000
917 | | | | date: Thu Jan 01 00:00:06 1970 +0000
918 | | | | summary: (6) merge two known; one immediate left, one far left
918 | | | | summary: (6) merge two known; one immediate left, one far left
919 | | | |
919 | | | |
920 | o | | changeset: 5:4409d547b708
920 | o | | changeset: 5:4409d547b708
921 | |\ \ \ parent: 3:27eef8ed80b4
921 | |\ \ \ parent: 3:27eef8ed80b4
922 | | | | | parent: 4:26a8bac39d9f
922 | | | | | parent: 4:26a8bac39d9f
923 | | | | | user: test
923 | | | | | user: test
924 | | | | | date: Thu Jan 01 00:00:05 1970 +0000
924 | | | | | date: Thu Jan 01 00:00:05 1970 +0000
925 | | | | | summary: (5) expand
925 | | | | | summary: (5) expand
926 | | | | |
926 | | | | |
927 | | o | | changeset: 4:26a8bac39d9f
927 | | o | | changeset: 4:26a8bac39d9f
928 | |/|/ / parent: 1:6db2ef61d156
928 | |/|/ / parent: 1:6db2ef61d156
929 | | | | parent: 3:27eef8ed80b4
929 | | | | parent: 3:27eef8ed80b4
930 | | | | user: test
930 | | | | user: test
931 | | | | date: Thu Jan 01 00:00:04 1970 +0000
931 | | | | date: Thu Jan 01 00:00:04 1970 +0000
932 | | | | summary: (4) merge two known; one immediate left, one immediate right
932 | | | | summary: (4) merge two known; one immediate left, one immediate right
933 | | | |
933 | | | |
934 | o | | changeset: 3:27eef8ed80b4
934 | o | | changeset: 3:27eef8ed80b4
935 |/ / / user: test
935 |/ / / user: test
936 | | | date: Thu Jan 01 00:00:03 1970 +0000
936 | | | date: Thu Jan 01 00:00:03 1970 +0000
937 | | | summary: (3) collapse
937 | | | summary: (3) collapse
938 | | |
938 | | |
939 o | | changeset: 2:3d9a33b8d1e1
939 o | | changeset: 2:3d9a33b8d1e1
940 |/ / user: test
940 |/ / user: test
941 | | date: Thu Jan 01 00:00:02 1970 +0000
941 | | date: Thu Jan 01 00:00:02 1970 +0000
942 | | summary: (2) collapse
942 | | summary: (2) collapse
943 | |
943 | |
944 o | changeset: 1:6db2ef61d156
944 o | changeset: 1:6db2ef61d156
945 |/ user: test
945 |/ user: test
946 | date: Thu Jan 01 00:00:01 1970 +0000
946 | date: Thu Jan 01 00:00:01 1970 +0000
947 | summary: (1) collapse
947 | summary: (1) collapse
948 |
948 |
949 o changeset: 0:e6eb3150255d
949 o changeset: 0:e6eb3150255d
950 user: test
950 user: test
951 date: Thu Jan 01 00:00:00 1970 +0000
951 date: Thu Jan 01 00:00:00 1970 +0000
952 summary: (0) root
952 summary: (0) root
953
953
954
954
955
955
956 File glog per revset (only merges):
956 File glog per revset (only merges):
957
957
958 $ hg log -G -r 'file("a")' -m
958 $ hg log -G -r 'file("a")' -m
959 o changeset: 32:d06dffa21a31
959 o changeset: 32:d06dffa21a31
960 |\ parent: 27:886ed638191b
960 |\ parent: 27:886ed638191b
961 | : parent: 31:621d83e11f67
961 | : parent: 31:621d83e11f67
962 | : user: test
962 | : user: test
963 | : date: Thu Jan 01 00:00:32 1970 +0000
963 | : date: Thu Jan 01 00:00:32 1970 +0000
964 | : summary: (32) expand
964 | : summary: (32) expand
965 | :
965 | :
966 o : changeset: 31:621d83e11f67
966 o : changeset: 31:621d83e11f67
967 |\: parent: 21:d42a756af44d
967 |\: parent: 21:d42a756af44d
968 | : parent: 30:6e11cd4b648f
968 | : parent: 30:6e11cd4b648f
969 | : user: test
969 | : user: test
970 | : date: Thu Jan 01 00:00:31 1970 +0000
970 | : date: Thu Jan 01 00:00:31 1970 +0000
971 | : summary: (31) expand
971 | : summary: (31) expand
972 | :
972 | :
973 o : changeset: 30:6e11cd4b648f
973 o : changeset: 30:6e11cd4b648f
974 |\ \ parent: 28:44ecd0b9ae99
974 |\ \ parent: 28:44ecd0b9ae99
975 | ~ : parent: 29:cd9bb2be7593
975 | ~ : parent: 29:cd9bb2be7593
976 | : user: test
976 | : user: test
977 | : date: Thu Jan 01 00:00:30 1970 +0000
977 | : date: Thu Jan 01 00:00:30 1970 +0000
978 | : summary: (30) expand
978 | : summary: (30) expand
979 | /
979 | /
980 o : changeset: 28:44ecd0b9ae99
980 o : changeset: 28:44ecd0b9ae99
981 |\ \ parent: 1:6db2ef61d156
981 |\ \ parent: 1:6db2ef61d156
982 | ~ : parent: 26:7f25b6c2f0b9
982 | ~ : parent: 26:7f25b6c2f0b9
983 | : user: test
983 | : user: test
984 | : date: Thu Jan 01 00:00:28 1970 +0000
984 | : date: Thu Jan 01 00:00:28 1970 +0000
985 | : summary: (28) merge zero known
985 | : summary: (28) merge zero known
986 | /
986 | /
987 o : changeset: 26:7f25b6c2f0b9
987 o : changeset: 26:7f25b6c2f0b9
988 |\ \ parent: 18:1aa84d96232a
988 |\ \ parent: 18:1aa84d96232a
989 | | : parent: 25:91da8ed57247
989 | | : parent: 25:91da8ed57247
990 | | : user: test
990 | | : user: test
991 | | : date: Thu Jan 01 00:00:26 1970 +0000
991 | | : date: Thu Jan 01 00:00:26 1970 +0000
992 | | : summary: (26) merge one known; far right
992 | | : summary: (26) merge one known; far right
993 | | :
993 | | :
994 | o : changeset: 25:91da8ed57247
994 | o : changeset: 25:91da8ed57247
995 | |\: parent: 21:d42a756af44d
995 | |\: parent: 21:d42a756af44d
996 | | : parent: 24:a9c19a3d96b7
996 | | : parent: 24:a9c19a3d96b7
997 | | : user: test
997 | | : user: test
998 | | : date: Thu Jan 01 00:00:25 1970 +0000
998 | | : date: Thu Jan 01 00:00:25 1970 +0000
999 | | : summary: (25) merge one known; far left
999 | | : summary: (25) merge one known; far left
1000 | | :
1000 | | :
1001 | o : changeset: 24:a9c19a3d96b7
1001 | o : changeset: 24:a9c19a3d96b7
1002 | |\ \ parent: 0:e6eb3150255d
1002 | |\ \ parent: 0:e6eb3150255d
1003 | | ~ : parent: 23:a01cddf0766d
1003 | | ~ : parent: 23:a01cddf0766d
1004 | | : user: test
1004 | | : user: test
1005 | | : date: Thu Jan 01 00:00:24 1970 +0000
1005 | | : date: Thu Jan 01 00:00:24 1970 +0000
1006 | | : summary: (24) merge one known; immediate right
1006 | | : summary: (24) merge one known; immediate right
1007 | | /
1007 | | /
1008 | o : changeset: 23:a01cddf0766d
1008 | o : changeset: 23:a01cddf0766d
1009 | |\ \ parent: 1:6db2ef61d156
1009 | |\ \ parent: 1:6db2ef61d156
1010 | | ~ : parent: 22:e0d9cccacb5d
1010 | | ~ : parent: 22:e0d9cccacb5d
1011 | | : user: test
1011 | | : user: test
1012 | | : date: Thu Jan 01 00:00:23 1970 +0000
1012 | | : date: Thu Jan 01 00:00:23 1970 +0000
1013 | | : summary: (23) merge one known; immediate left
1013 | | : summary: (23) merge one known; immediate left
1014 | | /
1014 | | /
1015 | o : changeset: 22:e0d9cccacb5d
1015 | o : changeset: 22:e0d9cccacb5d
1016 |/:/ parent: 18:1aa84d96232a
1016 |/:/ parent: 18:1aa84d96232a
1017 | : parent: 21:d42a756af44d
1017 | : parent: 21:d42a756af44d
1018 | : user: test
1018 | : user: test
1019 | : date: Thu Jan 01 00:00:22 1970 +0000
1019 | : date: Thu Jan 01 00:00:22 1970 +0000
1020 | : summary: (22) merge two known; one far left, one far right
1020 | : summary: (22) merge two known; one far left, one far right
1021 | :
1021 | :
1022 | o changeset: 21:d42a756af44d
1022 | o changeset: 21:d42a756af44d
1023 | |\ parent: 19:31ddc2c1573b
1023 | |\ parent: 19:31ddc2c1573b
1024 | | | parent: 20:d30ed6450e32
1024 | | | parent: 20:d30ed6450e32
1025 | | | user: test
1025 | | | user: test
1026 | | | date: Thu Jan 01 00:00:21 1970 +0000
1026 | | | date: Thu Jan 01 00:00:21 1970 +0000
1027 | | | summary: (21) expand
1027 | | | summary: (21) expand
1028 | | |
1028 | | |
1029 +---o changeset: 20:d30ed6450e32
1029 +---o changeset: 20:d30ed6450e32
1030 | | | parent: 0:e6eb3150255d
1030 | | | parent: 0:e6eb3150255d
1031 | | ~ parent: 18:1aa84d96232a
1031 | | ~ parent: 18:1aa84d96232a
1032 | | user: test
1032 | | user: test
1033 | | date: Thu Jan 01 00:00:20 1970 +0000
1033 | | date: Thu Jan 01 00:00:20 1970 +0000
1034 | | summary: (20) merge two known; two far right
1034 | | summary: (20) merge two known; two far right
1035 | |
1035 | |
1036 | o changeset: 19:31ddc2c1573b
1036 | o changeset: 19:31ddc2c1573b
1037 | |\ parent: 15:1dda3f72782d
1037 | |\ parent: 15:1dda3f72782d
1038 | | | parent: 17:44765d7c06e0
1038 | | | parent: 17:44765d7c06e0
1039 | | | user: test
1039 | | | user: test
1040 | | | date: Thu Jan 01 00:00:19 1970 +0000
1040 | | | date: Thu Jan 01 00:00:19 1970 +0000
1041 | | | summary: (19) expand
1041 | | | summary: (19) expand
1042 | | |
1042 | | |
1043 o | | changeset: 18:1aa84d96232a
1043 o | | changeset: 18:1aa84d96232a
1044 |\| | parent: 1:6db2ef61d156
1044 |\| | parent: 1:6db2ef61d156
1045 ~ | | parent: 15:1dda3f72782d
1045 ~ | | parent: 15:1dda3f72782d
1046 | | user: test
1046 | | user: test
1047 | | date: Thu Jan 01 00:00:18 1970 +0000
1047 | | date: Thu Jan 01 00:00:18 1970 +0000
1048 | | summary: (18) merge two known; two far left
1048 | | summary: (18) merge two known; two far left
1049 / /
1049 / /
1050 | o changeset: 17:44765d7c06e0
1050 | o changeset: 17:44765d7c06e0
1051 | |\ parent: 12:86b91144a6e9
1051 | |\ parent: 12:86b91144a6e9
1052 | | | parent: 16:3677d192927d
1052 | | | parent: 16:3677d192927d
1053 | | | user: test
1053 | | | user: test
1054 | | | date: Thu Jan 01 00:00:17 1970 +0000
1054 | | | date: Thu Jan 01 00:00:17 1970 +0000
1055 | | | summary: (17) expand
1055 | | | summary: (17) expand
1056 | | |
1056 | | |
1057 | | o changeset: 16:3677d192927d
1057 | | o changeset: 16:3677d192927d
1058 | | |\ parent: 0:e6eb3150255d
1058 | | |\ parent: 0:e6eb3150255d
1059 | | ~ ~ parent: 1:6db2ef61d156
1059 | | ~ ~ parent: 1:6db2ef61d156
1060 | | user: test
1060 | | user: test
1061 | | date: Thu Jan 01 00:00:16 1970 +0000
1061 | | date: Thu Jan 01 00:00:16 1970 +0000
1062 | | summary: (16) merge two known; one immediate right, one near right
1062 | | summary: (16) merge two known; one immediate right, one near right
1063 | |
1063 | |
1064 o | changeset: 15:1dda3f72782d
1064 o | changeset: 15:1dda3f72782d
1065 |\ \ parent: 13:22d8966a97e3
1065 |\ \ parent: 13:22d8966a97e3
1066 | | | parent: 14:8eac370358ef
1066 | | | parent: 14:8eac370358ef
1067 | | | user: test
1067 | | | user: test
1068 | | | date: Thu Jan 01 00:00:15 1970 +0000
1068 | | | date: Thu Jan 01 00:00:15 1970 +0000
1069 | | | summary: (15) expand
1069 | | | summary: (15) expand
1070 | | |
1070 | | |
1071 | o | changeset: 14:8eac370358ef
1071 | o | changeset: 14:8eac370358ef
1072 | |\| parent: 0:e6eb3150255d
1072 | |\| parent: 0:e6eb3150255d
1073 | ~ | parent: 12:86b91144a6e9
1073 | ~ | parent: 12:86b91144a6e9
1074 | | user: test
1074 | | user: test
1075 | | date: Thu Jan 01 00:00:14 1970 +0000
1075 | | date: Thu Jan 01 00:00:14 1970 +0000
1076 | | summary: (14) merge two known; one immediate right, one far right
1076 | | summary: (14) merge two known; one immediate right, one far right
1077 | /
1077 | /
1078 o | changeset: 13:22d8966a97e3
1078 o | changeset: 13:22d8966a97e3
1079 |\ \ parent: 9:7010c0af0a35
1079 |\ \ parent: 9:7010c0af0a35
1080 | | | parent: 11:832d76e6bdf2
1080 | | | parent: 11:832d76e6bdf2
1081 | | | user: test
1081 | | | user: test
1082 | | | date: Thu Jan 01 00:00:13 1970 +0000
1082 | | | date: Thu Jan 01 00:00:13 1970 +0000
1083 | | | summary: (13) expand
1083 | | | summary: (13) expand
1084 | | |
1084 | | |
1085 +---o changeset: 12:86b91144a6e9
1085 +---o changeset: 12:86b91144a6e9
1086 | | | parent: 1:6db2ef61d156
1086 | | | parent: 1:6db2ef61d156
1087 | | ~ parent: 9:7010c0af0a35
1087 | | ~ parent: 9:7010c0af0a35
1088 | | user: test
1088 | | user: test
1089 | | date: Thu Jan 01 00:00:12 1970 +0000
1089 | | date: Thu Jan 01 00:00:12 1970 +0000
1090 | | summary: (12) merge two known; one immediate right, one far left
1090 | | summary: (12) merge two known; one immediate right, one far left
1091 | |
1091 | |
1092 | o changeset: 11:832d76e6bdf2
1092 | o changeset: 11:832d76e6bdf2
1093 | |\ parent: 6:b105a072e251
1093 | |\ parent: 6:b105a072e251
1094 | | | parent: 10:74c64d036d72
1094 | | | parent: 10:74c64d036d72
1095 | | | user: test
1095 | | | user: test
1096 | | | date: Thu Jan 01 00:00:11 1970 +0000
1096 | | | date: Thu Jan 01 00:00:11 1970 +0000
1097 | | | summary: (11) expand
1097 | | | summary: (11) expand
1098 | | |
1098 | | |
1099 | | o changeset: 10:74c64d036d72
1099 | | o changeset: 10:74c64d036d72
1100 | |/| parent: 0:e6eb3150255d
1100 | |/| parent: 0:e6eb3150255d
1101 | | ~ parent: 6:b105a072e251
1101 | | ~ parent: 6:b105a072e251
1102 | | user: test
1102 | | user: test
1103 | | date: Thu Jan 01 00:00:10 1970 +0000
1103 | | date: Thu Jan 01 00:00:10 1970 +0000
1104 | | summary: (10) merge two known; one immediate left, one near right
1104 | | summary: (10) merge two known; one immediate left, one near right
1105 | |
1105 | |
1106 o | changeset: 9:7010c0af0a35
1106 o | changeset: 9:7010c0af0a35
1107 |\ \ parent: 7:b632bb1b1224
1107 |\ \ parent: 7:b632bb1b1224
1108 | | | parent: 8:7a0b11f71937
1108 | | | parent: 8:7a0b11f71937
1109 | | | user: test
1109 | | | user: test
1110 | | | date: Thu Jan 01 00:00:09 1970 +0000
1110 | | | date: Thu Jan 01 00:00:09 1970 +0000
1111 | | | summary: (9) expand
1111 | | | summary: (9) expand
1112 | | |
1112 | | |
1113 | o | changeset: 8:7a0b11f71937
1113 | o | changeset: 8:7a0b11f71937
1114 |/| | parent: 0:e6eb3150255d
1114 |/| | parent: 0:e6eb3150255d
1115 | ~ | parent: 7:b632bb1b1224
1115 | ~ | parent: 7:b632bb1b1224
1116 | | user: test
1116 | | user: test
1117 | | date: Thu Jan 01 00:00:08 1970 +0000
1117 | | date: Thu Jan 01 00:00:08 1970 +0000
1118 | | summary: (8) merge two known; one immediate left, one far right
1118 | | summary: (8) merge two known; one immediate left, one far right
1119 | /
1119 | /
1120 o | changeset: 7:b632bb1b1224
1120 o | changeset: 7:b632bb1b1224
1121 |\ \ parent: 2:3d9a33b8d1e1
1121 |\ \ parent: 2:3d9a33b8d1e1
1122 | ~ | parent: 5:4409d547b708
1122 | ~ | parent: 5:4409d547b708
1123 | | user: test
1123 | | user: test
1124 | | date: Thu Jan 01 00:00:07 1970 +0000
1124 | | date: Thu Jan 01 00:00:07 1970 +0000
1125 | | summary: (7) expand
1125 | | summary: (7) expand
1126 | /
1126 | /
1127 | o changeset: 6:b105a072e251
1127 | o changeset: 6:b105a072e251
1128 |/| parent: 2:3d9a33b8d1e1
1128 |/| parent: 2:3d9a33b8d1e1
1129 | ~ parent: 5:4409d547b708
1129 | ~ parent: 5:4409d547b708
1130 | user: test
1130 | user: test
1131 | date: Thu Jan 01 00:00:06 1970 +0000
1131 | date: Thu Jan 01 00:00:06 1970 +0000
1132 | summary: (6) merge two known; one immediate left, one far left
1132 | summary: (6) merge two known; one immediate left, one far left
1133 |
1133 |
1134 o changeset: 5:4409d547b708
1134 o changeset: 5:4409d547b708
1135 |\ parent: 3:27eef8ed80b4
1135 |\ parent: 3:27eef8ed80b4
1136 | ~ parent: 4:26a8bac39d9f
1136 | ~ parent: 4:26a8bac39d9f
1137 | user: test
1137 | user: test
1138 | date: Thu Jan 01 00:00:05 1970 +0000
1138 | date: Thu Jan 01 00:00:05 1970 +0000
1139 | summary: (5) expand
1139 | summary: (5) expand
1140 |
1140 |
1141 o changeset: 4:26a8bac39d9f
1141 o changeset: 4:26a8bac39d9f
1142 |\ parent: 1:6db2ef61d156
1142 |\ parent: 1:6db2ef61d156
1143 ~ ~ parent: 3:27eef8ed80b4
1143 ~ ~ parent: 3:27eef8ed80b4
1144 user: test
1144 user: test
1145 date: Thu Jan 01 00:00:04 1970 +0000
1145 date: Thu Jan 01 00:00:04 1970 +0000
1146 summary: (4) merge two known; one immediate left, one immediate right
1146 summary: (4) merge two known; one immediate left, one immediate right
1147
1147
1148
1148
1149
1149
1150 Empty revision range - display nothing:
1150 Empty revision range - display nothing:
1151 $ hg log -G -r 1..0
1151 $ hg log -G -r 1..0
1152
1152
1153 $ cd ..
1153 $ cd ..
1154
1154
1155 #if no-outer-repo
1155 #if no-outer-repo
1156
1156
1157 From outer space:
1157 From outer space:
1158 $ hg log -G -l1 repo
1158 $ hg log -G -l1 repo
1159 @ changeset: 34:fea3ac5810e0
1159 @ changeset: 34:fea3ac5810e0
1160 | tag: tip
1160 | tag: tip
1161 ~ parent: 32:d06dffa21a31
1161 ~ parent: 32:d06dffa21a31
1162 user: test
1162 user: test
1163 date: Thu Jan 01 00:00:34 1970 +0000
1163 date: Thu Jan 01 00:00:34 1970 +0000
1164 summary: (34) head
1164 summary: (34) head
1165
1165
1166 $ hg log -G -l1 repo/a
1166 $ hg log -G -l1 repo/a
1167 @ changeset: 34:fea3ac5810e0
1167 @ changeset: 34:fea3ac5810e0
1168 | tag: tip
1168 | tag: tip
1169 ~ parent: 32:d06dffa21a31
1169 ~ parent: 32:d06dffa21a31
1170 user: test
1170 user: test
1171 date: Thu Jan 01 00:00:34 1970 +0000
1171 date: Thu Jan 01 00:00:34 1970 +0000
1172 summary: (34) head
1172 summary: (34) head
1173
1173
1174 $ hg log -G -l1 repo/missing
1174 $ hg log -G -l1 repo/missing
1175
1175
1176 #endif
1176 #endif
1177
1177
1178 File log with revs != cset revs:
1178 File log with revs != cset revs:
1179 $ hg init flog
1179 $ hg init flog
1180 $ cd flog
1180 $ cd flog
1181 $ echo one >one
1181 $ echo one >one
1182 $ hg add one
1182 $ hg add one
1183 $ hg commit -mone
1183 $ hg commit -mone
1184 $ echo two >two
1184 $ echo two >two
1185 $ hg add two
1185 $ hg add two
1186 $ hg commit -mtwo
1186 $ hg commit -mtwo
1187 $ echo more >two
1187 $ echo more >two
1188 $ hg commit -mmore
1188 $ hg commit -mmore
1189 $ hg log -G two
1189 $ hg log -G two
1190 @ changeset: 2:12c28321755b
1190 @ changeset: 2:12c28321755b
1191 | tag: tip
1191 | tag: tip
1192 | user: test
1192 | user: test
1193 | date: Thu Jan 01 00:00:00 1970 +0000
1193 | date: Thu Jan 01 00:00:00 1970 +0000
1194 | summary: more
1194 | summary: more
1195 |
1195 |
1196 o changeset: 1:5ac72c0599bf
1196 o changeset: 1:5ac72c0599bf
1197 | user: test
1197 | user: test
1198 ~ date: Thu Jan 01 00:00:00 1970 +0000
1198 ~ date: Thu Jan 01 00:00:00 1970 +0000
1199 summary: two
1199 summary: two
1200
1200
1201
1201
1202 Issue1896: File log with explicit style
1202 Issue1896: File log with explicit style
1203 $ hg log -G --style=default one
1203 $ hg log -G --style=default one
1204 o changeset: 0:3d578b4a1f53
1204 o changeset: 0:3d578b4a1f53
1205 user: test
1205 user: test
1206 date: Thu Jan 01 00:00:00 1970 +0000
1206 date: Thu Jan 01 00:00:00 1970 +0000
1207 summary: one
1207 summary: one
1208
1208
1209 Issue2395: glog --style header and footer
1209 Issue2395: glog --style header and footer
1210 $ hg log -G --style=xml one
1210 $ hg log -G --style=xml one
1211 <?xml version="1.0"?>
1211 <?xml version="1.0"?>
1212 <log>
1212 <log>
1213 o <logentry revision="0" node="3d578b4a1f537d5fcf7301bfa9c0b97adfaa6fb1">
1213 o <logentry revision="0" node="3d578b4a1f537d5fcf7301bfa9c0b97adfaa6fb1">
1214 <author email="test">test</author>
1214 <author email="test">test</author>
1215 <date>1970-01-01T00:00:00+00:00</date>
1215 <date>1970-01-01T00:00:00+00:00</date>
1216 <msg xml:space="preserve">one</msg>
1216 <msg xml:space="preserve">one</msg>
1217 </logentry>
1217 </logentry>
1218 </log>
1218 </log>
1219
1219
1220 $ cd ..
1220 $ cd ..
1221
1221
1222 Incoming and outgoing:
1222 Incoming and outgoing:
1223
1223
1224 $ hg clone -U -r31 repo repo2
1224 $ hg clone -U -r31 repo repo2
1225 adding changesets
1225 adding changesets
1226 adding manifests
1226 adding manifests
1227 adding file changes
1227 adding file changes
1228 added 31 changesets with 31 changes to 1 files
1228 added 31 changesets with 31 changes to 1 files
1229 new changesets e6eb3150255d:621d83e11f67
1229 new changesets e6eb3150255d:621d83e11f67
1230 $ cd repo2
1230 $ cd repo2
1231
1231
1232 $ hg incoming --graph ../repo
1232 $ hg incoming --graph ../repo
1233 comparing with ../repo
1233 comparing with ../repo
1234 searching for changes
1234 searching for changes
1235 o changeset: 34:fea3ac5810e0
1235 o changeset: 34:fea3ac5810e0
1236 | tag: tip
1236 | tag: tip
1237 | parent: 32:d06dffa21a31
1237 | parent: 32:d06dffa21a31
1238 | user: test
1238 | user: test
1239 | date: Thu Jan 01 00:00:34 1970 +0000
1239 | date: Thu Jan 01 00:00:34 1970 +0000
1240 | summary: (34) head
1240 | summary: (34) head
1241 |
1241 |
1242 | o changeset: 33:68608f5145f9
1242 | o changeset: 33:68608f5145f9
1243 | parent: 18:1aa84d96232a
1243 | parent: 18:1aa84d96232a
1244 | user: test
1244 | user: test
1245 | date: Thu Jan 01 00:00:33 1970 +0000
1245 | date: Thu Jan 01 00:00:33 1970 +0000
1246 | summary: (33) head
1246 | summary: (33) head
1247 |
1247 |
1248 o changeset: 32:d06dffa21a31
1248 o changeset: 32:d06dffa21a31
1249 | parent: 27:886ed638191b
1249 | parent: 27:886ed638191b
1250 | parent: 31:621d83e11f67
1250 | parent: 31:621d83e11f67
1251 | user: test
1251 | user: test
1252 | date: Thu Jan 01 00:00:32 1970 +0000
1252 | date: Thu Jan 01 00:00:32 1970 +0000
1253 | summary: (32) expand
1253 | summary: (32) expand
1254 |
1254 |
1255 o changeset: 27:886ed638191b
1255 o changeset: 27:886ed638191b
1256 parent: 21:d42a756af44d
1256 parent: 21:d42a756af44d
1257 user: test
1257 user: test
1258 date: Thu Jan 01 00:00:27 1970 +0000
1258 date: Thu Jan 01 00:00:27 1970 +0000
1259 summary: (27) collapse
1259 summary: (27) collapse
1260
1260
1261 $ cd ..
1261 $ cd ..
1262
1262
1263 $ hg -R repo outgoing --graph repo2
1263 $ hg -R repo outgoing --graph repo2
1264 comparing with repo2
1264 comparing with repo2
1265 searching for changes
1265 searching for changes
1266 @ changeset: 34:fea3ac5810e0
1266 @ changeset: 34:fea3ac5810e0
1267 | tag: tip
1267 | tag: tip
1268 | parent: 32:d06dffa21a31
1268 | parent: 32:d06dffa21a31
1269 | user: test
1269 | user: test
1270 | date: Thu Jan 01 00:00:34 1970 +0000
1270 | date: Thu Jan 01 00:00:34 1970 +0000
1271 | summary: (34) head
1271 | summary: (34) head
1272 |
1272 |
1273 | o changeset: 33:68608f5145f9
1273 | o changeset: 33:68608f5145f9
1274 | parent: 18:1aa84d96232a
1274 | parent: 18:1aa84d96232a
1275 | user: test
1275 | user: test
1276 | date: Thu Jan 01 00:00:33 1970 +0000
1276 | date: Thu Jan 01 00:00:33 1970 +0000
1277 | summary: (33) head
1277 | summary: (33) head
1278 |
1278 |
1279 o changeset: 32:d06dffa21a31
1279 o changeset: 32:d06dffa21a31
1280 | parent: 27:886ed638191b
1280 | parent: 27:886ed638191b
1281 | parent: 31:621d83e11f67
1281 | parent: 31:621d83e11f67
1282 | user: test
1282 | user: test
1283 | date: Thu Jan 01 00:00:32 1970 +0000
1283 | date: Thu Jan 01 00:00:32 1970 +0000
1284 | summary: (32) expand
1284 | summary: (32) expand
1285 |
1285 |
1286 o changeset: 27:886ed638191b
1286 o changeset: 27:886ed638191b
1287 parent: 21:d42a756af44d
1287 parent: 21:d42a756af44d
1288 user: test
1288 user: test
1289 date: Thu Jan 01 00:00:27 1970 +0000
1289 date: Thu Jan 01 00:00:27 1970 +0000
1290 summary: (27) collapse
1290 summary: (27) collapse
1291
1291
1292
1292
1293 File + limit with revs != cset revs:
1293 File + limit with revs != cset revs:
1294 $ cd repo
1294 $ cd repo
1295 $ touch b
1295 $ touch b
1296 $ hg ci -Aqm0
1296 $ hg ci -Aqm0
1297 $ hg log -G -l2 a
1297 $ hg log -G -l2 a
1298 o changeset: 34:fea3ac5810e0
1298 o changeset: 34:fea3ac5810e0
1299 | parent: 32:d06dffa21a31
1299 | parent: 32:d06dffa21a31
1300 ~ user: test
1300 ~ user: test
1301 date: Thu Jan 01 00:00:34 1970 +0000
1301 date: Thu Jan 01 00:00:34 1970 +0000
1302 summary: (34) head
1302 summary: (34) head
1303
1303
1304 o changeset: 33:68608f5145f9
1304 o changeset: 33:68608f5145f9
1305 | parent: 18:1aa84d96232a
1305 | parent: 18:1aa84d96232a
1306 ~ user: test
1306 ~ user: test
1307 date: Thu Jan 01 00:00:33 1970 +0000
1307 date: Thu Jan 01 00:00:33 1970 +0000
1308 summary: (33) head
1308 summary: (33) head
1309
1309
1310
1310
1311 File + limit + -ra:b, (b - a) < limit:
1311 File + limit + -ra:b, (b - a) < limit:
1312 $ hg log -G -l3000 -r32:tip a
1312 $ hg log -G -l3000 -r32:tip a
1313 o changeset: 34:fea3ac5810e0
1313 o changeset: 34:fea3ac5810e0
1314 | parent: 32:d06dffa21a31
1314 | parent: 32:d06dffa21a31
1315 | user: test
1315 | user: test
1316 | date: Thu Jan 01 00:00:34 1970 +0000
1316 | date: Thu Jan 01 00:00:34 1970 +0000
1317 | summary: (34) head
1317 | summary: (34) head
1318 |
1318 |
1319 | o changeset: 33:68608f5145f9
1319 | o changeset: 33:68608f5145f9
1320 | | parent: 18:1aa84d96232a
1320 | | parent: 18:1aa84d96232a
1321 | ~ user: test
1321 | ~ user: test
1322 | date: Thu Jan 01 00:00:33 1970 +0000
1322 | date: Thu Jan 01 00:00:33 1970 +0000
1323 | summary: (33) head
1323 | summary: (33) head
1324 |
1324 |
1325 o changeset: 32:d06dffa21a31
1325 o changeset: 32:d06dffa21a31
1326 |\ parent: 27:886ed638191b
1326 |\ parent: 27:886ed638191b
1327 ~ ~ parent: 31:621d83e11f67
1327 ~ ~ parent: 31:621d83e11f67
1328 user: test
1328 user: test
1329 date: Thu Jan 01 00:00:32 1970 +0000
1329 date: Thu Jan 01 00:00:32 1970 +0000
1330 summary: (32) expand
1330 summary: (32) expand
1331
1331
1332
1332
1333 Point out a common and an uncommon unshown parent
1333 Point out a common and an uncommon unshown parent
1334
1334
1335 $ hg log -G -r 'rev(8) or rev(9)'
1335 $ hg log -G -r 'rev(8) or rev(9)'
1336 o changeset: 9:7010c0af0a35
1336 o changeset: 9:7010c0af0a35
1337 |\ parent: 7:b632bb1b1224
1337 |\ parent: 7:b632bb1b1224
1338 | ~ parent: 8:7a0b11f71937
1338 | ~ parent: 8:7a0b11f71937
1339 | user: test
1339 | user: test
1340 | date: Thu Jan 01 00:00:09 1970 +0000
1340 | date: Thu Jan 01 00:00:09 1970 +0000
1341 | summary: (9) expand
1341 | summary: (9) expand
1342 |
1342 |
1343 o changeset: 8:7a0b11f71937
1343 o changeset: 8:7a0b11f71937
1344 |\ parent: 0:e6eb3150255d
1344 |\ parent: 0:e6eb3150255d
1345 ~ ~ parent: 7:b632bb1b1224
1345 ~ ~ parent: 7:b632bb1b1224
1346 user: test
1346 user: test
1347 date: Thu Jan 01 00:00:08 1970 +0000
1347 date: Thu Jan 01 00:00:08 1970 +0000
1348 summary: (8) merge two known; one immediate left, one far right
1348 summary: (8) merge two known; one immediate left, one far right
1349
1349
1350
1350
1351 File + limit + -ra:b, b < tip:
1351 File + limit + -ra:b, b < tip:
1352
1352
1353 $ hg log -G -l1 -r32:34 a
1353 $ hg log -G -l1 -r32:34 a
1354 o changeset: 34:fea3ac5810e0
1354 o changeset: 34:fea3ac5810e0
1355 | parent: 32:d06dffa21a31
1355 | parent: 32:d06dffa21a31
1356 ~ user: test
1356 ~ user: test
1357 date: Thu Jan 01 00:00:34 1970 +0000
1357 date: Thu Jan 01 00:00:34 1970 +0000
1358 summary: (34) head
1358 summary: (34) head
1359
1359
1360
1360
1361 file(File) + limit + -ra:b, b < tip:
1361 file(File) + limit + -ra:b, b < tip:
1362
1362
1363 $ hg log -G -l1 -r32:34 -r 'file("a")'
1363 $ hg log -G -l1 -r32:34 -r 'file("a")'
1364 o changeset: 34:fea3ac5810e0
1364 o changeset: 34:fea3ac5810e0
1365 | parent: 32:d06dffa21a31
1365 | parent: 32:d06dffa21a31
1366 ~ user: test
1366 ~ user: test
1367 date: Thu Jan 01 00:00:34 1970 +0000
1367 date: Thu Jan 01 00:00:34 1970 +0000
1368 summary: (34) head
1368 summary: (34) head
1369
1369
1370
1370
1371 limit(file(File) and a::b), b < tip:
1371 limit(file(File) and a::b), b < tip:
1372
1372
1373 $ hg log -G -r 'limit(file("a") and 32::34, 1)'
1373 $ hg log -G -r 'limit(file("a") and 32::34, 1)'
1374 o changeset: 32:d06dffa21a31
1374 o changeset: 32:d06dffa21a31
1375 |\ parent: 27:886ed638191b
1375 |\ parent: 27:886ed638191b
1376 ~ ~ parent: 31:621d83e11f67
1376 ~ ~ parent: 31:621d83e11f67
1377 user: test
1377 user: test
1378 date: Thu Jan 01 00:00:32 1970 +0000
1378 date: Thu Jan 01 00:00:32 1970 +0000
1379 summary: (32) expand
1379 summary: (32) expand
1380
1380
1381
1381
1382 File + limit + -ra:b, b < tip:
1382 File + limit + -ra:b, b < tip:
1383
1383
1384 $ hg log -G -r 'limit(file("a") and 34::32, 1)'
1384 $ hg log -G -r 'limit(file("a") and 34::32, 1)'
1385
1385
1386 File + limit + -ra:b, b < tip, (b - a) < limit:
1386 File + limit + -ra:b, b < tip, (b - a) < limit:
1387
1387
1388 $ hg log -G -l10 -r33:34 a
1388 $ hg log -G -l10 -r33:34 a
1389 o changeset: 34:fea3ac5810e0
1389 o changeset: 34:fea3ac5810e0
1390 | parent: 32:d06dffa21a31
1390 | parent: 32:d06dffa21a31
1391 ~ user: test
1391 ~ user: test
1392 date: Thu Jan 01 00:00:34 1970 +0000
1392 date: Thu Jan 01 00:00:34 1970 +0000
1393 summary: (34) head
1393 summary: (34) head
1394
1394
1395 o changeset: 33:68608f5145f9
1395 o changeset: 33:68608f5145f9
1396 | parent: 18:1aa84d96232a
1396 | parent: 18:1aa84d96232a
1397 ~ user: test
1397 ~ user: test
1398 date: Thu Jan 01 00:00:33 1970 +0000
1398 date: Thu Jan 01 00:00:33 1970 +0000
1399 summary: (33) head
1399 summary: (33) head
1400
1400
1401
1401
1402 Do not crash or produce strange graphs if history is buggy
1402 Do not crash or produce strange graphs if history is buggy
1403
1403
1404 $ hg branch branch
1404 $ hg branch branch
1405 marked working directory as branch branch
1405 marked working directory as branch branch
1406 (branches are permanent and global, did you want a bookmark?)
1406 (branches are permanent and global, did you want a bookmark?)
1407 $ commit 36 "buggy merge: identical parents" 35 35
1407 $ commit 36 "buggy merge: identical parents" 35 35
1408 $ hg log -G -l5
1408 $ hg log -G -l5
1409 @ changeset: 36:08a19a744424
1409 @ changeset: 36:08a19a744424
1410 | branch: branch
1410 | branch: branch
1411 | tag: tip
1411 | tag: tip
1412 | parent: 35:9159c3644c5e
1412 | parent: 35:9159c3644c5e
1413 | parent: 35:9159c3644c5e
1413 | parent: 35:9159c3644c5e
1414 | user: test
1414 | user: test
1415 | date: Thu Jan 01 00:00:36 1970 +0000
1415 | date: Thu Jan 01 00:00:36 1970 +0000
1416 | summary: (36) buggy merge: identical parents
1416 | summary: (36) buggy merge: identical parents
1417 |
1417 |
1418 o changeset: 35:9159c3644c5e
1418 o changeset: 35:9159c3644c5e
1419 | user: test
1419 | user: test
1420 | date: Thu Jan 01 00:00:00 1970 +0000
1420 | date: Thu Jan 01 00:00:00 1970 +0000
1421 | summary: 0
1421 | summary: 0
1422 |
1422 |
1423 o changeset: 34:fea3ac5810e0
1423 o changeset: 34:fea3ac5810e0
1424 | parent: 32:d06dffa21a31
1424 | parent: 32:d06dffa21a31
1425 | user: test
1425 | user: test
1426 | date: Thu Jan 01 00:00:34 1970 +0000
1426 | date: Thu Jan 01 00:00:34 1970 +0000
1427 | summary: (34) head
1427 | summary: (34) head
1428 |
1428 |
1429 | o changeset: 33:68608f5145f9
1429 | o changeset: 33:68608f5145f9
1430 | | parent: 18:1aa84d96232a
1430 | | parent: 18:1aa84d96232a
1431 | ~ user: test
1431 | ~ user: test
1432 | date: Thu Jan 01 00:00:33 1970 +0000
1432 | date: Thu Jan 01 00:00:33 1970 +0000
1433 | summary: (33) head
1433 | summary: (33) head
1434 |
1434 |
1435 o changeset: 32:d06dffa21a31
1435 o changeset: 32:d06dffa21a31
1436 |\ parent: 27:886ed638191b
1436 |\ parent: 27:886ed638191b
1437 ~ ~ parent: 31:621d83e11f67
1437 ~ ~ parent: 31:621d83e11f67
1438 user: test
1438 user: test
1439 date: Thu Jan 01 00:00:32 1970 +0000
1439 date: Thu Jan 01 00:00:32 1970 +0000
1440 summary: (32) expand
1440 summary: (32) expand
1441
1441
1442
1442
1443 Test log -G options
1443 Test log -G options
1444
1444
1445 $ testlog() {
1445 $ testlog() {
1446 > hg log -G --print-revset "$@"
1446 > hg log -G --print-revset "$@"
1447 > hg log --template 'nodetag {rev}\n' "$@" | grep nodetag \
1447 > hg log --template 'nodetag {rev}\n' "$@" | grep nodetag \
1448 > | sed 's/.*nodetag/nodetag/' > log.nodes
1448 > | sed 's/.*nodetag/nodetag/' > log.nodes
1449 > hg log -G --template 'nodetag {rev}\n' "$@" | grep nodetag \
1449 > hg log -G --template 'nodetag {rev}\n' "$@" | grep nodetag \
1450 > | sed 's/.*nodetag/nodetag/' > glog.nodes
1450 > | sed 's/.*nodetag/nodetag/' > glog.nodes
1451 > (cmp log.nodes glog.nodes || diff -u log.nodes glog.nodes) \
1451 > (cmp log.nodes glog.nodes || diff -u log.nodes glog.nodes) \
1452 > | grep '^[-+@ ]' || :
1452 > | grep '^[-+@ ]' || :
1453 > }
1453 > }
1454
1454
1455 glog always reorders nodes which explains the difference with log
1455 glog always reorders nodes which explains the difference with log
1456
1456
1457 $ testlog -r 27 -r 25 -r 21 -r 34 -r 32 -r 31
1457 $ testlog -r 27 -r 25 -r 21 -r 34 -r 32 -r 31
1458 ['27', '25', '21', '34', '32', '31']
1458 ['27', '25', '21', '34', '32', '31']
1459 []
1459 []
1460 <baseset- [21, 25, 27, 31, 32, 34]>
1460 <baseset- [21, 25, 27, 31, 32, 34]>
1461 --- log.nodes * (glob)
1461 --- log.nodes * (glob)
1462 +++ glog.nodes * (glob)
1462 +++ glog.nodes * (glob)
1463 @@ -1,6 +1,6 @@
1463 @@ -1,6 +1,6 @@
1464 -nodetag 27
1464 -nodetag 27
1465 -nodetag 25
1465 -nodetag 25
1466 -nodetag 21
1466 -nodetag 21
1467 nodetag 34
1467 nodetag 34
1468 nodetag 32
1468 nodetag 32
1469 nodetag 31
1469 nodetag 31
1470 +nodetag 27
1470 +nodetag 27
1471 +nodetag 25
1471 +nodetag 25
1472 +nodetag 21
1472 +nodetag 21
1473 $ testlog -u test -u not-a-user
1473 $ testlog -u test -u not-a-user
1474 []
1474 []
1475 (or
1475 (or
1476 (list
1476 (list
1477 (func
1477 (func
1478 (symbol 'user')
1478 (symbol 'user')
1479 (string 'test'))
1479 (string 'test'))
1480 (func
1480 (func
1481 (symbol 'user')
1481 (symbol 'user')
1482 (string 'not-a-user'))))
1482 (string 'not-a-user'))))
1483 <filteredset
1483 <filteredset
1484 <spanset- 0:37>,
1484 <spanset- 0:37>,
1485 <addset
1485 <addset
1486 <filteredset
1486 <filteredset
1487 <fullreposet+ 0:37>,
1487 <fullreposet+ 0:37>,
1488 <user 'test'>>,
1488 <user 'test'>>,
1489 <filteredset
1489 <filteredset
1490 <fullreposet+ 0:37>,
1490 <fullreposet+ 0:37>,
1491 <user 'not-a-user'>>>>
1491 <user 'not-a-user'>>>>
1492 $ testlog -b not-a-branch
1492 $ testlog -b not-a-branch
1493 abort: unknown revision 'not-a-branch'!
1493 abort: unknown revision 'not-a-branch'!
1494 abort: unknown revision 'not-a-branch'!
1494 abort: unknown revision 'not-a-branch'!
1495 abort: unknown revision 'not-a-branch'!
1495 abort: unknown revision 'not-a-branch'!
1496 $ testlog -b 35 -b 36 --only-branch branch
1496 $ testlog -b 35 -b 36 --only-branch branch
1497 []
1497 []
1498 (or
1498 (or
1499 (list
1499 (list
1500 (func
1500 (func
1501 (symbol 'branch')
1501 (symbol 'branch')
1502 (string 'default'))
1502 (string 'default'))
1503 (func
1503 (or
1504 (symbol 'branch')
1504 (list
1505 (string 'branch'))
1505 (func
1506 (func
1506 (symbol 'branch')
1507 (symbol 'branch')
1507 (string 'branch'))
1508 (string 'branch'))))
1508 (func
1509 (symbol 'branch')
1510 (string 'branch'))))))
1509 <filteredset
1511 <filteredset
1510 <spanset- 0:37>,
1512 <spanset- 0:37>,
1511 <addset
1513 <addset
1512 <filteredset
1514 <filteredset
1513 <fullreposet+ 0:37>,
1515 <fullreposet+ 0:37>,
1514 <branch 'default'>>,
1516 <branch 'default'>>,
1515 <addset
1517 <addset
1516 <filteredset
1518 <filteredset
1517 <fullreposet+ 0:37>,
1519 <fullreposet+ 0:37>,
1518 <branch 'branch'>>,
1520 <branch 'branch'>>,
1519 <filteredset
1521 <filteredset
1520 <fullreposet+ 0:37>,
1522 <fullreposet+ 0:37>,
1521 <branch 'branch'>>>>>
1523 <branch 'branch'>>>>>
1522 $ testlog -k expand -k merge
1524 $ testlog -k expand -k merge
1523 []
1525 []
1524 (or
1526 (or
1525 (list
1527 (list
1526 (func
1528 (func
1527 (symbol 'keyword')
1529 (symbol 'keyword')
1528 (string 'expand'))
1530 (string 'expand'))
1529 (func
1531 (func
1530 (symbol 'keyword')
1532 (symbol 'keyword')
1531 (string 'merge'))))
1533 (string 'merge'))))
1532 <filteredset
1534 <filteredset
1533 <spanset- 0:37>,
1535 <spanset- 0:37>,
1534 <addset
1536 <addset
1535 <filteredset
1537 <filteredset
1536 <fullreposet+ 0:37>,
1538 <fullreposet+ 0:37>,
1537 <keyword 'expand'>>,
1539 <keyword 'expand'>>,
1538 <filteredset
1540 <filteredset
1539 <fullreposet+ 0:37>,
1541 <fullreposet+ 0:37>,
1540 <keyword 'merge'>>>>
1542 <keyword 'merge'>>>>
1541 $ testlog --only-merges
1543 $ testlog --only-merges
1542 []
1544 []
1543 (func
1545 (func
1544 (symbol 'merge')
1546 (symbol 'merge')
1545 None)
1547 None)
1546 <filteredset
1548 <filteredset
1547 <spanset- 0:37>,
1549 <spanset- 0:37>,
1548 <merge>>
1550 <merge>>
1549 $ testlog --no-merges
1551 $ testlog --no-merges
1550 []
1552 []
1551 (not
1553 (not
1552 (func
1554 (func
1553 (symbol 'merge')
1555 (symbol 'merge')
1554 None))
1556 None))
1555 <filteredset
1557 <filteredset
1556 <spanset- 0:37>,
1558 <spanset- 0:37>,
1557 <not
1559 <not
1558 <filteredset
1560 <filteredset
1559 <spanset- 0:37>,
1561 <spanset- 0:37>,
1560 <merge>>>>
1562 <merge>>>>
1561 $ testlog --date '2 0 to 4 0'
1563 $ testlog --date '2 0 to 4 0'
1562 []
1564 []
1563 (func
1565 (func
1564 (symbol 'date')
1566 (symbol 'date')
1565 (string '2 0 to 4 0'))
1567 (string '2 0 to 4 0'))
1566 <filteredset
1568 <filteredset
1567 <spanset- 0:37>,
1569 <spanset- 0:37>,
1568 <date '2 0 to 4 0'>>
1570 <date '2 0 to 4 0'>>
1569 $ hg log -G -d 'brace ) in a date'
1571 $ hg log -G -d 'brace ) in a date'
1570 hg: parse error: invalid date: 'brace ) in a date'
1572 hg: parse error: invalid date: 'brace ) in a date'
1571 [255]
1573 [255]
1572 $ testlog --prune 31 --prune 32
1574 $ testlog --prune 31 --prune 32
1573 []
1575 []
1574 (and
1576 (not
1575 (not
1577 (or
1576 (func
1578 (list
1577 (symbol 'ancestors')
1579 (func
1578 (string '31')))
1580 (symbol 'ancestors')
1579 (not
1581 (string '31'))
1580 (func
1582 (func
1581 (symbol 'ancestors')
1583 (symbol 'ancestors')
1582 (string '32'))))
1584 (string '32')))))
1583 <filteredset
1585 <filteredset
1584 <filteredset
1586 <spanset- 0:37>,
1585 <spanset- 0:37>,
1587 <not
1586 <not
1588 <addset
1587 <filteredset
1589 <filteredset
1588 <spanset- 0:37>,
1590 <spanset- 0:37>,
1589 <generatorsetdesc+>>>>,
1591 <generatorsetdesc+>>,
1590 <not
1592 <filteredset
1591 <filteredset
1593 <spanset- 0:37>,
1592 <spanset- 0:37>,
1594 <generatorsetdesc+>>>>>
1593 <generatorsetdesc+>>>>
1594
1595
1595 Dedicated repo for --follow and paths filtering. The g is crafted to
1596 Dedicated repo for --follow and paths filtering. The g is crafted to
1596 have 2 filelog topological heads in a linear changeset graph.
1597 have 2 filelog topological heads in a linear changeset graph.
1597
1598
1598 $ cd ..
1599 $ cd ..
1599 $ hg init follow
1600 $ hg init follow
1600 $ cd follow
1601 $ cd follow
1601 $ testlog --follow
1602 $ testlog --follow
1602 []
1603 []
1603 []
1604 []
1604 <baseset []>
1605 <baseset []>
1605 $ testlog -rnull
1606 $ testlog -rnull
1606 ['null']
1607 ['null']
1607 []
1608 []
1608 <baseset [-1]>
1609 <baseset [-1]>
1609 $ echo a > a
1610 $ echo a > a
1610 $ echo aa > aa
1611 $ echo aa > aa
1611 $ echo f > f
1612 $ echo f > f
1612 $ hg ci -Am "add a" a aa f
1613 $ hg ci -Am "add a" a aa f
1613 $ hg cp a b
1614 $ hg cp a b
1614 $ hg cp f g
1615 $ hg cp f g
1615 $ hg ci -m "copy a b"
1616 $ hg ci -m "copy a b"
1616 $ mkdir dir
1617 $ mkdir dir
1617 $ hg mv b dir
1618 $ hg mv b dir
1618 $ echo g >> g
1619 $ echo g >> g
1619 $ echo f >> f
1620 $ echo f >> f
1620 $ hg ci -m "mv b dir/b"
1621 $ hg ci -m "mv b dir/b"
1621 $ hg mv a b
1622 $ hg mv a b
1622 $ hg cp -f f g
1623 $ hg cp -f f g
1623 $ echo a > d
1624 $ echo a > d
1624 $ hg add d
1625 $ hg add d
1625 $ hg ci -m "mv a b; add d"
1626 $ hg ci -m "mv a b; add d"
1626 $ hg mv dir/b e
1627 $ hg mv dir/b e
1627 $ hg ci -m "mv dir/b e"
1628 $ hg ci -m "mv dir/b e"
1628 $ hg log -G --template '({rev}) {desc|firstline}\n'
1629 $ hg log -G --template '({rev}) {desc|firstline}\n'
1629 @ (4) mv dir/b e
1630 @ (4) mv dir/b e
1630 |
1631 |
1631 o (3) mv a b; add d
1632 o (3) mv a b; add d
1632 |
1633 |
1633 o (2) mv b dir/b
1634 o (2) mv b dir/b
1634 |
1635 |
1635 o (1) copy a b
1636 o (1) copy a b
1636 |
1637 |
1637 o (0) add a
1638 o (0) add a
1638
1639
1639
1640
1640 $ testlog a
1641 $ testlog a
1641 []
1642 []
1642 (func
1643 (func
1643 (symbol 'filelog')
1644 (symbol 'filelog')
1644 (string 'a'))
1645 (string 'a'))
1645 <filteredset
1646 <filteredset
1646 <spanset- 0:5>, set([0])>
1647 <spanset- 0:5>, set([0])>
1647 $ testlog a b
1648 $ testlog a b
1648 []
1649 []
1649 (or
1650 (or
1650 (list
1651 (list
1651 (func
1652 (func
1652 (symbol 'filelog')
1653 (symbol 'filelog')
1653 (string 'a'))
1654 (string 'a'))
1654 (func
1655 (func
1655 (symbol 'filelog')
1656 (symbol 'filelog')
1656 (string 'b'))))
1657 (string 'b'))))
1657 <filteredset
1658 <filteredset
1658 <spanset- 0:5>,
1659 <spanset- 0:5>,
1659 <addset
1660 <addset
1660 <baseset+ [0]>,
1661 <baseset+ [0]>,
1661 <baseset+ [1]>>>
1662 <baseset+ [1]>>>
1662
1663
1663 Test falling back to slow path for non-existing files
1664 Test falling back to slow path for non-existing files
1664
1665
1665 $ testlog a c
1666 $ testlog a c
1666 []
1667 []
1667 (func
1668 (func
1668 (symbol '_matchfiles')
1669 (symbol '_matchfiles')
1669 (list
1670 (list
1670 (string 'r:')
1671 (string 'r:')
1671 (string 'd:relpath')
1672 (string 'd:relpath')
1672 (string 'p:a')
1673 (string 'p:a')
1673 (string 'p:c')))
1674 (string 'p:c')))
1674 <filteredset
1675 <filteredset
1675 <spanset- 0:5>,
1676 <spanset- 0:5>,
1676 <matchfiles patterns=['a', 'c'], include=[] exclude=[], default='relpath', rev=None>>
1677 <matchfiles patterns=['a', 'c'], include=[] exclude=[], default='relpath', rev=None>>
1677
1678
1678 Test multiple --include/--exclude/paths
1679 Test multiple --include/--exclude/paths
1679
1680
1680 $ testlog --include a --include e --exclude b --exclude e a e
1681 $ testlog --include a --include e --exclude b --exclude e a e
1681 []
1682 []
1682 (func
1683 (func
1683 (symbol '_matchfiles')
1684 (symbol '_matchfiles')
1684 (list
1685 (list
1685 (string 'r:')
1686 (string 'r:')
1686 (string 'd:relpath')
1687 (string 'd:relpath')
1687 (string 'p:a')
1688 (string 'p:a')
1688 (string 'p:e')
1689 (string 'p:e')
1689 (string 'i:a')
1690 (string 'i:a')
1690 (string 'i:e')
1691 (string 'i:e')
1691 (string 'x:b')
1692 (string 'x:b')
1692 (string 'x:e')))
1693 (string 'x:e')))
1693 <filteredset
1694 <filteredset
1694 <spanset- 0:5>,
1695 <spanset- 0:5>,
1695 <matchfiles patterns=['a', 'e'], include=['a', 'e'] exclude=['b', 'e'], default='relpath', rev=None>>
1696 <matchfiles patterns=['a', 'e'], include=['a', 'e'] exclude=['b', 'e'], default='relpath', rev=None>>
1696
1697
1697 Test glob expansion of pats
1698 Test glob expansion of pats
1698
1699
1699 $ expandglobs=`$PYTHON -c "import mercurial.util; \
1700 $ expandglobs=`$PYTHON -c "import mercurial.util; \
1700 > print(mercurial.util.expandglobs and 'true' or 'false')"`
1701 > print(mercurial.util.expandglobs and 'true' or 'false')"`
1701 $ if [ $expandglobs = "true" ]; then
1702 $ if [ $expandglobs = "true" ]; then
1702 > testlog 'a*';
1703 > testlog 'a*';
1703 > else
1704 > else
1704 > testlog a*;
1705 > testlog a*;
1705 > fi;
1706 > fi;
1706 []
1707 []
1707 (func
1708 (func
1708 (symbol 'filelog')
1709 (symbol 'filelog')
1709 (string 'aa'))
1710 (string 'aa'))
1710 <filteredset
1711 <filteredset
1711 <spanset- 0:5>, set([0])>
1712 <spanset- 0:5>, set([0])>
1712
1713
1713 Test --follow on a non-existent directory
1714 Test --follow on a non-existent directory
1714
1715
1715 $ testlog -f dir
1716 $ testlog -f dir
1716 abort: cannot follow file not in parent revision: "dir"
1717 abort: cannot follow file not in parent revision: "dir"
1717 abort: cannot follow file not in parent revision: "dir"
1718 abort: cannot follow file not in parent revision: "dir"
1718 abort: cannot follow file not in parent revision: "dir"
1719 abort: cannot follow file not in parent revision: "dir"
1719
1720
1720 Test --follow on a directory
1721 Test --follow on a directory
1721
1722
1722 $ hg up -q '.^'
1723 $ hg up -q '.^'
1723 $ testlog -f dir
1724 $ testlog -f dir
1724 []
1725 []
1725 (and
1726 (and
1726 (func
1727 (func
1727 (symbol 'ancestors')
1728 (symbol 'ancestors')
1728 (symbol '.'))
1729 (symbol '.'))
1729 (func
1730 (func
1730 (symbol '_matchfiles')
1731 (symbol '_matchfiles')
1731 (list
1732 (list
1732 (string 'r:')
1733 (string 'r:')
1733 (string 'd:relpath')
1734 (string 'd:relpath')
1734 (string 'p:dir'))))
1735 (string 'p:dir'))))
1735 <filteredset
1736 <filteredset
1736 <filteredset
1737 <filteredset
1737 <spanset- 0:4>,
1738 <spanset- 0:4>,
1738 <generatorsetdesc+>>,
1739 <generatorsetdesc+>>,
1739 <matchfiles patterns=['dir'], include=[] exclude=[], default='relpath', rev=None>>
1740 <matchfiles patterns=['dir'], include=[] exclude=[], default='relpath', rev=None>>
1740 $ hg up -q tip
1741 $ hg up -q tip
1741
1742
1742 Test --follow on file not in parent revision
1743 Test --follow on file not in parent revision
1743
1744
1744 $ testlog -f a
1745 $ testlog -f a
1745 abort: cannot follow file not in parent revision: "a"
1746 abort: cannot follow file not in parent revision: "a"
1746 abort: cannot follow file not in parent revision: "a"
1747 abort: cannot follow file not in parent revision: "a"
1747 abort: cannot follow file not in parent revision: "a"
1748 abort: cannot follow file not in parent revision: "a"
1748
1749
1749 Test --follow and patterns
1750 Test --follow and patterns
1750
1751
1751 $ testlog -f 'glob:*'
1752 $ testlog -f 'glob:*'
1752 []
1753 []
1753 (and
1754 (and
1754 (func
1755 (func
1755 (symbol 'ancestors')
1756 (symbol 'ancestors')
1756 (symbol '.'))
1757 (symbol '.'))
1757 (func
1758 (func
1758 (symbol '_matchfiles')
1759 (symbol '_matchfiles')
1759 (list
1760 (list
1760 (string 'r:')
1761 (string 'r:')
1761 (string 'd:relpath')
1762 (string 'd:relpath')
1762 (string 'p:glob:*'))))
1763 (string 'p:glob:*'))))
1763 <filteredset
1764 <filteredset
1764 <filteredset
1765 <filteredset
1765 <spanset- 0:5>,
1766 <spanset- 0:5>,
1766 <generatorsetdesc+>>,
1767 <generatorsetdesc+>>,
1767 <matchfiles patterns=['glob:*'], include=[] exclude=[], default='relpath', rev=None>>
1768 <matchfiles patterns=['glob:*'], include=[] exclude=[], default='relpath', rev=None>>
1768
1769
1769 Test --follow on a single rename
1770 Test --follow on a single rename
1770
1771
1771 $ hg up -q 2
1772 $ hg up -q 2
1772 $ testlog -f a
1773 $ testlog -f a
1773 []
1774 []
1774 (func
1775 (func
1775 (symbol 'follow')
1776 (symbol 'follow')
1776 (string 'a'))
1777 (string 'a'))
1777 <filteredset
1778 <filteredset
1778 <spanset- 0:3>,
1779 <spanset- 0:3>,
1779 <generatorsetdesc+>>
1780 <generatorsetdesc+>>
1780
1781
1781 Test --follow and multiple renames
1782 Test --follow and multiple renames
1782
1783
1783 $ hg up -q tip
1784 $ hg up -q tip
1784 $ testlog -f e
1785 $ testlog -f e
1785 []
1786 []
1786 (func
1787 (func
1787 (symbol 'follow')
1788 (symbol 'follow')
1788 (string 'e'))
1789 (string 'e'))
1789 <filteredset
1790 <filteredset
1790 <spanset- 0:5>,
1791 <spanset- 0:5>,
1791 <generatorsetdesc+>>
1792 <generatorsetdesc+>>
1792
1793
1793 Test --follow and multiple filelog heads
1794 Test --follow and multiple filelog heads
1794
1795
1795 $ hg up -q 2
1796 $ hg up -q 2
1796 $ testlog -f g
1797 $ testlog -f g
1797 []
1798 []
1798 (func
1799 (func
1799 (symbol 'follow')
1800 (symbol 'follow')
1800 (string 'g'))
1801 (string 'g'))
1801 <filteredset
1802 <filteredset
1802 <spanset- 0:3>,
1803 <spanset- 0:3>,
1803 <generatorsetdesc+>>
1804 <generatorsetdesc+>>
1804 $ cat log.nodes
1805 $ cat log.nodes
1805 nodetag 2
1806 nodetag 2
1806 nodetag 1
1807 nodetag 1
1807 nodetag 0
1808 nodetag 0
1808 $ hg up -q tip
1809 $ hg up -q tip
1809 $ testlog -f g
1810 $ testlog -f g
1810 []
1811 []
1811 (func
1812 (func
1812 (symbol 'follow')
1813 (symbol 'follow')
1813 (string 'g'))
1814 (string 'g'))
1814 <filteredset
1815 <filteredset
1815 <spanset- 0:5>,
1816 <spanset- 0:5>,
1816 <generatorsetdesc+>>
1817 <generatorsetdesc+>>
1817 $ cat log.nodes
1818 $ cat log.nodes
1818 nodetag 3
1819 nodetag 3
1819 nodetag 2
1820 nodetag 2
1820 nodetag 0
1821 nodetag 0
1821
1822
1822 Test --follow and multiple files
1823 Test --follow and multiple files
1823
1824
1824 $ testlog -f g e
1825 $ testlog -f g e
1825 []
1826 []
1826 (or
1827 (or
1827 (list
1828 (list
1828 (func
1829 (func
1829 (symbol 'follow')
1830 (symbol 'follow')
1830 (string 'g'))
1831 (string 'g'))
1831 (func
1832 (func
1832 (symbol 'follow')
1833 (symbol 'follow')
1833 (string 'e'))))
1834 (string 'e'))))
1834 <filteredset
1835 <filteredset
1835 <spanset- 0:5>,
1836 <spanset- 0:5>,
1836 <addset
1837 <addset
1837 <generatorsetdesc+>,
1838 <generatorsetdesc+>,
1838 <generatorsetdesc+>>>
1839 <generatorsetdesc+>>>
1839 $ cat log.nodes
1840 $ cat log.nodes
1840 nodetag 4
1841 nodetag 4
1841 nodetag 3
1842 nodetag 3
1842 nodetag 2
1843 nodetag 2
1843 nodetag 1
1844 nodetag 1
1844 nodetag 0
1845 nodetag 0
1845
1846
1846 Test --follow null parent
1847 Test --follow null parent
1847
1848
1848 $ hg up -q null
1849 $ hg up -q null
1849 $ testlog -f
1850 $ testlog -f
1850 []
1851 []
1851 []
1852 []
1852 <baseset []>
1853 <baseset []>
1853
1854
1854 Test --follow-first
1855 Test --follow-first
1855
1856
1856 $ hg up -q 3
1857 $ hg up -q 3
1857 $ echo ee > e
1858 $ echo ee > e
1858 $ hg ci -Am "add another e" e
1859 $ hg ci -Am "add another e" e
1859 created new head
1860 created new head
1860 $ hg merge --tool internal:other 4
1861 $ hg merge --tool internal:other 4
1861 0 files updated, 1 files merged, 1 files removed, 0 files unresolved
1862 0 files updated, 1 files merged, 1 files removed, 0 files unresolved
1862 (branch merge, don't forget to commit)
1863 (branch merge, don't forget to commit)
1863 $ echo merge > e
1864 $ echo merge > e
1864 $ hg ci -m "merge 5 and 4"
1865 $ hg ci -m "merge 5 and 4"
1865 $ testlog --follow-first
1866 $ testlog --follow-first
1866 []
1867 []
1867 (func
1868 (func
1868 (symbol '_firstancestors')
1869 (symbol '_firstancestors')
1869 (func
1870 (func
1870 (symbol 'rev')
1871 (symbol 'rev')
1871 (symbol '6')))
1872 (symbol '6')))
1872 <filteredset
1873 <filteredset
1873 <spanset- 0:7>,
1874 <spanset- 0:7>,
1874 <generatorsetdesc+>>
1875 <generatorsetdesc+>>
1875
1876
1876 Cannot compare with log --follow-first FILE as it never worked
1877 Cannot compare with log --follow-first FILE as it never worked
1877
1878
1878 $ hg log -G --print-revset --follow-first e
1879 $ hg log -G --print-revset --follow-first e
1879 []
1880 []
1880 (func
1881 (func
1881 (symbol '_followfirst')
1882 (symbol '_followfirst')
1882 (string 'e'))
1883 (string 'e'))
1883 <filteredset
1884 <filteredset
1884 <spanset- 0:7>,
1885 <spanset- 0:7>,
1885 <generatorsetdesc+>>
1886 <generatorsetdesc+>>
1886 $ hg log -G --follow-first e --template '{rev} {desc|firstline}\n'
1887 $ hg log -G --follow-first e --template '{rev} {desc|firstline}\n'
1887 @ 6 merge 5 and 4
1888 @ 6 merge 5 and 4
1888 |\
1889 |\
1889 | ~
1890 | ~
1890 o 5 add another e
1891 o 5 add another e
1891 |
1892 |
1892 ~
1893 ~
1893
1894
1894 Test --copies
1895 Test --copies
1895
1896
1896 $ hg log -G --copies --template "{rev} {desc|firstline} \
1897 $ hg log -G --copies --template "{rev} {desc|firstline} \
1897 > copies: {file_copies_switch}\n"
1898 > copies: {file_copies_switch}\n"
1898 @ 6 merge 5 and 4 copies:
1899 @ 6 merge 5 and 4 copies:
1899 |\
1900 |\
1900 | o 5 add another e copies:
1901 | o 5 add another e copies:
1901 | |
1902 | |
1902 o | 4 mv dir/b e copies: e (dir/b)
1903 o | 4 mv dir/b e copies: e (dir/b)
1903 |/
1904 |/
1904 o 3 mv a b; add d copies: b (a)g (f)
1905 o 3 mv a b; add d copies: b (a)g (f)
1905 |
1906 |
1906 o 2 mv b dir/b copies: dir/b (b)
1907 o 2 mv b dir/b copies: dir/b (b)
1907 |
1908 |
1908 o 1 copy a b copies: b (a)g (f)
1909 o 1 copy a b copies: b (a)g (f)
1909 |
1910 |
1910 o 0 add a copies:
1911 o 0 add a copies:
1911
1912
1912 Test "set:..." and parent revision
1913 Test "set:..." and parent revision
1913
1914
1914 $ hg up -q 4
1915 $ hg up -q 4
1915 $ testlog "set:copied()"
1916 $ testlog "set:copied()"
1916 []
1917 []
1917 (func
1918 (func
1918 (symbol '_matchfiles')
1919 (symbol '_matchfiles')
1919 (list
1920 (list
1920 (string 'r:')
1921 (string 'r:')
1921 (string 'd:relpath')
1922 (string 'd:relpath')
1922 (string 'p:set:copied()')))
1923 (string 'p:set:copied()')))
1923 <filteredset
1924 <filteredset
1924 <spanset- 0:7>,
1925 <spanset- 0:7>,
1925 <matchfiles patterns=['set:copied()'], include=[] exclude=[], default='relpath', rev=None>>
1926 <matchfiles patterns=['set:copied()'], include=[] exclude=[], default='relpath', rev=None>>
1926 $ testlog --include "set:copied()"
1927 $ testlog --include "set:copied()"
1927 []
1928 []
1928 (func
1929 (func
1929 (symbol '_matchfiles')
1930 (symbol '_matchfiles')
1930 (list
1931 (list
1931 (string 'r:')
1932 (string 'r:')
1932 (string 'd:relpath')
1933 (string 'd:relpath')
1933 (string 'i:set:copied()')))
1934 (string 'i:set:copied()')))
1934 <filteredset
1935 <filteredset
1935 <spanset- 0:7>,
1936 <spanset- 0:7>,
1936 <matchfiles patterns=[], include=['set:copied()'] exclude=[], default='relpath', rev=None>>
1937 <matchfiles patterns=[], include=['set:copied()'] exclude=[], default='relpath', rev=None>>
1937 $ testlog -r "sort(file('set:copied()'), -rev)"
1938 $ testlog -r "sort(file('set:copied()'), -rev)"
1938 ["sort(file('set:copied()'), -rev)"]
1939 ["sort(file('set:copied()'), -rev)"]
1939 []
1940 []
1940 <baseset []>
1941 <baseset []>
1941
1942
1942 Test --removed
1943 Test --removed
1943
1944
1944 $ testlog --removed
1945 $ testlog --removed
1945 []
1946 []
1946 []
1947 []
1947 <spanset- 0:7>
1948 <spanset- 0:7>
1948 $ testlog --removed a
1949 $ testlog --removed a
1949 []
1950 []
1950 (func
1951 (func
1951 (symbol '_matchfiles')
1952 (symbol '_matchfiles')
1952 (list
1953 (list
1953 (string 'r:')
1954 (string 'r:')
1954 (string 'd:relpath')
1955 (string 'd:relpath')
1955 (string 'p:a')))
1956 (string 'p:a')))
1956 <filteredset
1957 <filteredset
1957 <spanset- 0:7>,
1958 <spanset- 0:7>,
1958 <matchfiles patterns=['a'], include=[] exclude=[], default='relpath', rev=None>>
1959 <matchfiles patterns=['a'], include=[] exclude=[], default='relpath', rev=None>>
1959 $ testlog --removed --follow a
1960 $ testlog --removed --follow a
1960 []
1961 []
1961 (and
1962 (and
1962 (func
1963 (func
1963 (symbol 'ancestors')
1964 (symbol 'ancestors')
1964 (symbol '.'))
1965 (symbol '.'))
1965 (func
1966 (func
1966 (symbol '_matchfiles')
1967 (symbol '_matchfiles')
1967 (list
1968 (list
1968 (string 'r:')
1969 (string 'r:')
1969 (string 'd:relpath')
1970 (string 'd:relpath')
1970 (string 'p:a'))))
1971 (string 'p:a'))))
1971 <filteredset
1972 <filteredset
1972 <filteredset
1973 <filteredset
1973 <spanset- 0:5>,
1974 <spanset- 0:5>,
1974 <generatorsetdesc+>>,
1975 <generatorsetdesc+>>,
1975 <matchfiles patterns=['a'], include=[] exclude=[], default='relpath', rev=None>>
1976 <matchfiles patterns=['a'], include=[] exclude=[], default='relpath', rev=None>>
1976
1977
1977 Test --patch and --stat with --follow and --follow-first
1978 Test --patch and --stat with --follow and --follow-first
1978
1979
1979 $ hg up -q 3
1980 $ hg up -q 3
1980 $ hg log -G --git --patch b
1981 $ hg log -G --git --patch b
1981 o changeset: 1:216d4c92cf98
1982 o changeset: 1:216d4c92cf98
1982 | user: test
1983 | user: test
1983 ~ date: Thu Jan 01 00:00:00 1970 +0000
1984 ~ date: Thu Jan 01 00:00:00 1970 +0000
1984 summary: copy a b
1985 summary: copy a b
1985
1986
1986 diff --git a/a b/b
1987 diff --git a/a b/b
1987 copy from a
1988 copy from a
1988 copy to b
1989 copy to b
1989
1990
1990
1991
1991 $ hg log -G --git --stat b
1992 $ hg log -G --git --stat b
1992 o changeset: 1:216d4c92cf98
1993 o changeset: 1:216d4c92cf98
1993 | user: test
1994 | user: test
1994 ~ date: Thu Jan 01 00:00:00 1970 +0000
1995 ~ date: Thu Jan 01 00:00:00 1970 +0000
1995 summary: copy a b
1996 summary: copy a b
1996
1997
1997 b | 0
1998 b | 0
1998 1 files changed, 0 insertions(+), 0 deletions(-)
1999 1 files changed, 0 insertions(+), 0 deletions(-)
1999
2000
2000
2001
2001 $ hg log -G --git --patch --follow b
2002 $ hg log -G --git --patch --follow b
2002 o changeset: 1:216d4c92cf98
2003 o changeset: 1:216d4c92cf98
2003 | user: test
2004 | user: test
2004 | date: Thu Jan 01 00:00:00 1970 +0000
2005 | date: Thu Jan 01 00:00:00 1970 +0000
2005 | summary: copy a b
2006 | summary: copy a b
2006 |
2007 |
2007 | diff --git a/a b/b
2008 | diff --git a/a b/b
2008 | copy from a
2009 | copy from a
2009 | copy to b
2010 | copy to b
2010 |
2011 |
2011 o changeset: 0:f8035bb17114
2012 o changeset: 0:f8035bb17114
2012 user: test
2013 user: test
2013 date: Thu Jan 01 00:00:00 1970 +0000
2014 date: Thu Jan 01 00:00:00 1970 +0000
2014 summary: add a
2015 summary: add a
2015
2016
2016 diff --git a/a b/a
2017 diff --git a/a b/a
2017 new file mode 100644
2018 new file mode 100644
2018 --- /dev/null
2019 --- /dev/null
2019 +++ b/a
2020 +++ b/a
2020 @@ -0,0 +1,1 @@
2021 @@ -0,0 +1,1 @@
2021 +a
2022 +a
2022
2023
2023
2024
2024 $ hg log -G --git --stat --follow b
2025 $ hg log -G --git --stat --follow b
2025 o changeset: 1:216d4c92cf98
2026 o changeset: 1:216d4c92cf98
2026 | user: test
2027 | user: test
2027 | date: Thu Jan 01 00:00:00 1970 +0000
2028 | date: Thu Jan 01 00:00:00 1970 +0000
2028 | summary: copy a b
2029 | summary: copy a b
2029 |
2030 |
2030 | b | 0
2031 | b | 0
2031 | 1 files changed, 0 insertions(+), 0 deletions(-)
2032 | 1 files changed, 0 insertions(+), 0 deletions(-)
2032 |
2033 |
2033 o changeset: 0:f8035bb17114
2034 o changeset: 0:f8035bb17114
2034 user: test
2035 user: test
2035 date: Thu Jan 01 00:00:00 1970 +0000
2036 date: Thu Jan 01 00:00:00 1970 +0000
2036 summary: add a
2037 summary: add a
2037
2038
2038 a | 1 +
2039 a | 1 +
2039 1 files changed, 1 insertions(+), 0 deletions(-)
2040 1 files changed, 1 insertions(+), 0 deletions(-)
2040
2041
2041
2042
2042 $ hg up -q 6
2043 $ hg up -q 6
2043 $ hg log -G --git --patch --follow-first e
2044 $ hg log -G --git --patch --follow-first e
2044 @ changeset: 6:fc281d8ff18d
2045 @ changeset: 6:fc281d8ff18d
2045 |\ tag: tip
2046 |\ tag: tip
2046 | ~ parent: 5:99b31f1c2782
2047 | ~ parent: 5:99b31f1c2782
2047 | parent: 4:17d952250a9d
2048 | parent: 4:17d952250a9d
2048 | user: test
2049 | user: test
2049 | date: Thu Jan 01 00:00:00 1970 +0000
2050 | date: Thu Jan 01 00:00:00 1970 +0000
2050 | summary: merge 5 and 4
2051 | summary: merge 5 and 4
2051 |
2052 |
2052 | diff --git a/e b/e
2053 | diff --git a/e b/e
2053 | --- a/e
2054 | --- a/e
2054 | +++ b/e
2055 | +++ b/e
2055 | @@ -1,1 +1,1 @@
2056 | @@ -1,1 +1,1 @@
2056 | -ee
2057 | -ee
2057 | +merge
2058 | +merge
2058 |
2059 |
2059 o changeset: 5:99b31f1c2782
2060 o changeset: 5:99b31f1c2782
2060 | parent: 3:5918b8d165d1
2061 | parent: 3:5918b8d165d1
2061 ~ user: test
2062 ~ user: test
2062 date: Thu Jan 01 00:00:00 1970 +0000
2063 date: Thu Jan 01 00:00:00 1970 +0000
2063 summary: add another e
2064 summary: add another e
2064
2065
2065 diff --git a/e b/e
2066 diff --git a/e b/e
2066 new file mode 100644
2067 new file mode 100644
2067 --- /dev/null
2068 --- /dev/null
2068 +++ b/e
2069 +++ b/e
2069 @@ -0,0 +1,1 @@
2070 @@ -0,0 +1,1 @@
2070 +ee
2071 +ee
2071
2072
2072
2073
2073 Test old-style --rev
2074 Test old-style --rev
2074
2075
2075 $ hg tag 'foo-bar'
2076 $ hg tag 'foo-bar'
2076 $ testlog -r 'foo-bar'
2077 $ testlog -r 'foo-bar'
2077 ['foo-bar']
2078 ['foo-bar']
2078 []
2079 []
2079 <baseset [6]>
2080 <baseset [6]>
2080
2081
2081 Test --follow and forward --rev
2082 Test --follow and forward --rev
2082
2083
2083 $ hg up -q 6
2084 $ hg up -q 6
2084 $ echo g > g
2085 $ echo g > g
2085 $ hg ci -Am 'add g' g
2086 $ hg ci -Am 'add g' g
2086 created new head
2087 created new head
2087 $ hg up -q 2
2088 $ hg up -q 2
2088 $ hg log -G --template "{rev} {desc|firstline}\n"
2089 $ hg log -G --template "{rev} {desc|firstline}\n"
2089 o 8 add g
2090 o 8 add g
2090 |
2091 |
2091 | o 7 Added tag foo-bar for changeset fc281d8ff18d
2092 | o 7 Added tag foo-bar for changeset fc281d8ff18d
2092 |/
2093 |/
2093 o 6 merge 5 and 4
2094 o 6 merge 5 and 4
2094 |\
2095 |\
2095 | o 5 add another e
2096 | o 5 add another e
2096 | |
2097 | |
2097 o | 4 mv dir/b e
2098 o | 4 mv dir/b e
2098 |/
2099 |/
2099 o 3 mv a b; add d
2100 o 3 mv a b; add d
2100 |
2101 |
2101 @ 2 mv b dir/b
2102 @ 2 mv b dir/b
2102 |
2103 |
2103 o 1 copy a b
2104 o 1 copy a b
2104 |
2105 |
2105 o 0 add a
2106 o 0 add a
2106
2107
2107 $ hg archive -r 7 archive
2108 $ hg archive -r 7 archive
2108 $ grep changessincelatesttag archive/.hg_archival.txt
2109 $ grep changessincelatesttag archive/.hg_archival.txt
2109 changessincelatesttag: 1
2110 changessincelatesttag: 1
2110 $ rm -r archive
2111 $ rm -r archive
2111
2112
2112 changessincelatesttag with no prior tag
2113 changessincelatesttag with no prior tag
2113 $ hg archive -r 4 archive
2114 $ hg archive -r 4 archive
2114 $ grep changessincelatesttag archive/.hg_archival.txt
2115 $ grep changessincelatesttag archive/.hg_archival.txt
2115 changessincelatesttag: 5
2116 changessincelatesttag: 5
2116
2117
2117 $ hg export 'all()'
2118 $ hg export 'all()'
2118 # HG changeset patch
2119 # HG changeset patch
2119 # User test
2120 # User test
2120 # Date 0 0
2121 # Date 0 0
2121 # Thu Jan 01 00:00:00 1970 +0000
2122 # Thu Jan 01 00:00:00 1970 +0000
2122 # Node ID f8035bb17114da16215af3436ec5222428ace8ee
2123 # Node ID f8035bb17114da16215af3436ec5222428ace8ee
2123 # Parent 0000000000000000000000000000000000000000
2124 # Parent 0000000000000000000000000000000000000000
2124 add a
2125 add a
2125
2126
2126 diff -r 000000000000 -r f8035bb17114 a
2127 diff -r 000000000000 -r f8035bb17114 a
2127 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2128 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2128 +++ b/a Thu Jan 01 00:00:00 1970 +0000
2129 +++ b/a Thu Jan 01 00:00:00 1970 +0000
2129 @@ -0,0 +1,1 @@
2130 @@ -0,0 +1,1 @@
2130 +a
2131 +a
2131 diff -r 000000000000 -r f8035bb17114 aa
2132 diff -r 000000000000 -r f8035bb17114 aa
2132 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2133 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2133 +++ b/aa Thu Jan 01 00:00:00 1970 +0000
2134 +++ b/aa Thu Jan 01 00:00:00 1970 +0000
2134 @@ -0,0 +1,1 @@
2135 @@ -0,0 +1,1 @@
2135 +aa
2136 +aa
2136 diff -r 000000000000 -r f8035bb17114 f
2137 diff -r 000000000000 -r f8035bb17114 f
2137 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2138 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2138 +++ b/f Thu Jan 01 00:00:00 1970 +0000
2139 +++ b/f Thu Jan 01 00:00:00 1970 +0000
2139 @@ -0,0 +1,1 @@
2140 @@ -0,0 +1,1 @@
2140 +f
2141 +f
2141 # HG changeset patch
2142 # HG changeset patch
2142 # User test
2143 # User test
2143 # Date 0 0
2144 # Date 0 0
2144 # Thu Jan 01 00:00:00 1970 +0000
2145 # Thu Jan 01 00:00:00 1970 +0000
2145 # Node ID 216d4c92cf98ff2b4641d508b76b529f3d424c92
2146 # Node ID 216d4c92cf98ff2b4641d508b76b529f3d424c92
2146 # Parent f8035bb17114da16215af3436ec5222428ace8ee
2147 # Parent f8035bb17114da16215af3436ec5222428ace8ee
2147 copy a b
2148 copy a b
2148
2149
2149 diff -r f8035bb17114 -r 216d4c92cf98 b
2150 diff -r f8035bb17114 -r 216d4c92cf98 b
2150 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2151 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2151 +++ b/b Thu Jan 01 00:00:00 1970 +0000
2152 +++ b/b Thu Jan 01 00:00:00 1970 +0000
2152 @@ -0,0 +1,1 @@
2153 @@ -0,0 +1,1 @@
2153 +a
2154 +a
2154 diff -r f8035bb17114 -r 216d4c92cf98 g
2155 diff -r f8035bb17114 -r 216d4c92cf98 g
2155 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2156 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2156 +++ b/g Thu Jan 01 00:00:00 1970 +0000
2157 +++ b/g Thu Jan 01 00:00:00 1970 +0000
2157 @@ -0,0 +1,1 @@
2158 @@ -0,0 +1,1 @@
2158 +f
2159 +f
2159 # HG changeset patch
2160 # HG changeset patch
2160 # User test
2161 # User test
2161 # Date 0 0
2162 # Date 0 0
2162 # Thu Jan 01 00:00:00 1970 +0000
2163 # Thu Jan 01 00:00:00 1970 +0000
2163 # Node ID bb573313a9e8349099b6ea2b2fb1fc7f424446f3
2164 # Node ID bb573313a9e8349099b6ea2b2fb1fc7f424446f3
2164 # Parent 216d4c92cf98ff2b4641d508b76b529f3d424c92
2165 # Parent 216d4c92cf98ff2b4641d508b76b529f3d424c92
2165 mv b dir/b
2166 mv b dir/b
2166
2167
2167 diff -r 216d4c92cf98 -r bb573313a9e8 b
2168 diff -r 216d4c92cf98 -r bb573313a9e8 b
2168 --- a/b Thu Jan 01 00:00:00 1970 +0000
2169 --- a/b Thu Jan 01 00:00:00 1970 +0000
2169 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2170 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2170 @@ -1,1 +0,0 @@
2171 @@ -1,1 +0,0 @@
2171 -a
2172 -a
2172 diff -r 216d4c92cf98 -r bb573313a9e8 dir/b
2173 diff -r 216d4c92cf98 -r bb573313a9e8 dir/b
2173 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2174 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2174 +++ b/dir/b Thu Jan 01 00:00:00 1970 +0000
2175 +++ b/dir/b Thu Jan 01 00:00:00 1970 +0000
2175 @@ -0,0 +1,1 @@
2176 @@ -0,0 +1,1 @@
2176 +a
2177 +a
2177 diff -r 216d4c92cf98 -r bb573313a9e8 f
2178 diff -r 216d4c92cf98 -r bb573313a9e8 f
2178 --- a/f Thu Jan 01 00:00:00 1970 +0000
2179 --- a/f Thu Jan 01 00:00:00 1970 +0000
2179 +++ b/f Thu Jan 01 00:00:00 1970 +0000
2180 +++ b/f Thu Jan 01 00:00:00 1970 +0000
2180 @@ -1,1 +1,2 @@
2181 @@ -1,1 +1,2 @@
2181 f
2182 f
2182 +f
2183 +f
2183 diff -r 216d4c92cf98 -r bb573313a9e8 g
2184 diff -r 216d4c92cf98 -r bb573313a9e8 g
2184 --- a/g Thu Jan 01 00:00:00 1970 +0000
2185 --- a/g Thu Jan 01 00:00:00 1970 +0000
2185 +++ b/g Thu Jan 01 00:00:00 1970 +0000
2186 +++ b/g Thu Jan 01 00:00:00 1970 +0000
2186 @@ -1,1 +1,2 @@
2187 @@ -1,1 +1,2 @@
2187 f
2188 f
2188 +g
2189 +g
2189 # HG changeset patch
2190 # HG changeset patch
2190 # User test
2191 # User test
2191 # Date 0 0
2192 # Date 0 0
2192 # Thu Jan 01 00:00:00 1970 +0000
2193 # Thu Jan 01 00:00:00 1970 +0000
2193 # Node ID 5918b8d165d1364e78a66d02e66caa0133c5d1ed
2194 # Node ID 5918b8d165d1364e78a66d02e66caa0133c5d1ed
2194 # Parent bb573313a9e8349099b6ea2b2fb1fc7f424446f3
2195 # Parent bb573313a9e8349099b6ea2b2fb1fc7f424446f3
2195 mv a b; add d
2196 mv a b; add d
2196
2197
2197 diff -r bb573313a9e8 -r 5918b8d165d1 a
2198 diff -r bb573313a9e8 -r 5918b8d165d1 a
2198 --- a/a Thu Jan 01 00:00:00 1970 +0000
2199 --- a/a Thu Jan 01 00:00:00 1970 +0000
2199 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2200 @@ -1,1 +0,0 @@
2201 @@ -1,1 +0,0 @@
2201 -a
2202 -a
2202 diff -r bb573313a9e8 -r 5918b8d165d1 b
2203 diff -r bb573313a9e8 -r 5918b8d165d1 b
2203 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2204 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2204 +++ b/b Thu Jan 01 00:00:00 1970 +0000
2205 +++ b/b Thu Jan 01 00:00:00 1970 +0000
2205 @@ -0,0 +1,1 @@
2206 @@ -0,0 +1,1 @@
2206 +a
2207 +a
2207 diff -r bb573313a9e8 -r 5918b8d165d1 d
2208 diff -r bb573313a9e8 -r 5918b8d165d1 d
2208 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2209 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2209 +++ b/d Thu Jan 01 00:00:00 1970 +0000
2210 +++ b/d Thu Jan 01 00:00:00 1970 +0000
2210 @@ -0,0 +1,1 @@
2211 @@ -0,0 +1,1 @@
2211 +a
2212 +a
2212 diff -r bb573313a9e8 -r 5918b8d165d1 g
2213 diff -r bb573313a9e8 -r 5918b8d165d1 g
2213 --- a/g Thu Jan 01 00:00:00 1970 +0000
2214 --- a/g Thu Jan 01 00:00:00 1970 +0000
2214 +++ b/g Thu Jan 01 00:00:00 1970 +0000
2215 +++ b/g Thu Jan 01 00:00:00 1970 +0000
2215 @@ -1,2 +1,2 @@
2216 @@ -1,2 +1,2 @@
2216 f
2217 f
2217 -g
2218 -g
2218 +f
2219 +f
2219 # HG changeset patch
2220 # HG changeset patch
2220 # User test
2221 # User test
2221 # Date 0 0
2222 # Date 0 0
2222 # Thu Jan 01 00:00:00 1970 +0000
2223 # Thu Jan 01 00:00:00 1970 +0000
2223 # Node ID 17d952250a9d03cc3dc77b199ab60e959b9b0260
2224 # Node ID 17d952250a9d03cc3dc77b199ab60e959b9b0260
2224 # Parent 5918b8d165d1364e78a66d02e66caa0133c5d1ed
2225 # Parent 5918b8d165d1364e78a66d02e66caa0133c5d1ed
2225 mv dir/b e
2226 mv dir/b e
2226
2227
2227 diff -r 5918b8d165d1 -r 17d952250a9d dir/b
2228 diff -r 5918b8d165d1 -r 17d952250a9d dir/b
2228 --- a/dir/b Thu Jan 01 00:00:00 1970 +0000
2229 --- a/dir/b Thu Jan 01 00:00:00 1970 +0000
2229 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2230 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2230 @@ -1,1 +0,0 @@
2231 @@ -1,1 +0,0 @@
2231 -a
2232 -a
2232 diff -r 5918b8d165d1 -r 17d952250a9d e
2233 diff -r 5918b8d165d1 -r 17d952250a9d e
2233 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2234 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2234 +++ b/e Thu Jan 01 00:00:00 1970 +0000
2235 +++ b/e Thu Jan 01 00:00:00 1970 +0000
2235 @@ -0,0 +1,1 @@
2236 @@ -0,0 +1,1 @@
2236 +a
2237 +a
2237 # HG changeset patch
2238 # HG changeset patch
2238 # User test
2239 # User test
2239 # Date 0 0
2240 # Date 0 0
2240 # Thu Jan 01 00:00:00 1970 +0000
2241 # Thu Jan 01 00:00:00 1970 +0000
2241 # Node ID 99b31f1c2782e2deb1723cef08930f70fc84b37b
2242 # Node ID 99b31f1c2782e2deb1723cef08930f70fc84b37b
2242 # Parent 5918b8d165d1364e78a66d02e66caa0133c5d1ed
2243 # Parent 5918b8d165d1364e78a66d02e66caa0133c5d1ed
2243 add another e
2244 add another e
2244
2245
2245 diff -r 5918b8d165d1 -r 99b31f1c2782 e
2246 diff -r 5918b8d165d1 -r 99b31f1c2782 e
2246 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2247 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2247 +++ b/e Thu Jan 01 00:00:00 1970 +0000
2248 +++ b/e Thu Jan 01 00:00:00 1970 +0000
2248 @@ -0,0 +1,1 @@
2249 @@ -0,0 +1,1 @@
2249 +ee
2250 +ee
2250 # HG changeset patch
2251 # HG changeset patch
2251 # User test
2252 # User test
2252 # Date 0 0
2253 # Date 0 0
2253 # Thu Jan 01 00:00:00 1970 +0000
2254 # Thu Jan 01 00:00:00 1970 +0000
2254 # Node ID fc281d8ff18d999ad6497b3d27390bcd695dcc73
2255 # Node ID fc281d8ff18d999ad6497b3d27390bcd695dcc73
2255 # Parent 99b31f1c2782e2deb1723cef08930f70fc84b37b
2256 # Parent 99b31f1c2782e2deb1723cef08930f70fc84b37b
2256 # Parent 17d952250a9d03cc3dc77b199ab60e959b9b0260
2257 # Parent 17d952250a9d03cc3dc77b199ab60e959b9b0260
2257 merge 5 and 4
2258 merge 5 and 4
2258
2259
2259 diff -r 99b31f1c2782 -r fc281d8ff18d dir/b
2260 diff -r 99b31f1c2782 -r fc281d8ff18d dir/b
2260 --- a/dir/b Thu Jan 01 00:00:00 1970 +0000
2261 --- a/dir/b Thu Jan 01 00:00:00 1970 +0000
2261 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2262 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2262 @@ -1,1 +0,0 @@
2263 @@ -1,1 +0,0 @@
2263 -a
2264 -a
2264 diff -r 99b31f1c2782 -r fc281d8ff18d e
2265 diff -r 99b31f1c2782 -r fc281d8ff18d e
2265 --- a/e Thu Jan 01 00:00:00 1970 +0000
2266 --- a/e Thu Jan 01 00:00:00 1970 +0000
2266 +++ b/e Thu Jan 01 00:00:00 1970 +0000
2267 +++ b/e Thu Jan 01 00:00:00 1970 +0000
2267 @@ -1,1 +1,1 @@
2268 @@ -1,1 +1,1 @@
2268 -ee
2269 -ee
2269 +merge
2270 +merge
2270 # HG changeset patch
2271 # HG changeset patch
2271 # User test
2272 # User test
2272 # Date 0 0
2273 # Date 0 0
2273 # Thu Jan 01 00:00:00 1970 +0000
2274 # Thu Jan 01 00:00:00 1970 +0000
2274 # Node ID 02dbb8e276b8ab7abfd07cab50c901647e75c2dd
2275 # Node ID 02dbb8e276b8ab7abfd07cab50c901647e75c2dd
2275 # Parent fc281d8ff18d999ad6497b3d27390bcd695dcc73
2276 # Parent fc281d8ff18d999ad6497b3d27390bcd695dcc73
2276 Added tag foo-bar for changeset fc281d8ff18d
2277 Added tag foo-bar for changeset fc281d8ff18d
2277
2278
2278 diff -r fc281d8ff18d -r 02dbb8e276b8 .hgtags
2279 diff -r fc281d8ff18d -r 02dbb8e276b8 .hgtags
2279 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2280 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2280 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
2281 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
2281 @@ -0,0 +1,1 @@
2282 @@ -0,0 +1,1 @@
2282 +fc281d8ff18d999ad6497b3d27390bcd695dcc73 foo-bar
2283 +fc281d8ff18d999ad6497b3d27390bcd695dcc73 foo-bar
2283 # HG changeset patch
2284 # HG changeset patch
2284 # User test
2285 # User test
2285 # Date 0 0
2286 # Date 0 0
2286 # Thu Jan 01 00:00:00 1970 +0000
2287 # Thu Jan 01 00:00:00 1970 +0000
2287 # Node ID 24c2e826ddebf80f9dcd60b856bdb8e6715c5449
2288 # Node ID 24c2e826ddebf80f9dcd60b856bdb8e6715c5449
2288 # Parent fc281d8ff18d999ad6497b3d27390bcd695dcc73
2289 # Parent fc281d8ff18d999ad6497b3d27390bcd695dcc73
2289 add g
2290 add g
2290
2291
2291 diff -r fc281d8ff18d -r 24c2e826ddeb g
2292 diff -r fc281d8ff18d -r 24c2e826ddeb g
2292 --- a/g Thu Jan 01 00:00:00 1970 +0000
2293 --- a/g Thu Jan 01 00:00:00 1970 +0000
2293 +++ b/g Thu Jan 01 00:00:00 1970 +0000
2294 +++ b/g Thu Jan 01 00:00:00 1970 +0000
2294 @@ -1,2 +1,1 @@
2295 @@ -1,2 +1,1 @@
2295 -f
2296 -f
2296 -f
2297 -f
2297 +g
2298 +g
2298 $ testlog --follow -r6 -r8 -r5 -r7 -r4
2299 $ testlog --follow -r6 -r8 -r5 -r7 -r4
2299 ['reverse(::(((6) or (8)) or ((5) or ((7) or (4)))))']
2300 ['reverse(::(((6) or (8)) or ((5) or ((7) or (4)))))']
2300 []
2301 []
2301 <generatorsetdesc->
2302 <generatorsetdesc->
2302
2303
2303 Test --follow-first and forward --rev
2304 Test --follow-first and forward --rev
2304
2305
2305 $ testlog --follow-first -r6 -r8 -r5 -r7 -r4
2306 $ testlog --follow-first -r6 -r8 -r5 -r7 -r4
2306 ['6', '8', '5', '7', '4']
2307 ['6', '8', '5', '7', '4']
2307 (func
2308 (func
2308 (symbol '_firstdescendants')
2309 (symbol '_firstdescendants')
2309 (func
2310 (func
2310 (symbol 'rev')
2311 (symbol 'rev')
2311 (symbol '6')))
2312 (symbol '6')))
2312 <filteredset
2313 <filteredset
2313 <baseset- [4, 5, 6, 7, 8]>,
2314 <baseset- [4, 5, 6, 7, 8]>,
2314 <generatorsetasc+>>
2315 <generatorsetasc+>>
2315 --- log.nodes * (glob)
2316 --- log.nodes * (glob)
2316 +++ glog.nodes * (glob)
2317 +++ glog.nodes * (glob)
2317 @@ -1,3 +1,3 @@
2318 @@ -1,3 +1,3 @@
2318 -nodetag 6
2319 -nodetag 6
2319 nodetag 8
2320 nodetag 8
2320 nodetag 7
2321 nodetag 7
2321 +nodetag 6
2322 +nodetag 6
2322
2323
2323 Test --follow and backward --rev
2324 Test --follow and backward --rev
2324
2325
2325 $ testlog --follow -r6 -r5 -r7 -r8 -r4
2326 $ testlog --follow -r6 -r5 -r7 -r8 -r4
2326 ['reverse(::(((6) or (5)) or ((7) or ((8) or (4)))))']
2327 ['reverse(::(((6) or (5)) or ((7) or ((8) or (4)))))']
2327 []
2328 []
2328 <generatorsetdesc->
2329 <generatorsetdesc->
2329
2330
2330 Test --follow-first and backward --rev
2331 Test --follow-first and backward --rev
2331
2332
2332 $ testlog --follow-first -r6 -r5 -r7 -r8 -r4
2333 $ testlog --follow-first -r6 -r5 -r7 -r8 -r4
2333 ['6', '5', '7', '8', '4']
2334 ['6', '5', '7', '8', '4']
2334 (func
2335 (func
2335 (symbol '_firstancestors')
2336 (symbol '_firstancestors')
2336 (func
2337 (func
2337 (symbol 'rev')
2338 (symbol 'rev')
2338 (symbol '6')))
2339 (symbol '6')))
2339 <filteredset
2340 <filteredset
2340 <baseset- [4, 5, 6, 7, 8]>,
2341 <baseset- [4, 5, 6, 7, 8]>,
2341 <generatorsetdesc+>>
2342 <generatorsetdesc+>>
2342
2343
2343 Test --follow with --rev of graphlog extension
2344 Test --follow with --rev of graphlog extension
2344
2345
2345 $ hg --config extensions.graphlog= glog -qfr1
2346 $ hg --config extensions.graphlog= glog -qfr1
2346 o 1:216d4c92cf98
2347 o 1:216d4c92cf98
2347 |
2348 |
2348 o 0:f8035bb17114
2349 o 0:f8035bb17114
2349
2350
2350
2351
2351 Test subdir
2352 Test subdir
2352
2353
2353 $ hg up -q 3
2354 $ hg up -q 3
2354 $ cd dir
2355 $ cd dir
2355 $ testlog .
2356 $ testlog .
2356 []
2357 []
2357 (func
2358 (func
2358 (symbol '_matchfiles')
2359 (symbol '_matchfiles')
2359 (list
2360 (list
2360 (string 'r:')
2361 (string 'r:')
2361 (string 'd:relpath')
2362 (string 'd:relpath')
2362 (string 'p:.')))
2363 (string 'p:.')))
2363 <filteredset
2364 <filteredset
2364 <spanset- 0:9>,
2365 <spanset- 0:9>,
2365 <matchfiles patterns=['.'], include=[] exclude=[], default='relpath', rev=None>>
2366 <matchfiles patterns=['.'], include=[] exclude=[], default='relpath', rev=None>>
2366 $ testlog ../b
2367 $ testlog ../b
2367 []
2368 []
2368 (func
2369 (func
2369 (symbol 'filelog')
2370 (symbol 'filelog')
2370 (string '../b'))
2371 (string '../b'))
2371 <filteredset
2372 <filteredset
2372 <spanset- 0:9>, set([1])>
2373 <spanset- 0:9>, set([1])>
2373 $ testlog -f ../b
2374 $ testlog -f ../b
2374 []
2375 []
2375 (func
2376 (func
2376 (symbol 'follow')
2377 (symbol 'follow')
2377 (string 'b'))
2378 (string 'b'))
2378 <filteredset
2379 <filteredset
2379 <spanset- 0:4>,
2380 <spanset- 0:4>,
2380 <generatorsetdesc+>>
2381 <generatorsetdesc+>>
2381 $ cd ..
2382 $ cd ..
2382
2383
2383 Test --hidden
2384 Test --hidden
2384 (enable obsolete)
2385 (enable obsolete)
2385
2386
2386 $ cat >> $HGRCPATH << EOF
2387 $ cat >> $HGRCPATH << EOF
2387 > [experimental]
2388 > [experimental]
2388 > evolution.createmarkers=True
2389 > evolution.createmarkers=True
2389 > EOF
2390 > EOF
2390
2391
2391 $ hg debugobsolete `hg id --debug -i -r 8`
2392 $ hg debugobsolete `hg id --debug -i -r 8`
2392 obsoleted 1 changesets
2393 obsoleted 1 changesets
2393 $ testlog
2394 $ testlog
2394 []
2395 []
2395 []
2396 []
2396 <spanset- 0:9>
2397 <spanset- 0:9>
2397 $ testlog --hidden
2398 $ testlog --hidden
2398 []
2399 []
2399 []
2400 []
2400 <spanset- 0:9>
2401 <spanset- 0:9>
2401 $ hg log -G --template '{rev} {desc}\n'
2402 $ hg log -G --template '{rev} {desc}\n'
2402 o 7 Added tag foo-bar for changeset fc281d8ff18d
2403 o 7 Added tag foo-bar for changeset fc281d8ff18d
2403 |
2404 |
2404 o 6 merge 5 and 4
2405 o 6 merge 5 and 4
2405 |\
2406 |\
2406 | o 5 add another e
2407 | o 5 add another e
2407 | |
2408 | |
2408 o | 4 mv dir/b e
2409 o | 4 mv dir/b e
2409 |/
2410 |/
2410 @ 3 mv a b; add d
2411 @ 3 mv a b; add d
2411 |
2412 |
2412 o 2 mv b dir/b
2413 o 2 mv b dir/b
2413 |
2414 |
2414 o 1 copy a b
2415 o 1 copy a b
2415 |
2416 |
2416 o 0 add a
2417 o 0 add a
2417
2418
2418
2419
2419 A template without trailing newline should do something sane
2420 A template without trailing newline should do something sane
2420
2421
2421 $ hg log -G -r ::2 --template '{rev} {desc}'
2422 $ hg log -G -r ::2 --template '{rev} {desc}'
2422 o 2 mv b dir/b
2423 o 2 mv b dir/b
2423 |
2424 |
2424 o 1 copy a b
2425 o 1 copy a b
2425 |
2426 |
2426 o 0 add a
2427 o 0 add a
2427
2428
2428
2429
2429 Extra newlines must be preserved
2430 Extra newlines must be preserved
2430
2431
2431 $ hg log -G -r ::2 --template '\n{rev} {desc}\n\n'
2432 $ hg log -G -r ::2 --template '\n{rev} {desc}\n\n'
2432 o
2433 o
2433 | 2 mv b dir/b
2434 | 2 mv b dir/b
2434 |
2435 |
2435 o
2436 o
2436 | 1 copy a b
2437 | 1 copy a b
2437 |
2438 |
2438 o
2439 o
2439 0 add a
2440 0 add a
2440
2441
2441
2442
2442 The almost-empty template should do something sane too ...
2443 The almost-empty template should do something sane too ...
2443
2444
2444 $ hg log -G -r ::2 --template '\n'
2445 $ hg log -G -r ::2 --template '\n'
2445 o
2446 o
2446 |
2447 |
2447 o
2448 o
2448 |
2449 |
2449 o
2450 o
2450
2451
2451
2452
2452 issue3772
2453 issue3772
2453
2454
2454 $ hg log -G -r :null
2455 $ hg log -G -r :null
2455 o changeset: 0:f8035bb17114
2456 o changeset: 0:f8035bb17114
2456 | user: test
2457 | user: test
2457 | date: Thu Jan 01 00:00:00 1970 +0000
2458 | date: Thu Jan 01 00:00:00 1970 +0000
2458 | summary: add a
2459 | summary: add a
2459 |
2460 |
2460 o changeset: -1:000000000000
2461 o changeset: -1:000000000000
2461 user:
2462 user:
2462 date: Thu Jan 01 00:00:00 1970 +0000
2463 date: Thu Jan 01 00:00:00 1970 +0000
2463
2464
2464 $ hg log -G -r null:null
2465 $ hg log -G -r null:null
2465 o changeset: -1:000000000000
2466 o changeset: -1:000000000000
2466 user:
2467 user:
2467 date: Thu Jan 01 00:00:00 1970 +0000
2468 date: Thu Jan 01 00:00:00 1970 +0000
2468
2469
2469
2470
2470 should not draw line down to null due to the magic of fullreposet
2471 should not draw line down to null due to the magic of fullreposet
2471
2472
2472 $ hg log -G -r 'all()' | tail -6
2473 $ hg log -G -r 'all()' | tail -6
2473 |
2474 |
2474 o changeset: 0:f8035bb17114
2475 o changeset: 0:f8035bb17114
2475 user: test
2476 user: test
2476 date: Thu Jan 01 00:00:00 1970 +0000
2477 date: Thu Jan 01 00:00:00 1970 +0000
2477 summary: add a
2478 summary: add a
2478
2479
2479
2480
2480 $ hg log -G -r 'branch(default)' | tail -6
2481 $ hg log -G -r 'branch(default)' | tail -6
2481 |
2482 |
2482 o changeset: 0:f8035bb17114
2483 o changeset: 0:f8035bb17114
2483 user: test
2484 user: test
2484 date: Thu Jan 01 00:00:00 1970 +0000
2485 date: Thu Jan 01 00:00:00 1970 +0000
2485 summary: add a
2486 summary: add a
2486
2487
2487
2488
2488 working-directory revision
2489 working-directory revision
2489
2490
2490 $ hg log -G -qr '. + wdir()'
2491 $ hg log -G -qr '. + wdir()'
2491 o 2147483647:ffffffffffff
2492 o 2147483647:ffffffffffff
2492 |
2493 |
2493 @ 3:5918b8d165d1
2494 @ 3:5918b8d165d1
2494 |
2495 |
2495 ~
2496 ~
2496
2497
2497 node template with changeset_printer:
2498 node template with changeset_printer:
2498
2499
2499 $ hg log -Gqr 5:7 --config ui.graphnodetemplate='"{rev}"'
2500 $ hg log -Gqr 5:7 --config ui.graphnodetemplate='"{rev}"'
2500 7 7:02dbb8e276b8
2501 7 7:02dbb8e276b8
2501 |
2502 |
2502 6 6:fc281d8ff18d
2503 6 6:fc281d8ff18d
2503 |\
2504 |\
2504 | ~
2505 | ~
2505 5 5:99b31f1c2782
2506 5 5:99b31f1c2782
2506 |
2507 |
2507 ~
2508 ~
2508
2509
2509 node template with changeset_templater (shared cache variable):
2510 node template with changeset_templater (shared cache variable):
2510
2511
2511 $ hg log -Gr 5:7 -T '{latesttag % "{rev} {tag}+{distance}"}\n' \
2512 $ hg log -Gr 5:7 -T '{latesttag % "{rev} {tag}+{distance}"}\n' \
2512 > --config ui.graphnodetemplate='{ifeq(latesttagdistance, 0, "#", graphnode)}'
2513 > --config ui.graphnodetemplate='{ifeq(latesttagdistance, 0, "#", graphnode)}'
2513 o 7 foo-bar+1
2514 o 7 foo-bar+1
2514 |
2515 |
2515 # 6 foo-bar+0
2516 # 6 foo-bar+0
2516 |\
2517 |\
2517 | ~
2518 | ~
2518 o 5 null+5
2519 o 5 null+5
2519 |
2520 |
2520 ~
2521 ~
2521
2522
2522 label() should just work in node template:
2523 label() should just work in node template:
2523
2524
2524 $ hg log -Gqr 7 --config extensions.color= --color=debug \
2525 $ hg log -Gqr 7 --config extensions.color= --color=debug \
2525 > --config ui.graphnodetemplate='{label("branch.{branch}", rev)}'
2526 > --config ui.graphnodetemplate='{label("branch.{branch}", rev)}'
2526 [branch.default|7] [log.node|7:02dbb8e276b8]
2527 [branch.default|7] [log.node|7:02dbb8e276b8]
2527 |
2528 |
2528 ~
2529 ~
2529
2530
2530 $ cd ..
2531 $ cd ..
2531
2532
2532 change graph edge styling
2533 change graph edge styling
2533
2534
2534 $ cd repo
2535 $ cd repo
2535 $ cat << EOF >> $HGRCPATH
2536 $ cat << EOF >> $HGRCPATH
2536 > [experimental]
2537 > [experimental]
2537 > graphstyle.parent = |
2538 > graphstyle.parent = |
2538 > graphstyle.grandparent = :
2539 > graphstyle.grandparent = :
2539 > graphstyle.missing =
2540 > graphstyle.missing =
2540 > EOF
2541 > EOF
2541 $ hg log -G -r 'file("a")' -m
2542 $ hg log -G -r 'file("a")' -m
2542 @ changeset: 36:08a19a744424
2543 @ changeset: 36:08a19a744424
2543 : branch: branch
2544 : branch: branch
2544 : tag: tip
2545 : tag: tip
2545 : parent: 35:9159c3644c5e
2546 : parent: 35:9159c3644c5e
2546 : parent: 35:9159c3644c5e
2547 : parent: 35:9159c3644c5e
2547 : user: test
2548 : user: test
2548 : date: Thu Jan 01 00:00:36 1970 +0000
2549 : date: Thu Jan 01 00:00:36 1970 +0000
2549 : summary: (36) buggy merge: identical parents
2550 : summary: (36) buggy merge: identical parents
2550 :
2551 :
2551 o changeset: 32:d06dffa21a31
2552 o changeset: 32:d06dffa21a31
2552 |\ parent: 27:886ed638191b
2553 |\ parent: 27:886ed638191b
2553 | : parent: 31:621d83e11f67
2554 | : parent: 31:621d83e11f67
2554 | : user: test
2555 | : user: test
2555 | : date: Thu Jan 01 00:00:32 1970 +0000
2556 | : date: Thu Jan 01 00:00:32 1970 +0000
2556 | : summary: (32) expand
2557 | : summary: (32) expand
2557 | :
2558 | :
2558 o : changeset: 31:621d83e11f67
2559 o : changeset: 31:621d83e11f67
2559 |\: parent: 21:d42a756af44d
2560 |\: parent: 21:d42a756af44d
2560 | : parent: 30:6e11cd4b648f
2561 | : parent: 30:6e11cd4b648f
2561 | : user: test
2562 | : user: test
2562 | : date: Thu Jan 01 00:00:31 1970 +0000
2563 | : date: Thu Jan 01 00:00:31 1970 +0000
2563 | : summary: (31) expand
2564 | : summary: (31) expand
2564 | :
2565 | :
2565 o : changeset: 30:6e11cd4b648f
2566 o : changeset: 30:6e11cd4b648f
2566 |\ \ parent: 28:44ecd0b9ae99
2567 |\ \ parent: 28:44ecd0b9ae99
2567 | ~ : parent: 29:cd9bb2be7593
2568 | ~ : parent: 29:cd9bb2be7593
2568 | : user: test
2569 | : user: test
2569 | : date: Thu Jan 01 00:00:30 1970 +0000
2570 | : date: Thu Jan 01 00:00:30 1970 +0000
2570 | : summary: (30) expand
2571 | : summary: (30) expand
2571 | /
2572 | /
2572 o : changeset: 28:44ecd0b9ae99
2573 o : changeset: 28:44ecd0b9ae99
2573 |\ \ parent: 1:6db2ef61d156
2574 |\ \ parent: 1:6db2ef61d156
2574 | ~ : parent: 26:7f25b6c2f0b9
2575 | ~ : parent: 26:7f25b6c2f0b9
2575 | : user: test
2576 | : user: test
2576 | : date: Thu Jan 01 00:00:28 1970 +0000
2577 | : date: Thu Jan 01 00:00:28 1970 +0000
2577 | : summary: (28) merge zero known
2578 | : summary: (28) merge zero known
2578 | /
2579 | /
2579 o : changeset: 26:7f25b6c2f0b9
2580 o : changeset: 26:7f25b6c2f0b9
2580 |\ \ parent: 18:1aa84d96232a
2581 |\ \ parent: 18:1aa84d96232a
2581 | | : parent: 25:91da8ed57247
2582 | | : parent: 25:91da8ed57247
2582 | | : user: test
2583 | | : user: test
2583 | | : date: Thu Jan 01 00:00:26 1970 +0000
2584 | | : date: Thu Jan 01 00:00:26 1970 +0000
2584 | | : summary: (26) merge one known; far right
2585 | | : summary: (26) merge one known; far right
2585 | | :
2586 | | :
2586 | o : changeset: 25:91da8ed57247
2587 | o : changeset: 25:91da8ed57247
2587 | |\: parent: 21:d42a756af44d
2588 | |\: parent: 21:d42a756af44d
2588 | | : parent: 24:a9c19a3d96b7
2589 | | : parent: 24:a9c19a3d96b7
2589 | | : user: test
2590 | | : user: test
2590 | | : date: Thu Jan 01 00:00:25 1970 +0000
2591 | | : date: Thu Jan 01 00:00:25 1970 +0000
2591 | | : summary: (25) merge one known; far left
2592 | | : summary: (25) merge one known; far left
2592 | | :
2593 | | :
2593 | o : changeset: 24:a9c19a3d96b7
2594 | o : changeset: 24:a9c19a3d96b7
2594 | |\ \ parent: 0:e6eb3150255d
2595 | |\ \ parent: 0:e6eb3150255d
2595 | | ~ : parent: 23:a01cddf0766d
2596 | | ~ : parent: 23:a01cddf0766d
2596 | | : user: test
2597 | | : user: test
2597 | | : date: Thu Jan 01 00:00:24 1970 +0000
2598 | | : date: Thu Jan 01 00:00:24 1970 +0000
2598 | | : summary: (24) merge one known; immediate right
2599 | | : summary: (24) merge one known; immediate right
2599 | | /
2600 | | /
2600 | o : changeset: 23:a01cddf0766d
2601 | o : changeset: 23:a01cddf0766d
2601 | |\ \ parent: 1:6db2ef61d156
2602 | |\ \ parent: 1:6db2ef61d156
2602 | | ~ : parent: 22:e0d9cccacb5d
2603 | | ~ : parent: 22:e0d9cccacb5d
2603 | | : user: test
2604 | | : user: test
2604 | | : date: Thu Jan 01 00:00:23 1970 +0000
2605 | | : date: Thu Jan 01 00:00:23 1970 +0000
2605 | | : summary: (23) merge one known; immediate left
2606 | | : summary: (23) merge one known; immediate left
2606 | | /
2607 | | /
2607 | o : changeset: 22:e0d9cccacb5d
2608 | o : changeset: 22:e0d9cccacb5d
2608 |/:/ parent: 18:1aa84d96232a
2609 |/:/ parent: 18:1aa84d96232a
2609 | : parent: 21:d42a756af44d
2610 | : parent: 21:d42a756af44d
2610 | : user: test
2611 | : user: test
2611 | : date: Thu Jan 01 00:00:22 1970 +0000
2612 | : date: Thu Jan 01 00:00:22 1970 +0000
2612 | : summary: (22) merge two known; one far left, one far right
2613 | : summary: (22) merge two known; one far left, one far right
2613 | :
2614 | :
2614 | o changeset: 21:d42a756af44d
2615 | o changeset: 21:d42a756af44d
2615 | |\ parent: 19:31ddc2c1573b
2616 | |\ parent: 19:31ddc2c1573b
2616 | | | parent: 20:d30ed6450e32
2617 | | | parent: 20:d30ed6450e32
2617 | | | user: test
2618 | | | user: test
2618 | | | date: Thu Jan 01 00:00:21 1970 +0000
2619 | | | date: Thu Jan 01 00:00:21 1970 +0000
2619 | | | summary: (21) expand
2620 | | | summary: (21) expand
2620 | | |
2621 | | |
2621 +---o changeset: 20:d30ed6450e32
2622 +---o changeset: 20:d30ed6450e32
2622 | | | parent: 0:e6eb3150255d
2623 | | | parent: 0:e6eb3150255d
2623 | | ~ parent: 18:1aa84d96232a
2624 | | ~ parent: 18:1aa84d96232a
2624 | | user: test
2625 | | user: test
2625 | | date: Thu Jan 01 00:00:20 1970 +0000
2626 | | date: Thu Jan 01 00:00:20 1970 +0000
2626 | | summary: (20) merge two known; two far right
2627 | | summary: (20) merge two known; two far right
2627 | |
2628 | |
2628 | o changeset: 19:31ddc2c1573b
2629 | o changeset: 19:31ddc2c1573b
2629 | |\ parent: 15:1dda3f72782d
2630 | |\ parent: 15:1dda3f72782d
2630 | | | parent: 17:44765d7c06e0
2631 | | | parent: 17:44765d7c06e0
2631 | | | user: test
2632 | | | user: test
2632 | | | date: Thu Jan 01 00:00:19 1970 +0000
2633 | | | date: Thu Jan 01 00:00:19 1970 +0000
2633 | | | summary: (19) expand
2634 | | | summary: (19) expand
2634 | | |
2635 | | |
2635 o | | changeset: 18:1aa84d96232a
2636 o | | changeset: 18:1aa84d96232a
2636 |\| | parent: 1:6db2ef61d156
2637 |\| | parent: 1:6db2ef61d156
2637 ~ | | parent: 15:1dda3f72782d
2638 ~ | | parent: 15:1dda3f72782d
2638 | | user: test
2639 | | user: test
2639 | | date: Thu Jan 01 00:00:18 1970 +0000
2640 | | date: Thu Jan 01 00:00:18 1970 +0000
2640 | | summary: (18) merge two known; two far left
2641 | | summary: (18) merge two known; two far left
2641 / /
2642 / /
2642 | o changeset: 17:44765d7c06e0
2643 | o changeset: 17:44765d7c06e0
2643 | |\ parent: 12:86b91144a6e9
2644 | |\ parent: 12:86b91144a6e9
2644 | | | parent: 16:3677d192927d
2645 | | | parent: 16:3677d192927d
2645 | | | user: test
2646 | | | user: test
2646 | | | date: Thu Jan 01 00:00:17 1970 +0000
2647 | | | date: Thu Jan 01 00:00:17 1970 +0000
2647 | | | summary: (17) expand
2648 | | | summary: (17) expand
2648 | | |
2649 | | |
2649 | | o changeset: 16:3677d192927d
2650 | | o changeset: 16:3677d192927d
2650 | | |\ parent: 0:e6eb3150255d
2651 | | |\ parent: 0:e6eb3150255d
2651 | | ~ ~ parent: 1:6db2ef61d156
2652 | | ~ ~ parent: 1:6db2ef61d156
2652 | | user: test
2653 | | user: test
2653 | | date: Thu Jan 01 00:00:16 1970 +0000
2654 | | date: Thu Jan 01 00:00:16 1970 +0000
2654 | | summary: (16) merge two known; one immediate right, one near right
2655 | | summary: (16) merge two known; one immediate right, one near right
2655 | |
2656 | |
2656 o | changeset: 15:1dda3f72782d
2657 o | changeset: 15:1dda3f72782d
2657 |\ \ parent: 13:22d8966a97e3
2658 |\ \ parent: 13:22d8966a97e3
2658 | | | parent: 14:8eac370358ef
2659 | | | parent: 14:8eac370358ef
2659 | | | user: test
2660 | | | user: test
2660 | | | date: Thu Jan 01 00:00:15 1970 +0000
2661 | | | date: Thu Jan 01 00:00:15 1970 +0000
2661 | | | summary: (15) expand
2662 | | | summary: (15) expand
2662 | | |
2663 | | |
2663 | o | changeset: 14:8eac370358ef
2664 | o | changeset: 14:8eac370358ef
2664 | |\| parent: 0:e6eb3150255d
2665 | |\| parent: 0:e6eb3150255d
2665 | ~ | parent: 12:86b91144a6e9
2666 | ~ | parent: 12:86b91144a6e9
2666 | | user: test
2667 | | user: test
2667 | | date: Thu Jan 01 00:00:14 1970 +0000
2668 | | date: Thu Jan 01 00:00:14 1970 +0000
2668 | | summary: (14) merge two known; one immediate right, one far right
2669 | | summary: (14) merge two known; one immediate right, one far right
2669 | /
2670 | /
2670 o | changeset: 13:22d8966a97e3
2671 o | changeset: 13:22d8966a97e3
2671 |\ \ parent: 9:7010c0af0a35
2672 |\ \ parent: 9:7010c0af0a35
2672 | | | parent: 11:832d76e6bdf2
2673 | | | parent: 11:832d76e6bdf2
2673 | | | user: test
2674 | | | user: test
2674 | | | date: Thu Jan 01 00:00:13 1970 +0000
2675 | | | date: Thu Jan 01 00:00:13 1970 +0000
2675 | | | summary: (13) expand
2676 | | | summary: (13) expand
2676 | | |
2677 | | |
2677 +---o changeset: 12:86b91144a6e9
2678 +---o changeset: 12:86b91144a6e9
2678 | | | parent: 1:6db2ef61d156
2679 | | | parent: 1:6db2ef61d156
2679 | | ~ parent: 9:7010c0af0a35
2680 | | ~ parent: 9:7010c0af0a35
2680 | | user: test
2681 | | user: test
2681 | | date: Thu Jan 01 00:00:12 1970 +0000
2682 | | date: Thu Jan 01 00:00:12 1970 +0000
2682 | | summary: (12) merge two known; one immediate right, one far left
2683 | | summary: (12) merge two known; one immediate right, one far left
2683 | |
2684 | |
2684 | o changeset: 11:832d76e6bdf2
2685 | o changeset: 11:832d76e6bdf2
2685 | |\ parent: 6:b105a072e251
2686 | |\ parent: 6:b105a072e251
2686 | | | parent: 10:74c64d036d72
2687 | | | parent: 10:74c64d036d72
2687 | | | user: test
2688 | | | user: test
2688 | | | date: Thu Jan 01 00:00:11 1970 +0000
2689 | | | date: Thu Jan 01 00:00:11 1970 +0000
2689 | | | summary: (11) expand
2690 | | | summary: (11) expand
2690 | | |
2691 | | |
2691 | | o changeset: 10:74c64d036d72
2692 | | o changeset: 10:74c64d036d72
2692 | |/| parent: 0:e6eb3150255d
2693 | |/| parent: 0:e6eb3150255d
2693 | | ~ parent: 6:b105a072e251
2694 | | ~ parent: 6:b105a072e251
2694 | | user: test
2695 | | user: test
2695 | | date: Thu Jan 01 00:00:10 1970 +0000
2696 | | date: Thu Jan 01 00:00:10 1970 +0000
2696 | | summary: (10) merge two known; one immediate left, one near right
2697 | | summary: (10) merge two known; one immediate left, one near right
2697 | |
2698 | |
2698 o | changeset: 9:7010c0af0a35
2699 o | changeset: 9:7010c0af0a35
2699 |\ \ parent: 7:b632bb1b1224
2700 |\ \ parent: 7:b632bb1b1224
2700 | | | parent: 8:7a0b11f71937
2701 | | | parent: 8:7a0b11f71937
2701 | | | user: test
2702 | | | user: test
2702 | | | date: Thu Jan 01 00:00:09 1970 +0000
2703 | | | date: Thu Jan 01 00:00:09 1970 +0000
2703 | | | summary: (9) expand
2704 | | | summary: (9) expand
2704 | | |
2705 | | |
2705 | o | changeset: 8:7a0b11f71937
2706 | o | changeset: 8:7a0b11f71937
2706 |/| | parent: 0:e6eb3150255d
2707 |/| | parent: 0:e6eb3150255d
2707 | ~ | parent: 7:b632bb1b1224
2708 | ~ | parent: 7:b632bb1b1224
2708 | | user: test
2709 | | user: test
2709 | | date: Thu Jan 01 00:00:08 1970 +0000
2710 | | date: Thu Jan 01 00:00:08 1970 +0000
2710 | | summary: (8) merge two known; one immediate left, one far right
2711 | | summary: (8) merge two known; one immediate left, one far right
2711 | /
2712 | /
2712 o | changeset: 7:b632bb1b1224
2713 o | changeset: 7:b632bb1b1224
2713 |\ \ parent: 2:3d9a33b8d1e1
2714 |\ \ parent: 2:3d9a33b8d1e1
2714 | ~ | parent: 5:4409d547b708
2715 | ~ | parent: 5:4409d547b708
2715 | | user: test
2716 | | user: test
2716 | | date: Thu Jan 01 00:00:07 1970 +0000
2717 | | date: Thu Jan 01 00:00:07 1970 +0000
2717 | | summary: (7) expand
2718 | | summary: (7) expand
2718 | /
2719 | /
2719 | o changeset: 6:b105a072e251
2720 | o changeset: 6:b105a072e251
2720 |/| parent: 2:3d9a33b8d1e1
2721 |/| parent: 2:3d9a33b8d1e1
2721 | ~ parent: 5:4409d547b708
2722 | ~ parent: 5:4409d547b708
2722 | user: test
2723 | user: test
2723 | date: Thu Jan 01 00:00:06 1970 +0000
2724 | date: Thu Jan 01 00:00:06 1970 +0000
2724 | summary: (6) merge two known; one immediate left, one far left
2725 | summary: (6) merge two known; one immediate left, one far left
2725 |
2726 |
2726 o changeset: 5:4409d547b708
2727 o changeset: 5:4409d547b708
2727 |\ parent: 3:27eef8ed80b4
2728 |\ parent: 3:27eef8ed80b4
2728 | ~ parent: 4:26a8bac39d9f
2729 | ~ parent: 4:26a8bac39d9f
2729 | user: test
2730 | user: test
2730 | date: Thu Jan 01 00:00:05 1970 +0000
2731 | date: Thu Jan 01 00:00:05 1970 +0000
2731 | summary: (5) expand
2732 | summary: (5) expand
2732 |
2733 |
2733 o changeset: 4:26a8bac39d9f
2734 o changeset: 4:26a8bac39d9f
2734 |\ parent: 1:6db2ef61d156
2735 |\ parent: 1:6db2ef61d156
2735 ~ ~ parent: 3:27eef8ed80b4
2736 ~ ~ parent: 3:27eef8ed80b4
2736 user: test
2737 user: test
2737 date: Thu Jan 01 00:00:04 1970 +0000
2738 date: Thu Jan 01 00:00:04 1970 +0000
2738 summary: (4) merge two known; one immediate left, one immediate right
2739 summary: (4) merge two known; one immediate left, one immediate right
2739
2740
2740
2741
2741 Setting HGPLAIN ignores graphmod styling:
2742 Setting HGPLAIN ignores graphmod styling:
2742
2743
2743 $ HGPLAIN=1 hg log -G -r 'file("a")' -m
2744 $ HGPLAIN=1 hg log -G -r 'file("a")' -m
2744 @ changeset: 36:08a19a744424
2745 @ changeset: 36:08a19a744424
2745 | branch: branch
2746 | branch: branch
2746 | tag: tip
2747 | tag: tip
2747 | parent: 35:9159c3644c5e
2748 | parent: 35:9159c3644c5e
2748 | parent: 35:9159c3644c5e
2749 | parent: 35:9159c3644c5e
2749 | user: test
2750 | user: test
2750 | date: Thu Jan 01 00:00:36 1970 +0000
2751 | date: Thu Jan 01 00:00:36 1970 +0000
2751 | summary: (36) buggy merge: identical parents
2752 | summary: (36) buggy merge: identical parents
2752 |
2753 |
2753 o changeset: 32:d06dffa21a31
2754 o changeset: 32:d06dffa21a31
2754 |\ parent: 27:886ed638191b
2755 |\ parent: 27:886ed638191b
2755 | | parent: 31:621d83e11f67
2756 | | parent: 31:621d83e11f67
2756 | | user: test
2757 | | user: test
2757 | | date: Thu Jan 01 00:00:32 1970 +0000
2758 | | date: Thu Jan 01 00:00:32 1970 +0000
2758 | | summary: (32) expand
2759 | | summary: (32) expand
2759 | |
2760 | |
2760 o | changeset: 31:621d83e11f67
2761 o | changeset: 31:621d83e11f67
2761 |\| parent: 21:d42a756af44d
2762 |\| parent: 21:d42a756af44d
2762 | | parent: 30:6e11cd4b648f
2763 | | parent: 30:6e11cd4b648f
2763 | | user: test
2764 | | user: test
2764 | | date: Thu Jan 01 00:00:31 1970 +0000
2765 | | date: Thu Jan 01 00:00:31 1970 +0000
2765 | | summary: (31) expand
2766 | | summary: (31) expand
2766 | |
2767 | |
2767 o | changeset: 30:6e11cd4b648f
2768 o | changeset: 30:6e11cd4b648f
2768 |\ \ parent: 28:44ecd0b9ae99
2769 |\ \ parent: 28:44ecd0b9ae99
2769 | | | parent: 29:cd9bb2be7593
2770 | | | parent: 29:cd9bb2be7593
2770 | | | user: test
2771 | | | user: test
2771 | | | date: Thu Jan 01 00:00:30 1970 +0000
2772 | | | date: Thu Jan 01 00:00:30 1970 +0000
2772 | | | summary: (30) expand
2773 | | | summary: (30) expand
2773 | | |
2774 | | |
2774 o | | changeset: 28:44ecd0b9ae99
2775 o | | changeset: 28:44ecd0b9ae99
2775 |\ \ \ parent: 1:6db2ef61d156
2776 |\ \ \ parent: 1:6db2ef61d156
2776 | | | | parent: 26:7f25b6c2f0b9
2777 | | | | parent: 26:7f25b6c2f0b9
2777 | | | | user: test
2778 | | | | user: test
2778 | | | | date: Thu Jan 01 00:00:28 1970 +0000
2779 | | | | date: Thu Jan 01 00:00:28 1970 +0000
2779 | | | | summary: (28) merge zero known
2780 | | | | summary: (28) merge zero known
2780 | | | |
2781 | | | |
2781 o | | | changeset: 26:7f25b6c2f0b9
2782 o | | | changeset: 26:7f25b6c2f0b9
2782 |\ \ \ \ parent: 18:1aa84d96232a
2783 |\ \ \ \ parent: 18:1aa84d96232a
2783 | | | | | parent: 25:91da8ed57247
2784 | | | | | parent: 25:91da8ed57247
2784 | | | | | user: test
2785 | | | | | user: test
2785 | | | | | date: Thu Jan 01 00:00:26 1970 +0000
2786 | | | | | date: Thu Jan 01 00:00:26 1970 +0000
2786 | | | | | summary: (26) merge one known; far right
2787 | | | | | summary: (26) merge one known; far right
2787 | | | | |
2788 | | | | |
2788 | o-----+ changeset: 25:91da8ed57247
2789 | o-----+ changeset: 25:91da8ed57247
2789 | | | | | parent: 21:d42a756af44d
2790 | | | | | parent: 21:d42a756af44d
2790 | | | | | parent: 24:a9c19a3d96b7
2791 | | | | | parent: 24:a9c19a3d96b7
2791 | | | | | user: test
2792 | | | | | user: test
2792 | | | | | date: Thu Jan 01 00:00:25 1970 +0000
2793 | | | | | date: Thu Jan 01 00:00:25 1970 +0000
2793 | | | | | summary: (25) merge one known; far left
2794 | | | | | summary: (25) merge one known; far left
2794 | | | | |
2795 | | | | |
2795 | o | | | changeset: 24:a9c19a3d96b7
2796 | o | | | changeset: 24:a9c19a3d96b7
2796 | |\ \ \ \ parent: 0:e6eb3150255d
2797 | |\ \ \ \ parent: 0:e6eb3150255d
2797 | | | | | | parent: 23:a01cddf0766d
2798 | | | | | | parent: 23:a01cddf0766d
2798 | | | | | | user: test
2799 | | | | | | user: test
2799 | | | | | | date: Thu Jan 01 00:00:24 1970 +0000
2800 | | | | | | date: Thu Jan 01 00:00:24 1970 +0000
2800 | | | | | | summary: (24) merge one known; immediate right
2801 | | | | | | summary: (24) merge one known; immediate right
2801 | | | | | |
2802 | | | | | |
2802 | o---+ | | changeset: 23:a01cddf0766d
2803 | o---+ | | changeset: 23:a01cddf0766d
2803 | | | | | | parent: 1:6db2ef61d156
2804 | | | | | | parent: 1:6db2ef61d156
2804 | | | | | | parent: 22:e0d9cccacb5d
2805 | | | | | | parent: 22:e0d9cccacb5d
2805 | | | | | | user: test
2806 | | | | | | user: test
2806 | | | | | | date: Thu Jan 01 00:00:23 1970 +0000
2807 | | | | | | date: Thu Jan 01 00:00:23 1970 +0000
2807 | | | | | | summary: (23) merge one known; immediate left
2808 | | | | | | summary: (23) merge one known; immediate left
2808 | | | | | |
2809 | | | | | |
2809 | o-------+ changeset: 22:e0d9cccacb5d
2810 | o-------+ changeset: 22:e0d9cccacb5d
2810 | | | | | | parent: 18:1aa84d96232a
2811 | | | | | | parent: 18:1aa84d96232a
2811 |/ / / / / parent: 21:d42a756af44d
2812 |/ / / / / parent: 21:d42a756af44d
2812 | | | | | user: test
2813 | | | | | user: test
2813 | | | | | date: Thu Jan 01 00:00:22 1970 +0000
2814 | | | | | date: Thu Jan 01 00:00:22 1970 +0000
2814 | | | | | summary: (22) merge two known; one far left, one far right
2815 | | | | | summary: (22) merge two known; one far left, one far right
2815 | | | | |
2816 | | | | |
2816 | | | | o changeset: 21:d42a756af44d
2817 | | | | o changeset: 21:d42a756af44d
2817 | | | | |\ parent: 19:31ddc2c1573b
2818 | | | | |\ parent: 19:31ddc2c1573b
2818 | | | | | | parent: 20:d30ed6450e32
2819 | | | | | | parent: 20:d30ed6450e32
2819 | | | | | | user: test
2820 | | | | | | user: test
2820 | | | | | | date: Thu Jan 01 00:00:21 1970 +0000
2821 | | | | | | date: Thu Jan 01 00:00:21 1970 +0000
2821 | | | | | | summary: (21) expand
2822 | | | | | | summary: (21) expand
2822 | | | | | |
2823 | | | | | |
2823 +-+-------o changeset: 20:d30ed6450e32
2824 +-+-------o changeset: 20:d30ed6450e32
2824 | | | | | parent: 0:e6eb3150255d
2825 | | | | | parent: 0:e6eb3150255d
2825 | | | | | parent: 18:1aa84d96232a
2826 | | | | | parent: 18:1aa84d96232a
2826 | | | | | user: test
2827 | | | | | user: test
2827 | | | | | date: Thu Jan 01 00:00:20 1970 +0000
2828 | | | | | date: Thu Jan 01 00:00:20 1970 +0000
2828 | | | | | summary: (20) merge two known; two far right
2829 | | | | | summary: (20) merge two known; two far right
2829 | | | | |
2830 | | | | |
2830 | | | | o changeset: 19:31ddc2c1573b
2831 | | | | o changeset: 19:31ddc2c1573b
2831 | | | | |\ parent: 15:1dda3f72782d
2832 | | | | |\ parent: 15:1dda3f72782d
2832 | | | | | | parent: 17:44765d7c06e0
2833 | | | | | | parent: 17:44765d7c06e0
2833 | | | | | | user: test
2834 | | | | | | user: test
2834 | | | | | | date: Thu Jan 01 00:00:19 1970 +0000
2835 | | | | | | date: Thu Jan 01 00:00:19 1970 +0000
2835 | | | | | | summary: (19) expand
2836 | | | | | | summary: (19) expand
2836 | | | | | |
2837 | | | | | |
2837 o---+---+ | changeset: 18:1aa84d96232a
2838 o---+---+ | changeset: 18:1aa84d96232a
2838 | | | | | parent: 1:6db2ef61d156
2839 | | | | | parent: 1:6db2ef61d156
2839 / / / / / parent: 15:1dda3f72782d
2840 / / / / / parent: 15:1dda3f72782d
2840 | | | | | user: test
2841 | | | | | user: test
2841 | | | | | date: Thu Jan 01 00:00:18 1970 +0000
2842 | | | | | date: Thu Jan 01 00:00:18 1970 +0000
2842 | | | | | summary: (18) merge two known; two far left
2843 | | | | | summary: (18) merge two known; two far left
2843 | | | | |
2844 | | | | |
2844 | | | | o changeset: 17:44765d7c06e0
2845 | | | | o changeset: 17:44765d7c06e0
2845 | | | | |\ parent: 12:86b91144a6e9
2846 | | | | |\ parent: 12:86b91144a6e9
2846 | | | | | | parent: 16:3677d192927d
2847 | | | | | | parent: 16:3677d192927d
2847 | | | | | | user: test
2848 | | | | | | user: test
2848 | | | | | | date: Thu Jan 01 00:00:17 1970 +0000
2849 | | | | | | date: Thu Jan 01 00:00:17 1970 +0000
2849 | | | | | | summary: (17) expand
2850 | | | | | | summary: (17) expand
2850 | | | | | |
2851 | | | | | |
2851 +-+-------o changeset: 16:3677d192927d
2852 +-+-------o changeset: 16:3677d192927d
2852 | | | | | parent: 0:e6eb3150255d
2853 | | | | | parent: 0:e6eb3150255d
2853 | | | | | parent: 1:6db2ef61d156
2854 | | | | | parent: 1:6db2ef61d156
2854 | | | | | user: test
2855 | | | | | user: test
2855 | | | | | date: Thu Jan 01 00:00:16 1970 +0000
2856 | | | | | date: Thu Jan 01 00:00:16 1970 +0000
2856 | | | | | summary: (16) merge two known; one immediate right, one near right
2857 | | | | | summary: (16) merge two known; one immediate right, one near right
2857 | | | | |
2858 | | | | |
2858 | | | o | changeset: 15:1dda3f72782d
2859 | | | o | changeset: 15:1dda3f72782d
2859 | | | |\ \ parent: 13:22d8966a97e3
2860 | | | |\ \ parent: 13:22d8966a97e3
2860 | | | | | | parent: 14:8eac370358ef
2861 | | | | | | parent: 14:8eac370358ef
2861 | | | | | | user: test
2862 | | | | | | user: test
2862 | | | | | | date: Thu Jan 01 00:00:15 1970 +0000
2863 | | | | | | date: Thu Jan 01 00:00:15 1970 +0000
2863 | | | | | | summary: (15) expand
2864 | | | | | | summary: (15) expand
2864 | | | | | |
2865 | | | | | |
2865 +-------o | changeset: 14:8eac370358ef
2866 +-------o | changeset: 14:8eac370358ef
2866 | | | | |/ parent: 0:e6eb3150255d
2867 | | | | |/ parent: 0:e6eb3150255d
2867 | | | | | parent: 12:86b91144a6e9
2868 | | | | | parent: 12:86b91144a6e9
2868 | | | | | user: test
2869 | | | | | user: test
2869 | | | | | date: Thu Jan 01 00:00:14 1970 +0000
2870 | | | | | date: Thu Jan 01 00:00:14 1970 +0000
2870 | | | | | summary: (14) merge two known; one immediate right, one far right
2871 | | | | | summary: (14) merge two known; one immediate right, one far right
2871 | | | | |
2872 | | | | |
2872 | | | o | changeset: 13:22d8966a97e3
2873 | | | o | changeset: 13:22d8966a97e3
2873 | | | |\ \ parent: 9:7010c0af0a35
2874 | | | |\ \ parent: 9:7010c0af0a35
2874 | | | | | | parent: 11:832d76e6bdf2
2875 | | | | | | parent: 11:832d76e6bdf2
2875 | | | | | | user: test
2876 | | | | | | user: test
2876 | | | | | | date: Thu Jan 01 00:00:13 1970 +0000
2877 | | | | | | date: Thu Jan 01 00:00:13 1970 +0000
2877 | | | | | | summary: (13) expand
2878 | | | | | | summary: (13) expand
2878 | | | | | |
2879 | | | | | |
2879 | +---+---o changeset: 12:86b91144a6e9
2880 | +---+---o changeset: 12:86b91144a6e9
2880 | | | | | parent: 1:6db2ef61d156
2881 | | | | | parent: 1:6db2ef61d156
2881 | | | | | parent: 9:7010c0af0a35
2882 | | | | | parent: 9:7010c0af0a35
2882 | | | | | user: test
2883 | | | | | user: test
2883 | | | | | date: Thu Jan 01 00:00:12 1970 +0000
2884 | | | | | date: Thu Jan 01 00:00:12 1970 +0000
2884 | | | | | summary: (12) merge two known; one immediate right, one far left
2885 | | | | | summary: (12) merge two known; one immediate right, one far left
2885 | | | | |
2886 | | | | |
2886 | | | | o changeset: 11:832d76e6bdf2
2887 | | | | o changeset: 11:832d76e6bdf2
2887 | | | | |\ parent: 6:b105a072e251
2888 | | | | |\ parent: 6:b105a072e251
2888 | | | | | | parent: 10:74c64d036d72
2889 | | | | | | parent: 10:74c64d036d72
2889 | | | | | | user: test
2890 | | | | | | user: test
2890 | | | | | | date: Thu Jan 01 00:00:11 1970 +0000
2891 | | | | | | date: Thu Jan 01 00:00:11 1970 +0000
2891 | | | | | | summary: (11) expand
2892 | | | | | | summary: (11) expand
2892 | | | | | |
2893 | | | | | |
2893 +---------o changeset: 10:74c64d036d72
2894 +---------o changeset: 10:74c64d036d72
2894 | | | | |/ parent: 0:e6eb3150255d
2895 | | | | |/ parent: 0:e6eb3150255d
2895 | | | | | parent: 6:b105a072e251
2896 | | | | | parent: 6:b105a072e251
2896 | | | | | user: test
2897 | | | | | user: test
2897 | | | | | date: Thu Jan 01 00:00:10 1970 +0000
2898 | | | | | date: Thu Jan 01 00:00:10 1970 +0000
2898 | | | | | summary: (10) merge two known; one immediate left, one near right
2899 | | | | | summary: (10) merge two known; one immediate left, one near right
2899 | | | | |
2900 | | | | |
2900 | | | o | changeset: 9:7010c0af0a35
2901 | | | o | changeset: 9:7010c0af0a35
2901 | | | |\ \ parent: 7:b632bb1b1224
2902 | | | |\ \ parent: 7:b632bb1b1224
2902 | | | | | | parent: 8:7a0b11f71937
2903 | | | | | | parent: 8:7a0b11f71937
2903 | | | | | | user: test
2904 | | | | | | user: test
2904 | | | | | | date: Thu Jan 01 00:00:09 1970 +0000
2905 | | | | | | date: Thu Jan 01 00:00:09 1970 +0000
2905 | | | | | | summary: (9) expand
2906 | | | | | | summary: (9) expand
2906 | | | | | |
2907 | | | | | |
2907 +-------o | changeset: 8:7a0b11f71937
2908 +-------o | changeset: 8:7a0b11f71937
2908 | | | |/ / parent: 0:e6eb3150255d
2909 | | | |/ / parent: 0:e6eb3150255d
2909 | | | | | parent: 7:b632bb1b1224
2910 | | | | | parent: 7:b632bb1b1224
2910 | | | | | user: test
2911 | | | | | user: test
2911 | | | | | date: Thu Jan 01 00:00:08 1970 +0000
2912 | | | | | date: Thu Jan 01 00:00:08 1970 +0000
2912 | | | | | summary: (8) merge two known; one immediate left, one far right
2913 | | | | | summary: (8) merge two known; one immediate left, one far right
2913 | | | | |
2914 | | | | |
2914 | | | o | changeset: 7:b632bb1b1224
2915 | | | o | changeset: 7:b632bb1b1224
2915 | | | |\ \ parent: 2:3d9a33b8d1e1
2916 | | | |\ \ parent: 2:3d9a33b8d1e1
2916 | | | | | | parent: 5:4409d547b708
2917 | | | | | | parent: 5:4409d547b708
2917 | | | | | | user: test
2918 | | | | | | user: test
2918 | | | | | | date: Thu Jan 01 00:00:07 1970 +0000
2919 | | | | | | date: Thu Jan 01 00:00:07 1970 +0000
2919 | | | | | | summary: (7) expand
2920 | | | | | | summary: (7) expand
2920 | | | | | |
2921 | | | | | |
2921 | | | +---o changeset: 6:b105a072e251
2922 | | | +---o changeset: 6:b105a072e251
2922 | | | | |/ parent: 2:3d9a33b8d1e1
2923 | | | | |/ parent: 2:3d9a33b8d1e1
2923 | | | | | parent: 5:4409d547b708
2924 | | | | | parent: 5:4409d547b708
2924 | | | | | user: test
2925 | | | | | user: test
2925 | | | | | date: Thu Jan 01 00:00:06 1970 +0000
2926 | | | | | date: Thu Jan 01 00:00:06 1970 +0000
2926 | | | | | summary: (6) merge two known; one immediate left, one far left
2927 | | | | | summary: (6) merge two known; one immediate left, one far left
2927 | | | | |
2928 | | | | |
2928 | | | o | changeset: 5:4409d547b708
2929 | | | o | changeset: 5:4409d547b708
2929 | | | |\ \ parent: 3:27eef8ed80b4
2930 | | | |\ \ parent: 3:27eef8ed80b4
2930 | | | | | | parent: 4:26a8bac39d9f
2931 | | | | | | parent: 4:26a8bac39d9f
2931 | | | | | | user: test
2932 | | | | | | user: test
2932 | | | | | | date: Thu Jan 01 00:00:05 1970 +0000
2933 | | | | | | date: Thu Jan 01 00:00:05 1970 +0000
2933 | | | | | | summary: (5) expand
2934 | | | | | | summary: (5) expand
2934 | | | | | |
2935 | | | | | |
2935 | +---o | | changeset: 4:26a8bac39d9f
2936 | +---o | | changeset: 4:26a8bac39d9f
2936 | | | |/ / parent: 1:6db2ef61d156
2937 | | | |/ / parent: 1:6db2ef61d156
2937 | | | | | parent: 3:27eef8ed80b4
2938 | | | | | parent: 3:27eef8ed80b4
2938 | | | | | user: test
2939 | | | | | user: test
2939 | | | | | date: Thu Jan 01 00:00:04 1970 +0000
2940 | | | | | date: Thu Jan 01 00:00:04 1970 +0000
2940 | | | | | summary: (4) merge two known; one immediate left, one immediate right
2941 | | | | | summary: (4) merge two known; one immediate left, one immediate right
2941 | | | | |
2942 | | | | |
2942
2943
2943 .. unless HGPLAINEXCEPT=graph is set:
2944 .. unless HGPLAINEXCEPT=graph is set:
2944
2945
2945 $ HGPLAIN=1 HGPLAINEXCEPT=graph hg log -G -r 'file("a")' -m
2946 $ HGPLAIN=1 HGPLAINEXCEPT=graph hg log -G -r 'file("a")' -m
2946 @ changeset: 36:08a19a744424
2947 @ changeset: 36:08a19a744424
2947 : branch: branch
2948 : branch: branch
2948 : tag: tip
2949 : tag: tip
2949 : parent: 35:9159c3644c5e
2950 : parent: 35:9159c3644c5e
2950 : parent: 35:9159c3644c5e
2951 : parent: 35:9159c3644c5e
2951 : user: test
2952 : user: test
2952 : date: Thu Jan 01 00:00:36 1970 +0000
2953 : date: Thu Jan 01 00:00:36 1970 +0000
2953 : summary: (36) buggy merge: identical parents
2954 : summary: (36) buggy merge: identical parents
2954 :
2955 :
2955 o changeset: 32:d06dffa21a31
2956 o changeset: 32:d06dffa21a31
2956 |\ parent: 27:886ed638191b
2957 |\ parent: 27:886ed638191b
2957 | : parent: 31:621d83e11f67
2958 | : parent: 31:621d83e11f67
2958 | : user: test
2959 | : user: test
2959 | : date: Thu Jan 01 00:00:32 1970 +0000
2960 | : date: Thu Jan 01 00:00:32 1970 +0000
2960 | : summary: (32) expand
2961 | : summary: (32) expand
2961 | :
2962 | :
2962 o : changeset: 31:621d83e11f67
2963 o : changeset: 31:621d83e11f67
2963 |\: parent: 21:d42a756af44d
2964 |\: parent: 21:d42a756af44d
2964 | : parent: 30:6e11cd4b648f
2965 | : parent: 30:6e11cd4b648f
2965 | : user: test
2966 | : user: test
2966 | : date: Thu Jan 01 00:00:31 1970 +0000
2967 | : date: Thu Jan 01 00:00:31 1970 +0000
2967 | : summary: (31) expand
2968 | : summary: (31) expand
2968 | :
2969 | :
2969 o : changeset: 30:6e11cd4b648f
2970 o : changeset: 30:6e11cd4b648f
2970 |\ \ parent: 28:44ecd0b9ae99
2971 |\ \ parent: 28:44ecd0b9ae99
2971 | ~ : parent: 29:cd9bb2be7593
2972 | ~ : parent: 29:cd9bb2be7593
2972 | : user: test
2973 | : user: test
2973 | : date: Thu Jan 01 00:00:30 1970 +0000
2974 | : date: Thu Jan 01 00:00:30 1970 +0000
2974 | : summary: (30) expand
2975 | : summary: (30) expand
2975 | /
2976 | /
2976 o : changeset: 28:44ecd0b9ae99
2977 o : changeset: 28:44ecd0b9ae99
2977 |\ \ parent: 1:6db2ef61d156
2978 |\ \ parent: 1:6db2ef61d156
2978 | ~ : parent: 26:7f25b6c2f0b9
2979 | ~ : parent: 26:7f25b6c2f0b9
2979 | : user: test
2980 | : user: test
2980 | : date: Thu Jan 01 00:00:28 1970 +0000
2981 | : date: Thu Jan 01 00:00:28 1970 +0000
2981 | : summary: (28) merge zero known
2982 | : summary: (28) merge zero known
2982 | /
2983 | /
2983 o : changeset: 26:7f25b6c2f0b9
2984 o : changeset: 26:7f25b6c2f0b9
2984 |\ \ parent: 18:1aa84d96232a
2985 |\ \ parent: 18:1aa84d96232a
2985 | | : parent: 25:91da8ed57247
2986 | | : parent: 25:91da8ed57247
2986 | | : user: test
2987 | | : user: test
2987 | | : date: Thu Jan 01 00:00:26 1970 +0000
2988 | | : date: Thu Jan 01 00:00:26 1970 +0000
2988 | | : summary: (26) merge one known; far right
2989 | | : summary: (26) merge one known; far right
2989 | | :
2990 | | :
2990 | o : changeset: 25:91da8ed57247
2991 | o : changeset: 25:91da8ed57247
2991 | |\: parent: 21:d42a756af44d
2992 | |\: parent: 21:d42a756af44d
2992 | | : parent: 24:a9c19a3d96b7
2993 | | : parent: 24:a9c19a3d96b7
2993 | | : user: test
2994 | | : user: test
2994 | | : date: Thu Jan 01 00:00:25 1970 +0000
2995 | | : date: Thu Jan 01 00:00:25 1970 +0000
2995 | | : summary: (25) merge one known; far left
2996 | | : summary: (25) merge one known; far left
2996 | | :
2997 | | :
2997 | o : changeset: 24:a9c19a3d96b7
2998 | o : changeset: 24:a9c19a3d96b7
2998 | |\ \ parent: 0:e6eb3150255d
2999 | |\ \ parent: 0:e6eb3150255d
2999 | | ~ : parent: 23:a01cddf0766d
3000 | | ~ : parent: 23:a01cddf0766d
3000 | | : user: test
3001 | | : user: test
3001 | | : date: Thu Jan 01 00:00:24 1970 +0000
3002 | | : date: Thu Jan 01 00:00:24 1970 +0000
3002 | | : summary: (24) merge one known; immediate right
3003 | | : summary: (24) merge one known; immediate right
3003 | | /
3004 | | /
3004 | o : changeset: 23:a01cddf0766d
3005 | o : changeset: 23:a01cddf0766d
3005 | |\ \ parent: 1:6db2ef61d156
3006 | |\ \ parent: 1:6db2ef61d156
3006 | | ~ : parent: 22:e0d9cccacb5d
3007 | | ~ : parent: 22:e0d9cccacb5d
3007 | | : user: test
3008 | | : user: test
3008 | | : date: Thu Jan 01 00:00:23 1970 +0000
3009 | | : date: Thu Jan 01 00:00:23 1970 +0000
3009 | | : summary: (23) merge one known; immediate left
3010 | | : summary: (23) merge one known; immediate left
3010 | | /
3011 | | /
3011 | o : changeset: 22:e0d9cccacb5d
3012 | o : changeset: 22:e0d9cccacb5d
3012 |/:/ parent: 18:1aa84d96232a
3013 |/:/ parent: 18:1aa84d96232a
3013 | : parent: 21:d42a756af44d
3014 | : parent: 21:d42a756af44d
3014 | : user: test
3015 | : user: test
3015 | : date: Thu Jan 01 00:00:22 1970 +0000
3016 | : date: Thu Jan 01 00:00:22 1970 +0000
3016 | : summary: (22) merge two known; one far left, one far right
3017 | : summary: (22) merge two known; one far left, one far right
3017 | :
3018 | :
3018 | o changeset: 21:d42a756af44d
3019 | o changeset: 21:d42a756af44d
3019 | |\ parent: 19:31ddc2c1573b
3020 | |\ parent: 19:31ddc2c1573b
3020 | | | parent: 20:d30ed6450e32
3021 | | | parent: 20:d30ed6450e32
3021 | | | user: test
3022 | | | user: test
3022 | | | date: Thu Jan 01 00:00:21 1970 +0000
3023 | | | date: Thu Jan 01 00:00:21 1970 +0000
3023 | | | summary: (21) expand
3024 | | | summary: (21) expand
3024 | | |
3025 | | |
3025 +---o changeset: 20:d30ed6450e32
3026 +---o changeset: 20:d30ed6450e32
3026 | | | parent: 0:e6eb3150255d
3027 | | | parent: 0:e6eb3150255d
3027 | | ~ parent: 18:1aa84d96232a
3028 | | ~ parent: 18:1aa84d96232a
3028 | | user: test
3029 | | user: test
3029 | | date: Thu Jan 01 00:00:20 1970 +0000
3030 | | date: Thu Jan 01 00:00:20 1970 +0000
3030 | | summary: (20) merge two known; two far right
3031 | | summary: (20) merge two known; two far right
3031 | |
3032 | |
3032 | o changeset: 19:31ddc2c1573b
3033 | o changeset: 19:31ddc2c1573b
3033 | |\ parent: 15:1dda3f72782d
3034 | |\ parent: 15:1dda3f72782d
3034 | | | parent: 17:44765d7c06e0
3035 | | | parent: 17:44765d7c06e0
3035 | | | user: test
3036 | | | user: test
3036 | | | date: Thu Jan 01 00:00:19 1970 +0000
3037 | | | date: Thu Jan 01 00:00:19 1970 +0000
3037 | | | summary: (19) expand
3038 | | | summary: (19) expand
3038 | | |
3039 | | |
3039 o | | changeset: 18:1aa84d96232a
3040 o | | changeset: 18:1aa84d96232a
3040 |\| | parent: 1:6db2ef61d156
3041 |\| | parent: 1:6db2ef61d156
3041 ~ | | parent: 15:1dda3f72782d
3042 ~ | | parent: 15:1dda3f72782d
3042 | | user: test
3043 | | user: test
3043 | | date: Thu Jan 01 00:00:18 1970 +0000
3044 | | date: Thu Jan 01 00:00:18 1970 +0000
3044 | | summary: (18) merge two known; two far left
3045 | | summary: (18) merge two known; two far left
3045 / /
3046 / /
3046 | o changeset: 17:44765d7c06e0
3047 | o changeset: 17:44765d7c06e0
3047 | |\ parent: 12:86b91144a6e9
3048 | |\ parent: 12:86b91144a6e9
3048 | | | parent: 16:3677d192927d
3049 | | | parent: 16:3677d192927d
3049 | | | user: test
3050 | | | user: test
3050 | | | date: Thu Jan 01 00:00:17 1970 +0000
3051 | | | date: Thu Jan 01 00:00:17 1970 +0000
3051 | | | summary: (17) expand
3052 | | | summary: (17) expand
3052 | | |
3053 | | |
3053 | | o changeset: 16:3677d192927d
3054 | | o changeset: 16:3677d192927d
3054 | | |\ parent: 0:e6eb3150255d
3055 | | |\ parent: 0:e6eb3150255d
3055 | | ~ ~ parent: 1:6db2ef61d156
3056 | | ~ ~ parent: 1:6db2ef61d156
3056 | | user: test
3057 | | user: test
3057 | | date: Thu Jan 01 00:00:16 1970 +0000
3058 | | date: Thu Jan 01 00:00:16 1970 +0000
3058 | | summary: (16) merge two known; one immediate right, one near right
3059 | | summary: (16) merge two known; one immediate right, one near right
3059 | |
3060 | |
3060 o | changeset: 15:1dda3f72782d
3061 o | changeset: 15:1dda3f72782d
3061 |\ \ parent: 13:22d8966a97e3
3062 |\ \ parent: 13:22d8966a97e3
3062 | | | parent: 14:8eac370358ef
3063 | | | parent: 14:8eac370358ef
3063 | | | user: test
3064 | | | user: test
3064 | | | date: Thu Jan 01 00:00:15 1970 +0000
3065 | | | date: Thu Jan 01 00:00:15 1970 +0000
3065 | | | summary: (15) expand
3066 | | | summary: (15) expand
3066 | | |
3067 | | |
3067 | o | changeset: 14:8eac370358ef
3068 | o | changeset: 14:8eac370358ef
3068 | |\| parent: 0:e6eb3150255d
3069 | |\| parent: 0:e6eb3150255d
3069 | ~ | parent: 12:86b91144a6e9
3070 | ~ | parent: 12:86b91144a6e9
3070 | | user: test
3071 | | user: test
3071 | | date: Thu Jan 01 00:00:14 1970 +0000
3072 | | date: Thu Jan 01 00:00:14 1970 +0000
3072 | | summary: (14) merge two known; one immediate right, one far right
3073 | | summary: (14) merge two known; one immediate right, one far right
3073 | /
3074 | /
3074 o | changeset: 13:22d8966a97e3
3075 o | changeset: 13:22d8966a97e3
3075 |\ \ parent: 9:7010c0af0a35
3076 |\ \ parent: 9:7010c0af0a35
3076 | | | parent: 11:832d76e6bdf2
3077 | | | parent: 11:832d76e6bdf2
3077 | | | user: test
3078 | | | user: test
3078 | | | date: Thu Jan 01 00:00:13 1970 +0000
3079 | | | date: Thu Jan 01 00:00:13 1970 +0000
3079 | | | summary: (13) expand
3080 | | | summary: (13) expand
3080 | | |
3081 | | |
3081 +---o changeset: 12:86b91144a6e9
3082 +---o changeset: 12:86b91144a6e9
3082 | | | parent: 1:6db2ef61d156
3083 | | | parent: 1:6db2ef61d156
3083 | | ~ parent: 9:7010c0af0a35
3084 | | ~ parent: 9:7010c0af0a35
3084 | | user: test
3085 | | user: test
3085 | | date: Thu Jan 01 00:00:12 1970 +0000
3086 | | date: Thu Jan 01 00:00:12 1970 +0000
3086 | | summary: (12) merge two known; one immediate right, one far left
3087 | | summary: (12) merge two known; one immediate right, one far left
3087 | |
3088 | |
3088 | o changeset: 11:832d76e6bdf2
3089 | o changeset: 11:832d76e6bdf2
3089 | |\ parent: 6:b105a072e251
3090 | |\ parent: 6:b105a072e251
3090 | | | parent: 10:74c64d036d72
3091 | | | parent: 10:74c64d036d72
3091 | | | user: test
3092 | | | user: test
3092 | | | date: Thu Jan 01 00:00:11 1970 +0000
3093 | | | date: Thu Jan 01 00:00:11 1970 +0000
3093 | | | summary: (11) expand
3094 | | | summary: (11) expand
3094 | | |
3095 | | |
3095 | | o changeset: 10:74c64d036d72
3096 | | o changeset: 10:74c64d036d72
3096 | |/| parent: 0:e6eb3150255d
3097 | |/| parent: 0:e6eb3150255d
3097 | | ~ parent: 6:b105a072e251
3098 | | ~ parent: 6:b105a072e251
3098 | | user: test
3099 | | user: test
3099 | | date: Thu Jan 01 00:00:10 1970 +0000
3100 | | date: Thu Jan 01 00:00:10 1970 +0000
3100 | | summary: (10) merge two known; one immediate left, one near right
3101 | | summary: (10) merge two known; one immediate left, one near right
3101 | |
3102 | |
3102 o | changeset: 9:7010c0af0a35
3103 o | changeset: 9:7010c0af0a35
3103 |\ \ parent: 7:b632bb1b1224
3104 |\ \ parent: 7:b632bb1b1224
3104 | | | parent: 8:7a0b11f71937
3105 | | | parent: 8:7a0b11f71937
3105 | | | user: test
3106 | | | user: test
3106 | | | date: Thu Jan 01 00:00:09 1970 +0000
3107 | | | date: Thu Jan 01 00:00:09 1970 +0000
3107 | | | summary: (9) expand
3108 | | | summary: (9) expand
3108 | | |
3109 | | |
3109 | o | changeset: 8:7a0b11f71937
3110 | o | changeset: 8:7a0b11f71937
3110 |/| | parent: 0:e6eb3150255d
3111 |/| | parent: 0:e6eb3150255d
3111 | ~ | parent: 7:b632bb1b1224
3112 | ~ | parent: 7:b632bb1b1224
3112 | | user: test
3113 | | user: test
3113 | | date: Thu Jan 01 00:00:08 1970 +0000
3114 | | date: Thu Jan 01 00:00:08 1970 +0000
3114 | | summary: (8) merge two known; one immediate left, one far right
3115 | | summary: (8) merge two known; one immediate left, one far right
3115 | /
3116 | /
3116 o | changeset: 7:b632bb1b1224
3117 o | changeset: 7:b632bb1b1224
3117 |\ \ parent: 2:3d9a33b8d1e1
3118 |\ \ parent: 2:3d9a33b8d1e1
3118 | ~ | parent: 5:4409d547b708
3119 | ~ | parent: 5:4409d547b708
3119 | | user: test
3120 | | user: test
3120 | | date: Thu Jan 01 00:00:07 1970 +0000
3121 | | date: Thu Jan 01 00:00:07 1970 +0000
3121 | | summary: (7) expand
3122 | | summary: (7) expand
3122 | /
3123 | /
3123 | o changeset: 6:b105a072e251
3124 | o changeset: 6:b105a072e251
3124 |/| parent: 2:3d9a33b8d1e1
3125 |/| parent: 2:3d9a33b8d1e1
3125 | ~ parent: 5:4409d547b708
3126 | ~ parent: 5:4409d547b708
3126 | user: test
3127 | user: test
3127 | date: Thu Jan 01 00:00:06 1970 +0000
3128 | date: Thu Jan 01 00:00:06 1970 +0000
3128 | summary: (6) merge two known; one immediate left, one far left
3129 | summary: (6) merge two known; one immediate left, one far left
3129 |
3130 |
3130 o changeset: 5:4409d547b708
3131 o changeset: 5:4409d547b708
3131 |\ parent: 3:27eef8ed80b4
3132 |\ parent: 3:27eef8ed80b4
3132 | ~ parent: 4:26a8bac39d9f
3133 | ~ parent: 4:26a8bac39d9f
3133 | user: test
3134 | user: test
3134 | date: Thu Jan 01 00:00:05 1970 +0000
3135 | date: Thu Jan 01 00:00:05 1970 +0000
3135 | summary: (5) expand
3136 | summary: (5) expand
3136 |
3137 |
3137 o changeset: 4:26a8bac39d9f
3138 o changeset: 4:26a8bac39d9f
3138 |\ parent: 1:6db2ef61d156
3139 |\ parent: 1:6db2ef61d156
3139 ~ ~ parent: 3:27eef8ed80b4
3140 ~ ~ parent: 3:27eef8ed80b4
3140 user: test
3141 user: test
3141 date: Thu Jan 01 00:00:04 1970 +0000
3142 date: Thu Jan 01 00:00:04 1970 +0000
3142 summary: (4) merge two known; one immediate left, one immediate right
3143 summary: (4) merge two known; one immediate left, one immediate right
3143
3144
3144 Draw only part of a grandparent line differently with "<N><char>"; only the
3145 Draw only part of a grandparent line differently with "<N><char>"; only the
3145 last N lines (for positive N) or everything but the first N lines (for
3146 last N lines (for positive N) or everything but the first N lines (for
3146 negative N) along the current node use the style, the rest of the edge uses
3147 negative N) along the current node use the style, the rest of the edge uses
3147 the parent edge styling.
3148 the parent edge styling.
3148
3149
3149 Last 3 lines:
3150 Last 3 lines:
3150
3151
3151 $ cat << EOF >> $HGRCPATH
3152 $ cat << EOF >> $HGRCPATH
3152 > [experimental]
3153 > [experimental]
3153 > graphstyle.parent = !
3154 > graphstyle.parent = !
3154 > graphstyle.grandparent = 3.
3155 > graphstyle.grandparent = 3.
3155 > graphstyle.missing =
3156 > graphstyle.missing =
3156 > EOF
3157 > EOF
3157 $ hg log -G -r '36:18 & file("a")' -m
3158 $ hg log -G -r '36:18 & file("a")' -m
3158 @ changeset: 36:08a19a744424
3159 @ changeset: 36:08a19a744424
3159 ! branch: branch
3160 ! branch: branch
3160 ! tag: tip
3161 ! tag: tip
3161 ! parent: 35:9159c3644c5e
3162 ! parent: 35:9159c3644c5e
3162 ! parent: 35:9159c3644c5e
3163 ! parent: 35:9159c3644c5e
3163 ! user: test
3164 ! user: test
3164 . date: Thu Jan 01 00:00:36 1970 +0000
3165 . date: Thu Jan 01 00:00:36 1970 +0000
3165 . summary: (36) buggy merge: identical parents
3166 . summary: (36) buggy merge: identical parents
3166 .
3167 .
3167 o changeset: 32:d06dffa21a31
3168 o changeset: 32:d06dffa21a31
3168 !\ parent: 27:886ed638191b
3169 !\ parent: 27:886ed638191b
3169 ! ! parent: 31:621d83e11f67
3170 ! ! parent: 31:621d83e11f67
3170 ! ! user: test
3171 ! ! user: test
3171 ! . date: Thu Jan 01 00:00:32 1970 +0000
3172 ! . date: Thu Jan 01 00:00:32 1970 +0000
3172 ! . summary: (32) expand
3173 ! . summary: (32) expand
3173 ! .
3174 ! .
3174 o ! changeset: 31:621d83e11f67
3175 o ! changeset: 31:621d83e11f67
3175 !\! parent: 21:d42a756af44d
3176 !\! parent: 21:d42a756af44d
3176 ! ! parent: 30:6e11cd4b648f
3177 ! ! parent: 30:6e11cd4b648f
3177 ! ! user: test
3178 ! ! user: test
3178 ! ! date: Thu Jan 01 00:00:31 1970 +0000
3179 ! ! date: Thu Jan 01 00:00:31 1970 +0000
3179 ! ! summary: (31) expand
3180 ! ! summary: (31) expand
3180 ! !
3181 ! !
3181 o ! changeset: 30:6e11cd4b648f
3182 o ! changeset: 30:6e11cd4b648f
3182 !\ \ parent: 28:44ecd0b9ae99
3183 !\ \ parent: 28:44ecd0b9ae99
3183 ! ~ ! parent: 29:cd9bb2be7593
3184 ! ~ ! parent: 29:cd9bb2be7593
3184 ! ! user: test
3185 ! ! user: test
3185 ! ! date: Thu Jan 01 00:00:30 1970 +0000
3186 ! ! date: Thu Jan 01 00:00:30 1970 +0000
3186 ! ! summary: (30) expand
3187 ! ! summary: (30) expand
3187 ! /
3188 ! /
3188 o ! changeset: 28:44ecd0b9ae99
3189 o ! changeset: 28:44ecd0b9ae99
3189 !\ \ parent: 1:6db2ef61d156
3190 !\ \ parent: 1:6db2ef61d156
3190 ! ~ ! parent: 26:7f25b6c2f0b9
3191 ! ~ ! parent: 26:7f25b6c2f0b9
3191 ! ! user: test
3192 ! ! user: test
3192 ! ! date: Thu Jan 01 00:00:28 1970 +0000
3193 ! ! date: Thu Jan 01 00:00:28 1970 +0000
3193 ! ! summary: (28) merge zero known
3194 ! ! summary: (28) merge zero known
3194 ! /
3195 ! /
3195 o ! changeset: 26:7f25b6c2f0b9
3196 o ! changeset: 26:7f25b6c2f0b9
3196 !\ \ parent: 18:1aa84d96232a
3197 !\ \ parent: 18:1aa84d96232a
3197 ! ! ! parent: 25:91da8ed57247
3198 ! ! ! parent: 25:91da8ed57247
3198 ! ! ! user: test
3199 ! ! ! user: test
3199 ! ! ! date: Thu Jan 01 00:00:26 1970 +0000
3200 ! ! ! date: Thu Jan 01 00:00:26 1970 +0000
3200 ! ! ! summary: (26) merge one known; far right
3201 ! ! ! summary: (26) merge one known; far right
3201 ! ! !
3202 ! ! !
3202 ! o ! changeset: 25:91da8ed57247
3203 ! o ! changeset: 25:91da8ed57247
3203 ! !\! parent: 21:d42a756af44d
3204 ! !\! parent: 21:d42a756af44d
3204 ! ! ! parent: 24:a9c19a3d96b7
3205 ! ! ! parent: 24:a9c19a3d96b7
3205 ! ! ! user: test
3206 ! ! ! user: test
3206 ! ! ! date: Thu Jan 01 00:00:25 1970 +0000
3207 ! ! ! date: Thu Jan 01 00:00:25 1970 +0000
3207 ! ! ! summary: (25) merge one known; far left
3208 ! ! ! summary: (25) merge one known; far left
3208 ! ! !
3209 ! ! !
3209 ! o ! changeset: 24:a9c19a3d96b7
3210 ! o ! changeset: 24:a9c19a3d96b7
3210 ! !\ \ parent: 0:e6eb3150255d
3211 ! !\ \ parent: 0:e6eb3150255d
3211 ! ! ~ ! parent: 23:a01cddf0766d
3212 ! ! ~ ! parent: 23:a01cddf0766d
3212 ! ! ! user: test
3213 ! ! ! user: test
3213 ! ! ! date: Thu Jan 01 00:00:24 1970 +0000
3214 ! ! ! date: Thu Jan 01 00:00:24 1970 +0000
3214 ! ! ! summary: (24) merge one known; immediate right
3215 ! ! ! summary: (24) merge one known; immediate right
3215 ! ! /
3216 ! ! /
3216 ! o ! changeset: 23:a01cddf0766d
3217 ! o ! changeset: 23:a01cddf0766d
3217 ! !\ \ parent: 1:6db2ef61d156
3218 ! !\ \ parent: 1:6db2ef61d156
3218 ! ! ~ ! parent: 22:e0d9cccacb5d
3219 ! ! ~ ! parent: 22:e0d9cccacb5d
3219 ! ! ! user: test
3220 ! ! ! user: test
3220 ! ! ! date: Thu Jan 01 00:00:23 1970 +0000
3221 ! ! ! date: Thu Jan 01 00:00:23 1970 +0000
3221 ! ! ! summary: (23) merge one known; immediate left
3222 ! ! ! summary: (23) merge one known; immediate left
3222 ! ! /
3223 ! ! /
3223 ! o ! changeset: 22:e0d9cccacb5d
3224 ! o ! changeset: 22:e0d9cccacb5d
3224 !/!/ parent: 18:1aa84d96232a
3225 !/!/ parent: 18:1aa84d96232a
3225 ! ! parent: 21:d42a756af44d
3226 ! ! parent: 21:d42a756af44d
3226 ! ! user: test
3227 ! ! user: test
3227 ! ! date: Thu Jan 01 00:00:22 1970 +0000
3228 ! ! date: Thu Jan 01 00:00:22 1970 +0000
3228 ! ! summary: (22) merge two known; one far left, one far right
3229 ! ! summary: (22) merge two known; one far left, one far right
3229 ! !
3230 ! !
3230 ! o changeset: 21:d42a756af44d
3231 ! o changeset: 21:d42a756af44d
3231 ! !\ parent: 19:31ddc2c1573b
3232 ! !\ parent: 19:31ddc2c1573b
3232 ! ! ! parent: 20:d30ed6450e32
3233 ! ! ! parent: 20:d30ed6450e32
3233 ! ! ! user: test
3234 ! ! ! user: test
3234 ! ! ! date: Thu Jan 01 00:00:21 1970 +0000
3235 ! ! ! date: Thu Jan 01 00:00:21 1970 +0000
3235 ! ! ! summary: (21) expand
3236 ! ! ! summary: (21) expand
3236 ! ! !
3237 ! ! !
3237 +---o changeset: 20:d30ed6450e32
3238 +---o changeset: 20:d30ed6450e32
3238 ! ! | parent: 0:e6eb3150255d
3239 ! ! | parent: 0:e6eb3150255d
3239 ! ! ~ parent: 18:1aa84d96232a
3240 ! ! ~ parent: 18:1aa84d96232a
3240 ! ! user: test
3241 ! ! user: test
3241 ! ! date: Thu Jan 01 00:00:20 1970 +0000
3242 ! ! date: Thu Jan 01 00:00:20 1970 +0000
3242 ! ! summary: (20) merge two known; two far right
3243 ! ! summary: (20) merge two known; two far right
3243 ! !
3244 ! !
3244 ! o changeset: 19:31ddc2c1573b
3245 ! o changeset: 19:31ddc2c1573b
3245 ! |\ parent: 15:1dda3f72782d
3246 ! |\ parent: 15:1dda3f72782d
3246 ! ~ ~ parent: 17:44765d7c06e0
3247 ! ~ ~ parent: 17:44765d7c06e0
3247 ! user: test
3248 ! user: test
3248 ! date: Thu Jan 01 00:00:19 1970 +0000
3249 ! date: Thu Jan 01 00:00:19 1970 +0000
3249 ! summary: (19) expand
3250 ! summary: (19) expand
3250 !
3251 !
3251 o changeset: 18:1aa84d96232a
3252 o changeset: 18:1aa84d96232a
3252 |\ parent: 1:6db2ef61d156
3253 |\ parent: 1:6db2ef61d156
3253 ~ ~ parent: 15:1dda3f72782d
3254 ~ ~ parent: 15:1dda3f72782d
3254 user: test
3255 user: test
3255 date: Thu Jan 01 00:00:18 1970 +0000
3256 date: Thu Jan 01 00:00:18 1970 +0000
3256 summary: (18) merge two known; two far left
3257 summary: (18) merge two known; two far left
3257
3258
3258 All but the first 3 lines:
3259 All but the first 3 lines:
3259
3260
3260 $ cat << EOF >> $HGRCPATH
3261 $ cat << EOF >> $HGRCPATH
3261 > [experimental]
3262 > [experimental]
3262 > graphstyle.parent = !
3263 > graphstyle.parent = !
3263 > graphstyle.grandparent = -3.
3264 > graphstyle.grandparent = -3.
3264 > graphstyle.missing =
3265 > graphstyle.missing =
3265 > EOF
3266 > EOF
3266 $ hg log -G -r '36:18 & file("a")' -m
3267 $ hg log -G -r '36:18 & file("a")' -m
3267 @ changeset: 36:08a19a744424
3268 @ changeset: 36:08a19a744424
3268 ! branch: branch
3269 ! branch: branch
3269 ! tag: tip
3270 ! tag: tip
3270 . parent: 35:9159c3644c5e
3271 . parent: 35:9159c3644c5e
3271 . parent: 35:9159c3644c5e
3272 . parent: 35:9159c3644c5e
3272 . user: test
3273 . user: test
3273 . date: Thu Jan 01 00:00:36 1970 +0000
3274 . date: Thu Jan 01 00:00:36 1970 +0000
3274 . summary: (36) buggy merge: identical parents
3275 . summary: (36) buggy merge: identical parents
3275 .
3276 .
3276 o changeset: 32:d06dffa21a31
3277 o changeset: 32:d06dffa21a31
3277 !\ parent: 27:886ed638191b
3278 !\ parent: 27:886ed638191b
3278 ! ! parent: 31:621d83e11f67
3279 ! ! parent: 31:621d83e11f67
3279 ! . user: test
3280 ! . user: test
3280 ! . date: Thu Jan 01 00:00:32 1970 +0000
3281 ! . date: Thu Jan 01 00:00:32 1970 +0000
3281 ! . summary: (32) expand
3282 ! . summary: (32) expand
3282 ! .
3283 ! .
3283 o ! changeset: 31:621d83e11f67
3284 o ! changeset: 31:621d83e11f67
3284 !\! parent: 21:d42a756af44d
3285 !\! parent: 21:d42a756af44d
3285 ! ! parent: 30:6e11cd4b648f
3286 ! ! parent: 30:6e11cd4b648f
3286 ! ! user: test
3287 ! ! user: test
3287 ! ! date: Thu Jan 01 00:00:31 1970 +0000
3288 ! ! date: Thu Jan 01 00:00:31 1970 +0000
3288 ! ! summary: (31) expand
3289 ! ! summary: (31) expand
3289 ! !
3290 ! !
3290 o ! changeset: 30:6e11cd4b648f
3291 o ! changeset: 30:6e11cd4b648f
3291 !\ \ parent: 28:44ecd0b9ae99
3292 !\ \ parent: 28:44ecd0b9ae99
3292 ! ~ ! parent: 29:cd9bb2be7593
3293 ! ~ ! parent: 29:cd9bb2be7593
3293 ! ! user: test
3294 ! ! user: test
3294 ! ! date: Thu Jan 01 00:00:30 1970 +0000
3295 ! ! date: Thu Jan 01 00:00:30 1970 +0000
3295 ! ! summary: (30) expand
3296 ! ! summary: (30) expand
3296 ! /
3297 ! /
3297 o ! changeset: 28:44ecd0b9ae99
3298 o ! changeset: 28:44ecd0b9ae99
3298 !\ \ parent: 1:6db2ef61d156
3299 !\ \ parent: 1:6db2ef61d156
3299 ! ~ ! parent: 26:7f25b6c2f0b9
3300 ! ~ ! parent: 26:7f25b6c2f0b9
3300 ! ! user: test
3301 ! ! user: test
3301 ! ! date: Thu Jan 01 00:00:28 1970 +0000
3302 ! ! date: Thu Jan 01 00:00:28 1970 +0000
3302 ! ! summary: (28) merge zero known
3303 ! ! summary: (28) merge zero known
3303 ! /
3304 ! /
3304 o ! changeset: 26:7f25b6c2f0b9
3305 o ! changeset: 26:7f25b6c2f0b9
3305 !\ \ parent: 18:1aa84d96232a
3306 !\ \ parent: 18:1aa84d96232a
3306 ! ! ! parent: 25:91da8ed57247
3307 ! ! ! parent: 25:91da8ed57247
3307 ! ! ! user: test
3308 ! ! ! user: test
3308 ! ! ! date: Thu Jan 01 00:00:26 1970 +0000
3309 ! ! ! date: Thu Jan 01 00:00:26 1970 +0000
3309 ! ! ! summary: (26) merge one known; far right
3310 ! ! ! summary: (26) merge one known; far right
3310 ! ! !
3311 ! ! !
3311 ! o ! changeset: 25:91da8ed57247
3312 ! o ! changeset: 25:91da8ed57247
3312 ! !\! parent: 21:d42a756af44d
3313 ! !\! parent: 21:d42a756af44d
3313 ! ! ! parent: 24:a9c19a3d96b7
3314 ! ! ! parent: 24:a9c19a3d96b7
3314 ! ! ! user: test
3315 ! ! ! user: test
3315 ! ! ! date: Thu Jan 01 00:00:25 1970 +0000
3316 ! ! ! date: Thu Jan 01 00:00:25 1970 +0000
3316 ! ! ! summary: (25) merge one known; far left
3317 ! ! ! summary: (25) merge one known; far left
3317 ! ! !
3318 ! ! !
3318 ! o ! changeset: 24:a9c19a3d96b7
3319 ! o ! changeset: 24:a9c19a3d96b7
3319 ! !\ \ parent: 0:e6eb3150255d
3320 ! !\ \ parent: 0:e6eb3150255d
3320 ! ! ~ ! parent: 23:a01cddf0766d
3321 ! ! ~ ! parent: 23:a01cddf0766d
3321 ! ! ! user: test
3322 ! ! ! user: test
3322 ! ! ! date: Thu Jan 01 00:00:24 1970 +0000
3323 ! ! ! date: Thu Jan 01 00:00:24 1970 +0000
3323 ! ! ! summary: (24) merge one known; immediate right
3324 ! ! ! summary: (24) merge one known; immediate right
3324 ! ! /
3325 ! ! /
3325 ! o ! changeset: 23:a01cddf0766d
3326 ! o ! changeset: 23:a01cddf0766d
3326 ! !\ \ parent: 1:6db2ef61d156
3327 ! !\ \ parent: 1:6db2ef61d156
3327 ! ! ~ ! parent: 22:e0d9cccacb5d
3328 ! ! ~ ! parent: 22:e0d9cccacb5d
3328 ! ! ! user: test
3329 ! ! ! user: test
3329 ! ! ! date: Thu Jan 01 00:00:23 1970 +0000
3330 ! ! ! date: Thu Jan 01 00:00:23 1970 +0000
3330 ! ! ! summary: (23) merge one known; immediate left
3331 ! ! ! summary: (23) merge one known; immediate left
3331 ! ! /
3332 ! ! /
3332 ! o ! changeset: 22:e0d9cccacb5d
3333 ! o ! changeset: 22:e0d9cccacb5d
3333 !/!/ parent: 18:1aa84d96232a
3334 !/!/ parent: 18:1aa84d96232a
3334 ! ! parent: 21:d42a756af44d
3335 ! ! parent: 21:d42a756af44d
3335 ! ! user: test
3336 ! ! user: test
3336 ! ! date: Thu Jan 01 00:00:22 1970 +0000
3337 ! ! date: Thu Jan 01 00:00:22 1970 +0000
3337 ! ! summary: (22) merge two known; one far left, one far right
3338 ! ! summary: (22) merge two known; one far left, one far right
3338 ! !
3339 ! !
3339 ! o changeset: 21:d42a756af44d
3340 ! o changeset: 21:d42a756af44d
3340 ! !\ parent: 19:31ddc2c1573b
3341 ! !\ parent: 19:31ddc2c1573b
3341 ! ! ! parent: 20:d30ed6450e32
3342 ! ! ! parent: 20:d30ed6450e32
3342 ! ! ! user: test
3343 ! ! ! user: test
3343 ! ! ! date: Thu Jan 01 00:00:21 1970 +0000
3344 ! ! ! date: Thu Jan 01 00:00:21 1970 +0000
3344 ! ! ! summary: (21) expand
3345 ! ! ! summary: (21) expand
3345 ! ! !
3346 ! ! !
3346 +---o changeset: 20:d30ed6450e32
3347 +---o changeset: 20:d30ed6450e32
3347 ! ! | parent: 0:e6eb3150255d
3348 ! ! | parent: 0:e6eb3150255d
3348 ! ! ~ parent: 18:1aa84d96232a
3349 ! ! ~ parent: 18:1aa84d96232a
3349 ! ! user: test
3350 ! ! user: test
3350 ! ! date: Thu Jan 01 00:00:20 1970 +0000
3351 ! ! date: Thu Jan 01 00:00:20 1970 +0000
3351 ! ! summary: (20) merge two known; two far right
3352 ! ! summary: (20) merge two known; two far right
3352 ! !
3353 ! !
3353 ! o changeset: 19:31ddc2c1573b
3354 ! o changeset: 19:31ddc2c1573b
3354 ! |\ parent: 15:1dda3f72782d
3355 ! |\ parent: 15:1dda3f72782d
3355 ! ~ ~ parent: 17:44765d7c06e0
3356 ! ~ ~ parent: 17:44765d7c06e0
3356 ! user: test
3357 ! user: test
3357 ! date: Thu Jan 01 00:00:19 1970 +0000
3358 ! date: Thu Jan 01 00:00:19 1970 +0000
3358 ! summary: (19) expand
3359 ! summary: (19) expand
3359 !
3360 !
3360 o changeset: 18:1aa84d96232a
3361 o changeset: 18:1aa84d96232a
3361 |\ parent: 1:6db2ef61d156
3362 |\ parent: 1:6db2ef61d156
3362 ~ ~ parent: 15:1dda3f72782d
3363 ~ ~ parent: 15:1dda3f72782d
3363 user: test
3364 user: test
3364 date: Thu Jan 01 00:00:18 1970 +0000
3365 date: Thu Jan 01 00:00:18 1970 +0000
3365 summary: (18) merge two known; two far left
3366 summary: (18) merge two known; two far left
3366
3367
3367 $ cd ..
3368 $ cd ..
3368
3369
3369 Change graph shorten, test better with graphstyle.missing not none
3370 Change graph shorten, test better with graphstyle.missing not none
3370
3371
3371 $ cd repo
3372 $ cd repo
3372 $ cat << EOF >> $HGRCPATH
3373 $ cat << EOF >> $HGRCPATH
3373 > [experimental]
3374 > [experimental]
3374 > graphstyle.parent = |
3375 > graphstyle.parent = |
3375 > graphstyle.grandparent = :
3376 > graphstyle.grandparent = :
3376 > graphstyle.missing = '
3377 > graphstyle.missing = '
3377 > graphshorten = true
3378 > graphshorten = true
3378 > EOF
3379 > EOF
3379 $ hg log -G -r 'file("a")' -m -T '{rev} {desc}'
3380 $ hg log -G -r 'file("a")' -m -T '{rev} {desc}'
3380 @ 36 (36) buggy merge: identical parents
3381 @ 36 (36) buggy merge: identical parents
3381 o 32 (32) expand
3382 o 32 (32) expand
3382 |\
3383 |\
3383 o : 31 (31) expand
3384 o : 31 (31) expand
3384 |\:
3385 |\:
3385 o : 30 (30) expand
3386 o : 30 (30) expand
3386 |\ \
3387 |\ \
3387 o \ \ 28 (28) merge zero known
3388 o \ \ 28 (28) merge zero known
3388 |\ \ \
3389 |\ \ \
3389 o \ \ \ 26 (26) merge one known; far right
3390 o \ \ \ 26 (26) merge one known; far right
3390 |\ \ \ \
3391 |\ \ \ \
3391 | o-----+ 25 (25) merge one known; far left
3392 | o-----+ 25 (25) merge one known; far left
3392 | o ' ' : 24 (24) merge one known; immediate right
3393 | o ' ' : 24 (24) merge one known; immediate right
3393 | |\ \ \ \
3394 | |\ \ \ \
3394 | o---+ ' : 23 (23) merge one known; immediate left
3395 | o---+ ' : 23 (23) merge one known; immediate left
3395 | o-------+ 22 (22) merge two known; one far left, one far right
3396 | o-------+ 22 (22) merge two known; one far left, one far right
3396 |/ / / / /
3397 |/ / / / /
3397 | ' ' ' o 21 (21) expand
3398 | ' ' ' o 21 (21) expand
3398 | ' ' ' |\
3399 | ' ' ' |\
3399 +-+-------o 20 (20) merge two known; two far right
3400 +-+-------o 20 (20) merge two known; two far right
3400 | ' ' ' o 19 (19) expand
3401 | ' ' ' o 19 (19) expand
3401 | ' ' ' |\
3402 | ' ' ' |\
3402 o---+---+ | 18 (18) merge two known; two far left
3403 o---+---+ | 18 (18) merge two known; two far left
3403 / / / / /
3404 / / / / /
3404 ' ' ' | o 17 (17) expand
3405 ' ' ' | o 17 (17) expand
3405 ' ' ' | |\
3406 ' ' ' | |\
3406 +-+-------o 16 (16) merge two known; one immediate right, one near right
3407 +-+-------o 16 (16) merge two known; one immediate right, one near right
3407 ' ' ' o | 15 (15) expand
3408 ' ' ' o | 15 (15) expand
3408 ' ' ' |\ \
3409 ' ' ' |\ \
3409 +-------o | 14 (14) merge two known; one immediate right, one far right
3410 +-------o | 14 (14) merge two known; one immediate right, one far right
3410 ' ' ' | |/
3411 ' ' ' | |/
3411 ' ' ' o | 13 (13) expand
3412 ' ' ' o | 13 (13) expand
3412 ' ' ' |\ \
3413 ' ' ' |\ \
3413 ' +---+---o 12 (12) merge two known; one immediate right, one far left
3414 ' +---+---o 12 (12) merge two known; one immediate right, one far left
3414 ' ' ' | o 11 (11) expand
3415 ' ' ' | o 11 (11) expand
3415 ' ' ' | |\
3416 ' ' ' | |\
3416 +---------o 10 (10) merge two known; one immediate left, one near right
3417 +---------o 10 (10) merge two known; one immediate left, one near right
3417 ' ' ' | |/
3418 ' ' ' | |/
3418 ' ' ' o | 9 (9) expand
3419 ' ' ' o | 9 (9) expand
3419 ' ' ' |\ \
3420 ' ' ' |\ \
3420 +-------o | 8 (8) merge two known; one immediate left, one far right
3421 +-------o | 8 (8) merge two known; one immediate left, one far right
3421 ' ' ' |/ /
3422 ' ' ' |/ /
3422 ' ' ' o | 7 (7) expand
3423 ' ' ' o | 7 (7) expand
3423 ' ' ' |\ \
3424 ' ' ' |\ \
3424 ' ' ' +---o 6 (6) merge two known; one immediate left, one far left
3425 ' ' ' +---o 6 (6) merge two known; one immediate left, one far left
3425 ' ' ' | '/
3426 ' ' ' | '/
3426 ' ' ' o ' 5 (5) expand
3427 ' ' ' o ' 5 (5) expand
3427 ' ' ' |\ \
3428 ' ' ' |\ \
3428 ' +---o ' ' 4 (4) merge two known; one immediate left, one immediate right
3429 ' +---o ' ' 4 (4) merge two known; one immediate left, one immediate right
3429 ' ' ' '/ /
3430 ' ' ' '/ /
3430
3431
3431 behavior with newlines
3432 behavior with newlines
3432
3433
3433 $ hg log -G -r ::2 -T '{rev} {desc}'
3434 $ hg log -G -r ::2 -T '{rev} {desc}'
3434 o 2 (2) collapse
3435 o 2 (2) collapse
3435 o 1 (1) collapse
3436 o 1 (1) collapse
3436 o 0 (0) root
3437 o 0 (0) root
3437
3438
3438 $ hg log -G -r ::2 -T '{rev} {desc}\n'
3439 $ hg log -G -r ::2 -T '{rev} {desc}\n'
3439 o 2 (2) collapse
3440 o 2 (2) collapse
3440 o 1 (1) collapse
3441 o 1 (1) collapse
3441 o 0 (0) root
3442 o 0 (0) root
3442
3443
3443 $ hg log -G -r ::2 -T '{rev} {desc}\n\n'
3444 $ hg log -G -r ::2 -T '{rev} {desc}\n\n'
3444 o 2 (2) collapse
3445 o 2 (2) collapse
3445 |
3446 |
3446 o 1 (1) collapse
3447 o 1 (1) collapse
3447 |
3448 |
3448 o 0 (0) root
3449 o 0 (0) root
3449
3450
3450
3451
3451 $ hg log -G -r ::2 -T '\n{rev} {desc}'
3452 $ hg log -G -r ::2 -T '\n{rev} {desc}'
3452 o
3453 o
3453 | 2 (2) collapse
3454 | 2 (2) collapse
3454 o
3455 o
3455 | 1 (1) collapse
3456 | 1 (1) collapse
3456 o
3457 o
3457 0 (0) root
3458 0 (0) root
3458
3459
3459 $ hg log -G -r ::2 -T '{rev} {desc}\n\n\n'
3460 $ hg log -G -r ::2 -T '{rev} {desc}\n\n\n'
3460 o 2 (2) collapse
3461 o 2 (2) collapse
3461 |
3462 |
3462 |
3463 |
3463 o 1 (1) collapse
3464 o 1 (1) collapse
3464 |
3465 |
3465 |
3466 |
3466 o 0 (0) root
3467 o 0 (0) root
3467
3468
3468
3469
3469 $ cd ..
3470 $ cd ..
3470
3471
3471 When inserting extra line nodes to handle more than 2 parents, ensure that
3472 When inserting extra line nodes to handle more than 2 parents, ensure that
3472 the right node styles are used (issue5174):
3473 the right node styles are used (issue5174):
3473
3474
3474 $ hg init repo-issue5174
3475 $ hg init repo-issue5174
3475 $ cd repo-issue5174
3476 $ cd repo-issue5174
3476 $ echo a > f0
3477 $ echo a > f0
3477 $ hg ci -Aqm 0
3478 $ hg ci -Aqm 0
3478 $ echo a > f1
3479 $ echo a > f1
3479 $ hg ci -Aqm 1
3480 $ hg ci -Aqm 1
3480 $ echo a > f2
3481 $ echo a > f2
3481 $ hg ci -Aqm 2
3482 $ hg ci -Aqm 2
3482 $ hg co ".^"
3483 $ hg co ".^"
3483 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
3484 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
3484 $ echo a > f3
3485 $ echo a > f3
3485 $ hg ci -Aqm 3
3486 $ hg ci -Aqm 3
3486 $ hg co ".^^"
3487 $ hg co ".^^"
3487 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
3488 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
3488 $ echo a > f4
3489 $ echo a > f4
3489 $ hg ci -Aqm 4
3490 $ hg ci -Aqm 4
3490 $ hg merge -r 2
3491 $ hg merge -r 2
3491 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
3492 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
3492 (branch merge, don't forget to commit)
3493 (branch merge, don't forget to commit)
3493 $ hg ci -qm 5
3494 $ hg ci -qm 5
3494 $ hg merge -r 3
3495 $ hg merge -r 3
3495 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
3496 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
3496 (branch merge, don't forget to commit)
3497 (branch merge, don't forget to commit)
3497 $ hg ci -qm 6
3498 $ hg ci -qm 6
3498 $ hg log -G -r '0 | 1 | 2 | 6'
3499 $ hg log -G -r '0 | 1 | 2 | 6'
3499 @ changeset: 6:851fe89689ad
3500 @ changeset: 6:851fe89689ad
3500 :\ tag: tip
3501 :\ tag: tip
3501 : : parent: 5:4f1e3cf15f5d
3502 : : parent: 5:4f1e3cf15f5d
3502 : : parent: 3:b74ba7084d2d
3503 : : parent: 3:b74ba7084d2d
3503 : : user: test
3504 : : user: test
3504 : : date: Thu Jan 01 00:00:00 1970 +0000
3505 : : date: Thu Jan 01 00:00:00 1970 +0000
3505 : : summary: 6
3506 : : summary: 6
3506 : :
3507 : :
3507 : \
3508 : \
3508 : :\
3509 : :\
3509 : o : changeset: 2:3e6599df4cce
3510 : o : changeset: 2:3e6599df4cce
3510 : :/ user: test
3511 : :/ user: test
3511 : : date: Thu Jan 01 00:00:00 1970 +0000
3512 : : date: Thu Jan 01 00:00:00 1970 +0000
3512 : : summary: 2
3513 : : summary: 2
3513 : :
3514 : :
3514 : o changeset: 1:bd9a55143933
3515 : o changeset: 1:bd9a55143933
3515 :/ user: test
3516 :/ user: test
3516 : date: Thu Jan 01 00:00:00 1970 +0000
3517 : date: Thu Jan 01 00:00:00 1970 +0000
3517 : summary: 1
3518 : summary: 1
3518 :
3519 :
3519 o changeset: 0:870a5edc339c
3520 o changeset: 0:870a5edc339c
3520 user: test
3521 user: test
3521 date: Thu Jan 01 00:00:00 1970 +0000
3522 date: Thu Jan 01 00:00:00 1970 +0000
3522 summary: 0
3523 summary: 0
3523
3524
3524
3525
3525 $ cd ..
3526 $ cd ..
3526
3527
3527 Multiple roots (issue5440):
3528 Multiple roots (issue5440):
3528
3529
3529 $ hg init multiroots
3530 $ hg init multiroots
3530 $ cd multiroots
3531 $ cd multiroots
3531 $ cat <<EOF > .hg/hgrc
3532 $ cat <<EOF > .hg/hgrc
3532 > [ui]
3533 > [ui]
3533 > logtemplate = '{rev} {desc}\n\n'
3534 > logtemplate = '{rev} {desc}\n\n'
3534 > EOF
3535 > EOF
3535
3536
3536 $ touch foo
3537 $ touch foo
3537 $ hg ci -Aqm foo
3538 $ hg ci -Aqm foo
3538 $ hg co -q null
3539 $ hg co -q null
3539 $ touch bar
3540 $ touch bar
3540 $ hg ci -Aqm bar
3541 $ hg ci -Aqm bar
3541
3542
3542 $ hg log -Gr null:
3543 $ hg log -Gr null:
3543 @ 1 bar
3544 @ 1 bar
3544 |
3545 |
3545 | o 0 foo
3546 | o 0 foo
3546 |/
3547 |/
3547 o -1
3548 o -1
3548
3549
3549 $ hg log -Gr null+0
3550 $ hg log -Gr null+0
3550 o 0 foo
3551 o 0 foo
3551 |
3552 |
3552 o -1
3553 o -1
3553
3554
3554 $ hg log -Gr null+1
3555 $ hg log -Gr null+1
3555 @ 1 bar
3556 @ 1 bar
3556 |
3557 |
3557 o -1
3558 o -1
3558
3559
3559
3560
3560 $ cd ..
3561 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now