##// END OF EJS Templates
commit: if interactive, look elsewhere for whitespace settings (BC)...
Kyle Lippincott -
r41701:66399f2e default
parent child Browse files
Show More
@@ -1,3327 +1,3331 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 os
11 import os
12 import re
12 import re
13
13
14 from .i18n import _
14 from .i18n import _
15 from .node import (
15 from .node import (
16 hex,
16 hex,
17 nullid,
17 nullid,
18 nullrev,
18 nullrev,
19 short,
19 short,
20 )
20 )
21
21
22 from . import (
22 from . import (
23 bookmarks,
23 bookmarks,
24 changelog,
24 changelog,
25 copies,
25 copies,
26 crecord as crecordmod,
26 crecord as crecordmod,
27 dirstateguard,
27 dirstateguard,
28 encoding,
28 encoding,
29 error,
29 error,
30 formatter,
30 formatter,
31 logcmdutil,
31 logcmdutil,
32 match as matchmod,
32 match as matchmod,
33 merge as mergemod,
33 merge as mergemod,
34 mergeutil,
34 mergeutil,
35 obsolete,
35 obsolete,
36 patch,
36 patch,
37 pathutil,
37 pathutil,
38 phases,
38 phases,
39 pycompat,
39 pycompat,
40 revlog,
40 revlog,
41 rewriteutil,
41 rewriteutil,
42 scmutil,
42 scmutil,
43 smartset,
43 smartset,
44 subrepoutil,
44 subrepoutil,
45 templatekw,
45 templatekw,
46 templater,
46 templater,
47 util,
47 util,
48 vfs as vfsmod,
48 vfs as vfsmod,
49 )
49 )
50
50
51 from .utils import (
51 from .utils import (
52 dateutil,
52 dateutil,
53 stringutil,
53 stringutil,
54 )
54 )
55
55
56 stringio = util.stringio
56 stringio = util.stringio
57
57
58 # templates of common command options
58 # templates of common command options
59
59
60 dryrunopts = [
60 dryrunopts = [
61 ('n', 'dry-run', None,
61 ('n', 'dry-run', None,
62 _('do not perform actions, just print output')),
62 _('do not perform actions, just print output')),
63 ]
63 ]
64
64
65 confirmopts = [
65 confirmopts = [
66 ('', 'confirm', None,
66 ('', 'confirm', None,
67 _('ask before applying actions')),
67 _('ask before applying actions')),
68 ]
68 ]
69
69
70 remoteopts = [
70 remoteopts = [
71 ('e', 'ssh', '',
71 ('e', 'ssh', '',
72 _('specify ssh command to use'), _('CMD')),
72 _('specify ssh command to use'), _('CMD')),
73 ('', 'remotecmd', '',
73 ('', 'remotecmd', '',
74 _('specify hg command to run on the remote side'), _('CMD')),
74 _('specify hg command to run on the remote side'), _('CMD')),
75 ('', 'insecure', None,
75 ('', 'insecure', None,
76 _('do not verify server certificate (ignoring web.cacerts config)')),
76 _('do not verify server certificate (ignoring web.cacerts config)')),
77 ]
77 ]
78
78
79 walkopts = [
79 walkopts = [
80 ('I', 'include', [],
80 ('I', 'include', [],
81 _('include names matching the given patterns'), _('PATTERN')),
81 _('include names matching the given patterns'), _('PATTERN')),
82 ('X', 'exclude', [],
82 ('X', 'exclude', [],
83 _('exclude names matching the given patterns'), _('PATTERN')),
83 _('exclude names matching the given patterns'), _('PATTERN')),
84 ]
84 ]
85
85
86 commitopts = [
86 commitopts = [
87 ('m', 'message', '',
87 ('m', 'message', '',
88 _('use text as commit message'), _('TEXT')),
88 _('use text as commit message'), _('TEXT')),
89 ('l', 'logfile', '',
89 ('l', 'logfile', '',
90 _('read commit message from file'), _('FILE')),
90 _('read commit message from file'), _('FILE')),
91 ]
91 ]
92
92
93 commitopts2 = [
93 commitopts2 = [
94 ('d', 'date', '',
94 ('d', 'date', '',
95 _('record the specified date as commit date'), _('DATE')),
95 _('record the specified date as commit date'), _('DATE')),
96 ('u', 'user', '',
96 ('u', 'user', '',
97 _('record the specified user as committer'), _('USER')),
97 _('record the specified user as committer'), _('USER')),
98 ]
98 ]
99
99
100 formatteropts = [
100 formatteropts = [
101 ('T', 'template', '',
101 ('T', 'template', '',
102 _('display with template'), _('TEMPLATE')),
102 _('display with template'), _('TEMPLATE')),
103 ]
103 ]
104
104
105 templateopts = [
105 templateopts = [
106 ('', 'style', '',
106 ('', 'style', '',
107 _('display using template map file (DEPRECATED)'), _('STYLE')),
107 _('display using template map file (DEPRECATED)'), _('STYLE')),
108 ('T', 'template', '',
108 ('T', 'template', '',
109 _('display with template'), _('TEMPLATE')),
109 _('display with template'), _('TEMPLATE')),
110 ]
110 ]
111
111
112 logopts = [
112 logopts = [
113 ('p', 'patch', None, _('show patch')),
113 ('p', 'patch', None, _('show patch')),
114 ('g', 'git', None, _('use git extended diff format')),
114 ('g', 'git', None, _('use git extended diff format')),
115 ('l', 'limit', '',
115 ('l', 'limit', '',
116 _('limit number of changes displayed'), _('NUM')),
116 _('limit number of changes displayed'), _('NUM')),
117 ('M', 'no-merges', None, _('do not show merges')),
117 ('M', 'no-merges', None, _('do not show merges')),
118 ('', 'stat', None, _('output diffstat-style summary of changes')),
118 ('', 'stat', None, _('output diffstat-style summary of changes')),
119 ('G', 'graph', None, _("show the revision DAG")),
119 ('G', 'graph', None, _("show the revision DAG")),
120 ] + templateopts
120 ] + templateopts
121
121
122 diffopts = [
122 diffopts = [
123 ('a', 'text', None, _('treat all files as text')),
123 ('a', 'text', None, _('treat all files as text')),
124 ('g', 'git', None, _('use git extended diff format')),
124 ('g', 'git', None, _('use git extended diff format')),
125 ('', 'binary', None, _('generate binary diffs in git mode (default)')),
125 ('', 'binary', None, _('generate binary diffs in git mode (default)')),
126 ('', 'nodates', None, _('omit dates from diff headers'))
126 ('', 'nodates', None, _('omit dates from diff headers'))
127 ]
127 ]
128
128
129 diffwsopts = [
129 diffwsopts = [
130 ('w', 'ignore-all-space', None,
130 ('w', 'ignore-all-space', None,
131 _('ignore white space when comparing lines')),
131 _('ignore white space when comparing lines')),
132 ('b', 'ignore-space-change', None,
132 ('b', 'ignore-space-change', None,
133 _('ignore changes in the amount of white space')),
133 _('ignore changes in the amount of white space')),
134 ('B', 'ignore-blank-lines', None,
134 ('B', 'ignore-blank-lines', None,
135 _('ignore changes whose lines are all blank')),
135 _('ignore changes whose lines are all blank')),
136 ('Z', 'ignore-space-at-eol', None,
136 ('Z', 'ignore-space-at-eol', None,
137 _('ignore changes in whitespace at EOL')),
137 _('ignore changes in whitespace at EOL')),
138 ]
138 ]
139
139
140 diffopts2 = [
140 diffopts2 = [
141 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
141 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
142 ('p', 'show-function', None, _('show which function each change is in')),
142 ('p', 'show-function', None, _('show which function each change is in')),
143 ('', 'reverse', None, _('produce a diff that undoes the changes')),
143 ('', 'reverse', None, _('produce a diff that undoes the changes')),
144 ] + diffwsopts + [
144 ] + diffwsopts + [
145 ('U', 'unified', '',
145 ('U', 'unified', '',
146 _('number of lines of context to show'), _('NUM')),
146 _('number of lines of context to show'), _('NUM')),
147 ('', 'stat', None, _('output diffstat-style summary of changes')),
147 ('', 'stat', None, _('output diffstat-style summary of changes')),
148 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
148 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
149 ]
149 ]
150
150
151 mergetoolopts = [
151 mergetoolopts = [
152 ('t', 'tool', '', _('specify merge tool'), _('TOOL')),
152 ('t', 'tool', '', _('specify merge tool'), _('TOOL')),
153 ]
153 ]
154
154
155 similarityopts = [
155 similarityopts = [
156 ('s', 'similarity', '',
156 ('s', 'similarity', '',
157 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
157 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
158 ]
158 ]
159
159
160 subrepoopts = [
160 subrepoopts = [
161 ('S', 'subrepos', None,
161 ('S', 'subrepos', None,
162 _('recurse into subrepositories'))
162 _('recurse into subrepositories'))
163 ]
163 ]
164
164
165 debugrevlogopts = [
165 debugrevlogopts = [
166 ('c', 'changelog', False, _('open changelog')),
166 ('c', 'changelog', False, _('open changelog')),
167 ('m', 'manifest', False, _('open manifest')),
167 ('m', 'manifest', False, _('open manifest')),
168 ('', 'dir', '', _('open directory manifest')),
168 ('', 'dir', '', _('open directory manifest')),
169 ]
169 ]
170
170
171 # special string such that everything below this line will be ingored in the
171 # special string such that everything below this line will be ingored in the
172 # editor text
172 # editor text
173 _linebelow = "^HG: ------------------------ >8 ------------------------$"
173 _linebelow = "^HG: ------------------------ >8 ------------------------$"
174
174
175 def ishunk(x):
175 def ishunk(x):
176 hunkclasses = (crecordmod.uihunk, patch.recordhunk)
176 hunkclasses = (crecordmod.uihunk, patch.recordhunk)
177 return isinstance(x, hunkclasses)
177 return isinstance(x, hunkclasses)
178
178
179 def newandmodified(chunks, originalchunks):
179 def newandmodified(chunks, originalchunks):
180 newlyaddedandmodifiedfiles = set()
180 newlyaddedandmodifiedfiles = set()
181 for chunk in chunks:
181 for chunk in chunks:
182 if ishunk(chunk) and chunk.header.isnewfile() and chunk not in \
182 if ishunk(chunk) and chunk.header.isnewfile() and chunk not in \
183 originalchunks:
183 originalchunks:
184 newlyaddedandmodifiedfiles.add(chunk.header.filename())
184 newlyaddedandmodifiedfiles.add(chunk.header.filename())
185 return newlyaddedandmodifiedfiles
185 return newlyaddedandmodifiedfiles
186
186
187 def parsealiases(cmd):
187 def parsealiases(cmd):
188 return cmd.split("|")
188 return cmd.split("|")
189
189
190 def setupwrapcolorwrite(ui):
190 def setupwrapcolorwrite(ui):
191 # wrap ui.write so diff output can be labeled/colorized
191 # wrap ui.write so diff output can be labeled/colorized
192 def wrapwrite(orig, *args, **kw):
192 def wrapwrite(orig, *args, **kw):
193 label = kw.pop(r'label', '')
193 label = kw.pop(r'label', '')
194 for chunk, l in patch.difflabel(lambda: args):
194 for chunk, l in patch.difflabel(lambda: args):
195 orig(chunk, label=label + l)
195 orig(chunk, label=label + l)
196
196
197 oldwrite = ui.write
197 oldwrite = ui.write
198 def wrap(*args, **kwargs):
198 def wrap(*args, **kwargs):
199 return wrapwrite(oldwrite, *args, **kwargs)
199 return wrapwrite(oldwrite, *args, **kwargs)
200 setattr(ui, 'write', wrap)
200 setattr(ui, 'write', wrap)
201 return oldwrite
201 return oldwrite
202
202
203 def filterchunks(ui, originalhunks, usecurses, testfile, operation=None):
203 def filterchunks(ui, originalhunks, usecurses, testfile, operation=None):
204 try:
204 try:
205 if usecurses:
205 if usecurses:
206 if testfile:
206 if testfile:
207 recordfn = crecordmod.testdecorator(
207 recordfn = crecordmod.testdecorator(
208 testfile, crecordmod.testchunkselector)
208 testfile, crecordmod.testchunkselector)
209 else:
209 else:
210 recordfn = crecordmod.chunkselector
210 recordfn = crecordmod.chunkselector
211
211
212 return crecordmod.filterpatch(ui, originalhunks, recordfn,
212 return crecordmod.filterpatch(ui, originalhunks, recordfn,
213 operation)
213 operation)
214 except crecordmod.fallbackerror as e:
214 except crecordmod.fallbackerror as e:
215 ui.warn('%s\n' % e.message)
215 ui.warn('%s\n' % e.message)
216 ui.warn(_('falling back to text mode\n'))
216 ui.warn(_('falling back to text mode\n'))
217
217
218 return patch.filterpatch(ui, originalhunks, operation)
218 return patch.filterpatch(ui, originalhunks, operation)
219
219
220 def recordfilter(ui, originalhunks, operation=None):
220 def recordfilter(ui, originalhunks, operation=None):
221 """ Prompts the user to filter the originalhunks and return a list of
221 """ Prompts the user to filter the originalhunks and return a list of
222 selected hunks.
222 selected hunks.
223 *operation* is used for to build ui messages to indicate the user what
223 *operation* is used for to build ui messages to indicate the user what
224 kind of filtering they are doing: reverting, committing, shelving, etc.
224 kind of filtering they are doing: reverting, committing, shelving, etc.
225 (see patch.filterpatch).
225 (see patch.filterpatch).
226 """
226 """
227 usecurses = crecordmod.checkcurses(ui)
227 usecurses = crecordmod.checkcurses(ui)
228 testfile = ui.config('experimental', 'crecordtest')
228 testfile = ui.config('experimental', 'crecordtest')
229 oldwrite = setupwrapcolorwrite(ui)
229 oldwrite = setupwrapcolorwrite(ui)
230 try:
230 try:
231 newchunks, newopts = filterchunks(ui, originalhunks, usecurses,
231 newchunks, newopts = filterchunks(ui, originalhunks, usecurses,
232 testfile, operation)
232 testfile, operation)
233 finally:
233 finally:
234 ui.write = oldwrite
234 ui.write = oldwrite
235 return newchunks, newopts
235 return newchunks, newopts
236
236
237 def dorecord(ui, repo, commitfunc, cmdsuggest, backupall,
237 def dorecord(ui, repo, commitfunc, cmdsuggest, backupall,
238 filterfn, *pats, **opts):
238 filterfn, *pats, **opts):
239 opts = pycompat.byteskwargs(opts)
239 opts = pycompat.byteskwargs(opts)
240 if not ui.interactive():
240 if not ui.interactive():
241 if cmdsuggest:
241 if cmdsuggest:
242 msg = _('running non-interactively, use %s instead') % cmdsuggest
242 msg = _('running non-interactively, use %s instead') % cmdsuggest
243 else:
243 else:
244 msg = _('running non-interactively')
244 msg = _('running non-interactively')
245 raise error.Abort(msg)
245 raise error.Abort(msg)
246
246
247 # make sure username is set before going interactive
247 # make sure username is set before going interactive
248 if not opts.get('user'):
248 if not opts.get('user'):
249 ui.username() # raise exception, username not provided
249 ui.username() # raise exception, username not provided
250
250
251 def recordfunc(ui, repo, message, match, opts):
251 def recordfunc(ui, repo, message, match, opts):
252 """This is generic record driver.
252 """This is generic record driver.
253
253
254 Its job is to interactively filter local changes, and
254 Its job is to interactively filter local changes, and
255 accordingly prepare working directory into a state in which the
255 accordingly prepare working directory into a state in which the
256 job can be delegated to a non-interactive commit command such as
256 job can be delegated to a non-interactive commit command such as
257 'commit' or 'qrefresh'.
257 'commit' or 'qrefresh'.
258
258
259 After the actual job is done by non-interactive command, the
259 After the actual job is done by non-interactive command, the
260 working directory is restored to its original state.
260 working directory is restored to its original state.
261
261
262 In the end we'll record interesting changes, and everything else
262 In the end we'll record interesting changes, and everything else
263 will be left in place, so the user can continue working.
263 will be left in place, so the user can continue working.
264 """
264 """
265
265
266 checkunfinished(repo, commit=True)
266 checkunfinished(repo, commit=True)
267 wctx = repo[None]
267 wctx = repo[None]
268 merge = len(wctx.parents()) > 1
268 merge = len(wctx.parents()) > 1
269 if merge:
269 if merge:
270 raise error.Abort(_('cannot partially commit a merge '
270 raise error.Abort(_('cannot partially commit a merge '
271 '(use "hg commit" instead)'))
271 '(use "hg commit" instead)'))
272
272
273 def fail(f, msg):
273 def fail(f, msg):
274 raise error.Abort('%s: %s' % (f, msg))
274 raise error.Abort('%s: %s' % (f, msg))
275
275
276 force = opts.get('force')
276 force = opts.get('force')
277 if not force:
277 if not force:
278 vdirs = []
278 vdirs = []
279 match.explicitdir = vdirs.append
279 match.explicitdir = vdirs.append
280 match.bad = fail
280 match.bad = fail
281
281
282 status = repo.status(match=match)
282 status = repo.status(match=match)
283 if not force:
283 if not force:
284 repo.checkcommitpatterns(wctx, vdirs, match, status, fail)
284 repo.checkcommitpatterns(wctx, vdirs, match, status, fail)
285 diffopts = patch.difffeatureopts(ui, opts=opts)
285 diffopts = patch.difffeatureopts(ui, opts=opts, whitespace=True,
286 section='commands',
287 configprefix='commit.interactive.')
286 diffopts.nodates = True
288 diffopts.nodates = True
287 diffopts.git = True
289 diffopts.git = True
288 diffopts.showfunc = True
290 diffopts.showfunc = True
289 originaldiff = patch.diff(repo, changes=status, opts=diffopts)
291 originaldiff = patch.diff(repo, changes=status, opts=diffopts)
290 originalchunks = patch.parsepatch(originaldiff)
292 originalchunks = patch.parsepatch(originaldiff)
291
293
292 # 1. filter patch, since we are intending to apply subset of it
294 # 1. filter patch, since we are intending to apply subset of it
293 try:
295 try:
294 chunks, newopts = filterfn(ui, originalchunks)
296 chunks, newopts = filterfn(ui, originalchunks)
295 except error.PatchError as err:
297 except error.PatchError as err:
296 raise error.Abort(_('error parsing patch: %s') % err)
298 raise error.Abort(_('error parsing patch: %s') % err)
297 opts.update(newopts)
299 opts.update(newopts)
298
300
299 # We need to keep a backup of files that have been newly added and
301 # We need to keep a backup of files that have been newly added and
300 # modified during the recording process because there is a previous
302 # modified during the recording process because there is a previous
301 # version without the edit in the workdir
303 # version without the edit in the workdir
302 newlyaddedandmodifiedfiles = newandmodified(chunks, originalchunks)
304 newlyaddedandmodifiedfiles = newandmodified(chunks, originalchunks)
303 contenders = set()
305 contenders = set()
304 for h in chunks:
306 for h in chunks:
305 try:
307 try:
306 contenders.update(set(h.files()))
308 contenders.update(set(h.files()))
307 except AttributeError:
309 except AttributeError:
308 pass
310 pass
309
311
310 changed = status.modified + status.added + status.removed
312 changed = status.modified + status.added + status.removed
311 newfiles = [f for f in changed if f in contenders]
313 newfiles = [f for f in changed if f in contenders]
312 if not newfiles:
314 if not newfiles:
313 ui.status(_('no changes to record\n'))
315 ui.status(_('no changes to record\n'))
314 return 0
316 return 0
315
317
316 modified = set(status.modified)
318 modified = set(status.modified)
317
319
318 # 2. backup changed files, so we can restore them in the end
320 # 2. backup changed files, so we can restore them in the end
319
321
320 if backupall:
322 if backupall:
321 tobackup = changed
323 tobackup = changed
322 else:
324 else:
323 tobackup = [f for f in newfiles if f in modified or f in \
325 tobackup = [f for f in newfiles if f in modified or f in \
324 newlyaddedandmodifiedfiles]
326 newlyaddedandmodifiedfiles]
325 backups = {}
327 backups = {}
326 if tobackup:
328 if tobackup:
327 backupdir = repo.vfs.join('record-backups')
329 backupdir = repo.vfs.join('record-backups')
328 try:
330 try:
329 os.mkdir(backupdir)
331 os.mkdir(backupdir)
330 except OSError as err:
332 except OSError as err:
331 if err.errno != errno.EEXIST:
333 if err.errno != errno.EEXIST:
332 raise
334 raise
333 try:
335 try:
334 # backup continues
336 # backup continues
335 for f in tobackup:
337 for f in tobackup:
336 fd, tmpname = pycompat.mkstemp(prefix=f.replace('/', '_') + '.',
338 fd, tmpname = pycompat.mkstemp(prefix=f.replace('/', '_') + '.',
337 dir=backupdir)
339 dir=backupdir)
338 os.close(fd)
340 os.close(fd)
339 ui.debug('backup %r as %r\n' % (f, tmpname))
341 ui.debug('backup %r as %r\n' % (f, tmpname))
340 util.copyfile(repo.wjoin(f), tmpname, copystat=True)
342 util.copyfile(repo.wjoin(f), tmpname, copystat=True)
341 backups[f] = tmpname
343 backups[f] = tmpname
342
344
343 fp = stringio()
345 fp = stringio()
344 for c in chunks:
346 for c in chunks:
345 fname = c.filename()
347 fname = c.filename()
346 if fname in backups:
348 if fname in backups:
347 c.write(fp)
349 c.write(fp)
348 dopatch = fp.tell()
350 dopatch = fp.tell()
349 fp.seek(0)
351 fp.seek(0)
350
352
351 # 2.5 optionally review / modify patch in text editor
353 # 2.5 optionally review / modify patch in text editor
352 if opts.get('review', False):
354 if opts.get('review', False):
353 patchtext = (crecordmod.diffhelptext
355 patchtext = (crecordmod.diffhelptext
354 + crecordmod.patchhelptext
356 + crecordmod.patchhelptext
355 + fp.read())
357 + fp.read())
356 reviewedpatch = ui.edit(patchtext, "",
358 reviewedpatch = ui.edit(patchtext, "",
357 action="diff",
359 action="diff",
358 repopath=repo.path)
360 repopath=repo.path)
359 fp.truncate(0)
361 fp.truncate(0)
360 fp.write(reviewedpatch)
362 fp.write(reviewedpatch)
361 fp.seek(0)
363 fp.seek(0)
362
364
363 [os.unlink(repo.wjoin(c)) for c in newlyaddedandmodifiedfiles]
365 [os.unlink(repo.wjoin(c)) for c in newlyaddedandmodifiedfiles]
364 # 3a. apply filtered patch to clean repo (clean)
366 # 3a. apply filtered patch to clean repo (clean)
365 if backups:
367 if backups:
366 # Equivalent to hg.revert
368 # Equivalent to hg.revert
367 m = scmutil.matchfiles(repo, backups.keys())
369 m = scmutil.matchfiles(repo, backups.keys())
368 mergemod.update(repo, repo.dirstate.p1(), branchmerge=False,
370 mergemod.update(repo, repo.dirstate.p1(), branchmerge=False,
369 force=True, matcher=m)
371 force=True, matcher=m)
370
372
371 # 3b. (apply)
373 # 3b. (apply)
372 if dopatch:
374 if dopatch:
373 try:
375 try:
374 ui.debug('applying patch\n')
376 ui.debug('applying patch\n')
375 ui.debug(fp.getvalue())
377 ui.debug(fp.getvalue())
376 patch.internalpatch(ui, repo, fp, 1, eolmode=None)
378 patch.internalpatch(ui, repo, fp, 1, eolmode=None)
377 except error.PatchError as err:
379 except error.PatchError as err:
378 raise error.Abort(pycompat.bytestr(err))
380 raise error.Abort(pycompat.bytestr(err))
379 del fp
381 del fp
380
382
381 # 4. We prepared working directory according to filtered
383 # 4. We prepared working directory according to filtered
382 # patch. Now is the time to delegate the job to
384 # patch. Now is the time to delegate the job to
383 # commit/qrefresh or the like!
385 # commit/qrefresh or the like!
384
386
385 # Make all of the pathnames absolute.
387 # Make all of the pathnames absolute.
386 newfiles = [repo.wjoin(nf) for nf in newfiles]
388 newfiles = [repo.wjoin(nf) for nf in newfiles]
387 return commitfunc(ui, repo, *newfiles, **pycompat.strkwargs(opts))
389 return commitfunc(ui, repo, *newfiles, **pycompat.strkwargs(opts))
388 finally:
390 finally:
389 # 5. finally restore backed-up files
391 # 5. finally restore backed-up files
390 try:
392 try:
391 dirstate = repo.dirstate
393 dirstate = repo.dirstate
392 for realname, tmpname in backups.iteritems():
394 for realname, tmpname in backups.iteritems():
393 ui.debug('restoring %r to %r\n' % (tmpname, realname))
395 ui.debug('restoring %r to %r\n' % (tmpname, realname))
394
396
395 if dirstate[realname] == 'n':
397 if dirstate[realname] == 'n':
396 # without normallookup, restoring timestamp
398 # without normallookup, restoring timestamp
397 # may cause partially committed files
399 # may cause partially committed files
398 # to be treated as unmodified
400 # to be treated as unmodified
399 dirstate.normallookup(realname)
401 dirstate.normallookup(realname)
400
402
401 # copystat=True here and above are a hack to trick any
403 # copystat=True here and above are a hack to trick any
402 # editors that have f open that we haven't modified them.
404 # editors that have f open that we haven't modified them.
403 #
405 #
404 # Also note that this racy as an editor could notice the
406 # Also note that this racy as an editor could notice the
405 # file's mtime before we've finished writing it.
407 # file's mtime before we've finished writing it.
406 util.copyfile(tmpname, repo.wjoin(realname), copystat=True)
408 util.copyfile(tmpname, repo.wjoin(realname), copystat=True)
407 os.unlink(tmpname)
409 os.unlink(tmpname)
408 if tobackup:
410 if tobackup:
409 os.rmdir(backupdir)
411 os.rmdir(backupdir)
410 except OSError:
412 except OSError:
411 pass
413 pass
412
414
413 def recordinwlock(ui, repo, message, match, opts):
415 def recordinwlock(ui, repo, message, match, opts):
414 with repo.wlock():
416 with repo.wlock():
415 return recordfunc(ui, repo, message, match, opts)
417 return recordfunc(ui, repo, message, match, opts)
416
418
417 return commit(ui, repo, recordinwlock, pats, opts)
419 return commit(ui, repo, recordinwlock, pats, opts)
418
420
419 class dirnode(object):
421 class dirnode(object):
420 """
422 """
421 Represent a directory in user working copy with information required for
423 Represent a directory in user working copy with information required for
422 the purpose of tersing its status.
424 the purpose of tersing its status.
423
425
424 path is the path to the directory, without a trailing '/'
426 path is the path to the directory, without a trailing '/'
425
427
426 statuses is a set of statuses of all files in this directory (this includes
428 statuses is a set of statuses of all files in this directory (this includes
427 all the files in all the subdirectories too)
429 all the files in all the subdirectories too)
428
430
429 files is a list of files which are direct child of this directory
431 files is a list of files which are direct child of this directory
430
432
431 subdirs is a dictionary of sub-directory name as the key and it's own
433 subdirs is a dictionary of sub-directory name as the key and it's own
432 dirnode object as the value
434 dirnode object as the value
433 """
435 """
434
436
435 def __init__(self, dirpath):
437 def __init__(self, dirpath):
436 self.path = dirpath
438 self.path = dirpath
437 self.statuses = set([])
439 self.statuses = set([])
438 self.files = []
440 self.files = []
439 self.subdirs = {}
441 self.subdirs = {}
440
442
441 def _addfileindir(self, filename, status):
443 def _addfileindir(self, filename, status):
442 """Add a file in this directory as a direct child."""
444 """Add a file in this directory as a direct child."""
443 self.files.append((filename, status))
445 self.files.append((filename, status))
444
446
445 def addfile(self, filename, status):
447 def addfile(self, filename, status):
446 """
448 """
447 Add a file to this directory or to its direct parent directory.
449 Add a file to this directory or to its direct parent directory.
448
450
449 If the file is not direct child of this directory, we traverse to the
451 If the file is not direct child of this directory, we traverse to the
450 directory of which this file is a direct child of and add the file
452 directory of which this file is a direct child of and add the file
451 there.
453 there.
452 """
454 """
453
455
454 # the filename contains a path separator, it means it's not the direct
456 # the filename contains a path separator, it means it's not the direct
455 # child of this directory
457 # child of this directory
456 if '/' in filename:
458 if '/' in filename:
457 subdir, filep = filename.split('/', 1)
459 subdir, filep = filename.split('/', 1)
458
460
459 # does the dirnode object for subdir exists
461 # does the dirnode object for subdir exists
460 if subdir not in self.subdirs:
462 if subdir not in self.subdirs:
461 subdirpath = pathutil.join(self.path, subdir)
463 subdirpath = pathutil.join(self.path, subdir)
462 self.subdirs[subdir] = dirnode(subdirpath)
464 self.subdirs[subdir] = dirnode(subdirpath)
463
465
464 # try adding the file in subdir
466 # try adding the file in subdir
465 self.subdirs[subdir].addfile(filep, status)
467 self.subdirs[subdir].addfile(filep, status)
466
468
467 else:
469 else:
468 self._addfileindir(filename, status)
470 self._addfileindir(filename, status)
469
471
470 if status not in self.statuses:
472 if status not in self.statuses:
471 self.statuses.add(status)
473 self.statuses.add(status)
472
474
473 def iterfilepaths(self):
475 def iterfilepaths(self):
474 """Yield (status, path) for files directly under this directory."""
476 """Yield (status, path) for files directly under this directory."""
475 for f, st in self.files:
477 for f, st in self.files:
476 yield st, pathutil.join(self.path, f)
478 yield st, pathutil.join(self.path, f)
477
479
478 def tersewalk(self, terseargs):
480 def tersewalk(self, terseargs):
479 """
481 """
480 Yield (status, path) obtained by processing the status of this
482 Yield (status, path) obtained by processing the status of this
481 dirnode.
483 dirnode.
482
484
483 terseargs is the string of arguments passed by the user with `--terse`
485 terseargs is the string of arguments passed by the user with `--terse`
484 flag.
486 flag.
485
487
486 Following are the cases which can happen:
488 Following are the cases which can happen:
487
489
488 1) All the files in the directory (including all the files in its
490 1) All the files in the directory (including all the files in its
489 subdirectories) share the same status and the user has asked us to terse
491 subdirectories) share the same status and the user has asked us to terse
490 that status. -> yield (status, dirpath). dirpath will end in '/'.
492 that status. -> yield (status, dirpath). dirpath will end in '/'.
491
493
492 2) Otherwise, we do following:
494 2) Otherwise, we do following:
493
495
494 a) Yield (status, filepath) for all the files which are in this
496 a) Yield (status, filepath) for all the files which are in this
495 directory (only the ones in this directory, not the subdirs)
497 directory (only the ones in this directory, not the subdirs)
496
498
497 b) Recurse the function on all the subdirectories of this
499 b) Recurse the function on all the subdirectories of this
498 directory
500 directory
499 """
501 """
500
502
501 if len(self.statuses) == 1:
503 if len(self.statuses) == 1:
502 onlyst = self.statuses.pop()
504 onlyst = self.statuses.pop()
503
505
504 # Making sure we terse only when the status abbreviation is
506 # Making sure we terse only when the status abbreviation is
505 # passed as terse argument
507 # passed as terse argument
506 if onlyst in terseargs:
508 if onlyst in terseargs:
507 yield onlyst, self.path + '/'
509 yield onlyst, self.path + '/'
508 return
510 return
509
511
510 # add the files to status list
512 # add the files to status list
511 for st, fpath in self.iterfilepaths():
513 for st, fpath in self.iterfilepaths():
512 yield st, fpath
514 yield st, fpath
513
515
514 #recurse on the subdirs
516 #recurse on the subdirs
515 for dirobj in self.subdirs.values():
517 for dirobj in self.subdirs.values():
516 for st, fpath in dirobj.tersewalk(terseargs):
518 for st, fpath in dirobj.tersewalk(terseargs):
517 yield st, fpath
519 yield st, fpath
518
520
519 def tersedir(statuslist, terseargs):
521 def tersedir(statuslist, terseargs):
520 """
522 """
521 Terse the status if all the files in a directory shares the same status.
523 Terse the status if all the files in a directory shares the same status.
522
524
523 statuslist is scmutil.status() object which contains a list of files for
525 statuslist is scmutil.status() object which contains a list of files for
524 each status.
526 each status.
525 terseargs is string which is passed by the user as the argument to `--terse`
527 terseargs is string which is passed by the user as the argument to `--terse`
526 flag.
528 flag.
527
529
528 The function makes a tree of objects of dirnode class, and at each node it
530 The function makes a tree of objects of dirnode class, and at each node it
529 stores the information required to know whether we can terse a certain
531 stores the information required to know whether we can terse a certain
530 directory or not.
532 directory or not.
531 """
533 """
532 # the order matters here as that is used to produce final list
534 # the order matters here as that is used to produce final list
533 allst = ('m', 'a', 'r', 'd', 'u', 'i', 'c')
535 allst = ('m', 'a', 'r', 'd', 'u', 'i', 'c')
534
536
535 # checking the argument validity
537 # checking the argument validity
536 for s in pycompat.bytestr(terseargs):
538 for s in pycompat.bytestr(terseargs):
537 if s not in allst:
539 if s not in allst:
538 raise error.Abort(_("'%s' not recognized") % s)
540 raise error.Abort(_("'%s' not recognized") % s)
539
541
540 # creating a dirnode object for the root of the repo
542 # creating a dirnode object for the root of the repo
541 rootobj = dirnode('')
543 rootobj = dirnode('')
542 pstatus = ('modified', 'added', 'deleted', 'clean', 'unknown',
544 pstatus = ('modified', 'added', 'deleted', 'clean', 'unknown',
543 'ignored', 'removed')
545 'ignored', 'removed')
544
546
545 tersedict = {}
547 tersedict = {}
546 for attrname in pstatus:
548 for attrname in pstatus:
547 statuschar = attrname[0:1]
549 statuschar = attrname[0:1]
548 for f in getattr(statuslist, attrname):
550 for f in getattr(statuslist, attrname):
549 rootobj.addfile(f, statuschar)
551 rootobj.addfile(f, statuschar)
550 tersedict[statuschar] = []
552 tersedict[statuschar] = []
551
553
552 # we won't be tersing the root dir, so add files in it
554 # we won't be tersing the root dir, so add files in it
553 for st, fpath in rootobj.iterfilepaths():
555 for st, fpath in rootobj.iterfilepaths():
554 tersedict[st].append(fpath)
556 tersedict[st].append(fpath)
555
557
556 # process each sub-directory and build tersedict
558 # process each sub-directory and build tersedict
557 for subdir in rootobj.subdirs.values():
559 for subdir in rootobj.subdirs.values():
558 for st, f in subdir.tersewalk(terseargs):
560 for st, f in subdir.tersewalk(terseargs):
559 tersedict[st].append(f)
561 tersedict[st].append(f)
560
562
561 tersedlist = []
563 tersedlist = []
562 for st in allst:
564 for st in allst:
563 tersedict[st].sort()
565 tersedict[st].sort()
564 tersedlist.append(tersedict[st])
566 tersedlist.append(tersedict[st])
565
567
566 return tersedlist
568 return tersedlist
567
569
568 def _commentlines(raw):
570 def _commentlines(raw):
569 '''Surround lineswith a comment char and a new line'''
571 '''Surround lineswith a comment char and a new line'''
570 lines = raw.splitlines()
572 lines = raw.splitlines()
571 commentedlines = ['# %s' % line for line in lines]
573 commentedlines = ['# %s' % line for line in lines]
572 return '\n'.join(commentedlines) + '\n'
574 return '\n'.join(commentedlines) + '\n'
573
575
574 def _conflictsmsg(repo):
576 def _conflictsmsg(repo):
575 mergestate = mergemod.mergestate.read(repo)
577 mergestate = mergemod.mergestate.read(repo)
576 if not mergestate.active():
578 if not mergestate.active():
577 return
579 return
578
580
579 m = scmutil.match(repo[None])
581 m = scmutil.match(repo[None])
580 unresolvedlist = [f for f in mergestate.unresolved() if m(f)]
582 unresolvedlist = [f for f in mergestate.unresolved() if m(f)]
581 if unresolvedlist:
583 if unresolvedlist:
582 mergeliststr = '\n'.join(
584 mergeliststr = '\n'.join(
583 [' %s' % util.pathto(repo.root, encoding.getcwd(), path)
585 [' %s' % util.pathto(repo.root, encoding.getcwd(), path)
584 for path in sorted(unresolvedlist)])
586 for path in sorted(unresolvedlist)])
585 msg = _('''Unresolved merge conflicts:
587 msg = _('''Unresolved merge conflicts:
586
588
587 %s
589 %s
588
590
589 To mark files as resolved: hg resolve --mark FILE''') % mergeliststr
591 To mark files as resolved: hg resolve --mark FILE''') % mergeliststr
590 else:
592 else:
591 msg = _('No unresolved merge conflicts.')
593 msg = _('No unresolved merge conflicts.')
592
594
593 return _commentlines(msg)
595 return _commentlines(msg)
594
596
595 def _helpmessage(continuecmd, abortcmd):
597 def _helpmessage(continuecmd, abortcmd):
596 msg = _('To continue: %s\n'
598 msg = _('To continue: %s\n'
597 'To abort: %s') % (continuecmd, abortcmd)
599 'To abort: %s') % (continuecmd, abortcmd)
598 return _commentlines(msg)
600 return _commentlines(msg)
599
601
600 def _rebasemsg():
602 def _rebasemsg():
601 return _helpmessage('hg rebase --continue', 'hg rebase --abort')
603 return _helpmessage('hg rebase --continue', 'hg rebase --abort')
602
604
603 def _histeditmsg():
605 def _histeditmsg():
604 return _helpmessage('hg histedit --continue', 'hg histedit --abort')
606 return _helpmessage('hg histedit --continue', 'hg histedit --abort')
605
607
606 def _unshelvemsg():
608 def _unshelvemsg():
607 return _helpmessage('hg unshelve --continue', 'hg unshelve --abort')
609 return _helpmessage('hg unshelve --continue', 'hg unshelve --abort')
608
610
609 def _graftmsg():
611 def _graftmsg():
610 return _helpmessage('hg graft --continue', 'hg graft --abort')
612 return _helpmessage('hg graft --continue', 'hg graft --abort')
611
613
612 def _mergemsg():
614 def _mergemsg():
613 return _helpmessage('hg commit', 'hg merge --abort')
615 return _helpmessage('hg commit', 'hg merge --abort')
614
616
615 def _bisectmsg():
617 def _bisectmsg():
616 msg = _('To mark the changeset good: hg bisect --good\n'
618 msg = _('To mark the changeset good: hg bisect --good\n'
617 'To mark the changeset bad: hg bisect --bad\n'
619 'To mark the changeset bad: hg bisect --bad\n'
618 'To abort: hg bisect --reset\n')
620 'To abort: hg bisect --reset\n')
619 return _commentlines(msg)
621 return _commentlines(msg)
620
622
621 def fileexistspredicate(filename):
623 def fileexistspredicate(filename):
622 return lambda repo: repo.vfs.exists(filename)
624 return lambda repo: repo.vfs.exists(filename)
623
625
624 def _mergepredicate(repo):
626 def _mergepredicate(repo):
625 return len(repo[None].parents()) > 1
627 return len(repo[None].parents()) > 1
626
628
627 STATES = (
629 STATES = (
628 # (state, predicate to detect states, helpful message function)
630 # (state, predicate to detect states, helpful message function)
629 ('histedit', fileexistspredicate('histedit-state'), _histeditmsg),
631 ('histedit', fileexistspredicate('histedit-state'), _histeditmsg),
630 ('bisect', fileexistspredicate('bisect.state'), _bisectmsg),
632 ('bisect', fileexistspredicate('bisect.state'), _bisectmsg),
631 ('graft', fileexistspredicate('graftstate'), _graftmsg),
633 ('graft', fileexistspredicate('graftstate'), _graftmsg),
632 ('unshelve', fileexistspredicate('shelvedstate'), _unshelvemsg),
634 ('unshelve', fileexistspredicate('shelvedstate'), _unshelvemsg),
633 ('rebase', fileexistspredicate('rebasestate'), _rebasemsg),
635 ('rebase', fileexistspredicate('rebasestate'), _rebasemsg),
634 # The merge state is part of a list that will be iterated over.
636 # The merge state is part of a list that will be iterated over.
635 # They need to be last because some of the other unfinished states may also
637 # They need to be last because some of the other unfinished states may also
636 # be in a merge or update state (eg. rebase, histedit, graft, etc).
638 # be in a merge or update state (eg. rebase, histedit, graft, etc).
637 # We want those to have priority.
639 # We want those to have priority.
638 ('merge', _mergepredicate, _mergemsg),
640 ('merge', _mergepredicate, _mergemsg),
639 )
641 )
640
642
641 def _getrepostate(repo):
643 def _getrepostate(repo):
642 # experimental config: commands.status.skipstates
644 # experimental config: commands.status.skipstates
643 skip = set(repo.ui.configlist('commands', 'status.skipstates'))
645 skip = set(repo.ui.configlist('commands', 'status.skipstates'))
644 for state, statedetectionpredicate, msgfn in STATES:
646 for state, statedetectionpredicate, msgfn in STATES:
645 if state in skip:
647 if state in skip:
646 continue
648 continue
647 if statedetectionpredicate(repo):
649 if statedetectionpredicate(repo):
648 return (state, statedetectionpredicate, msgfn)
650 return (state, statedetectionpredicate, msgfn)
649
651
650 def morestatus(repo, fm):
652 def morestatus(repo, fm):
651 statetuple = _getrepostate(repo)
653 statetuple = _getrepostate(repo)
652 label = 'status.morestatus'
654 label = 'status.morestatus'
653 if statetuple:
655 if statetuple:
654 state, statedetectionpredicate, helpfulmsg = statetuple
656 state, statedetectionpredicate, helpfulmsg = statetuple
655 statemsg = _('The repository is in an unfinished *%s* state.') % state
657 statemsg = _('The repository is in an unfinished *%s* state.') % state
656 fm.plain('%s\n' % _commentlines(statemsg), label=label)
658 fm.plain('%s\n' % _commentlines(statemsg), label=label)
657 conmsg = _conflictsmsg(repo)
659 conmsg = _conflictsmsg(repo)
658 if conmsg:
660 if conmsg:
659 fm.plain('%s\n' % conmsg, label=label)
661 fm.plain('%s\n' % conmsg, label=label)
660 if helpfulmsg:
662 if helpfulmsg:
661 helpmsg = helpfulmsg()
663 helpmsg = helpfulmsg()
662 fm.plain('%s\n' % helpmsg, label=label)
664 fm.plain('%s\n' % helpmsg, label=label)
663
665
664 def findpossible(cmd, table, strict=False):
666 def findpossible(cmd, table, strict=False):
665 """
667 """
666 Return cmd -> (aliases, command table entry)
668 Return cmd -> (aliases, command table entry)
667 for each matching command.
669 for each matching command.
668 Return debug commands (or their aliases) only if no normal command matches.
670 Return debug commands (or their aliases) only if no normal command matches.
669 """
671 """
670 choice = {}
672 choice = {}
671 debugchoice = {}
673 debugchoice = {}
672
674
673 if cmd in table:
675 if cmd in table:
674 # short-circuit exact matches, "log" alias beats "log|history"
676 # short-circuit exact matches, "log" alias beats "log|history"
675 keys = [cmd]
677 keys = [cmd]
676 else:
678 else:
677 keys = table.keys()
679 keys = table.keys()
678
680
679 allcmds = []
681 allcmds = []
680 for e in keys:
682 for e in keys:
681 aliases = parsealiases(e)
683 aliases = parsealiases(e)
682 allcmds.extend(aliases)
684 allcmds.extend(aliases)
683 found = None
685 found = None
684 if cmd in aliases:
686 if cmd in aliases:
685 found = cmd
687 found = cmd
686 elif not strict:
688 elif not strict:
687 for a in aliases:
689 for a in aliases:
688 if a.startswith(cmd):
690 if a.startswith(cmd):
689 found = a
691 found = a
690 break
692 break
691 if found is not None:
693 if found is not None:
692 if aliases[0].startswith("debug") or found.startswith("debug"):
694 if aliases[0].startswith("debug") or found.startswith("debug"):
693 debugchoice[found] = (aliases, table[e])
695 debugchoice[found] = (aliases, table[e])
694 else:
696 else:
695 choice[found] = (aliases, table[e])
697 choice[found] = (aliases, table[e])
696
698
697 if not choice and debugchoice:
699 if not choice and debugchoice:
698 choice = debugchoice
700 choice = debugchoice
699
701
700 return choice, allcmds
702 return choice, allcmds
701
703
702 def findcmd(cmd, table, strict=True):
704 def findcmd(cmd, table, strict=True):
703 """Return (aliases, command table entry) for command string."""
705 """Return (aliases, command table entry) for command string."""
704 choice, allcmds = findpossible(cmd, table, strict)
706 choice, allcmds = findpossible(cmd, table, strict)
705
707
706 if cmd in choice:
708 if cmd in choice:
707 return choice[cmd]
709 return choice[cmd]
708
710
709 if len(choice) > 1:
711 if len(choice) > 1:
710 clist = sorted(choice)
712 clist = sorted(choice)
711 raise error.AmbiguousCommand(cmd, clist)
713 raise error.AmbiguousCommand(cmd, clist)
712
714
713 if choice:
715 if choice:
714 return list(choice.values())[0]
716 return list(choice.values())[0]
715
717
716 raise error.UnknownCommand(cmd, allcmds)
718 raise error.UnknownCommand(cmd, allcmds)
717
719
718 def changebranch(ui, repo, revs, label):
720 def changebranch(ui, repo, revs, label):
719 """ Change the branch name of given revs to label """
721 """ Change the branch name of given revs to label """
720
722
721 with repo.wlock(), repo.lock(), repo.transaction('branches'):
723 with repo.wlock(), repo.lock(), repo.transaction('branches'):
722 # abort in case of uncommitted merge or dirty wdir
724 # abort in case of uncommitted merge or dirty wdir
723 bailifchanged(repo)
725 bailifchanged(repo)
724 revs = scmutil.revrange(repo, revs)
726 revs = scmutil.revrange(repo, revs)
725 if not revs:
727 if not revs:
726 raise error.Abort("empty revision set")
728 raise error.Abort("empty revision set")
727 roots = repo.revs('roots(%ld)', revs)
729 roots = repo.revs('roots(%ld)', revs)
728 if len(roots) > 1:
730 if len(roots) > 1:
729 raise error.Abort(_("cannot change branch of non-linear revisions"))
731 raise error.Abort(_("cannot change branch of non-linear revisions"))
730 rewriteutil.precheck(repo, revs, 'change branch of')
732 rewriteutil.precheck(repo, revs, 'change branch of')
731
733
732 root = repo[roots.first()]
734 root = repo[roots.first()]
733 rpb = {parent.branch() for parent in root.parents()}
735 rpb = {parent.branch() for parent in root.parents()}
734 if label not in rpb and label in repo.branchmap():
736 if label not in rpb and label in repo.branchmap():
735 raise error.Abort(_("a branch of the same name already exists"))
737 raise error.Abort(_("a branch of the same name already exists"))
736
738
737 if repo.revs('obsolete() and %ld', revs):
739 if repo.revs('obsolete() and %ld', revs):
738 raise error.Abort(_("cannot change branch of a obsolete changeset"))
740 raise error.Abort(_("cannot change branch of a obsolete changeset"))
739
741
740 # make sure only topological heads
742 # make sure only topological heads
741 if repo.revs('heads(%ld) - head()', revs):
743 if repo.revs('heads(%ld) - head()', revs):
742 raise error.Abort(_("cannot change branch in middle of a stack"))
744 raise error.Abort(_("cannot change branch in middle of a stack"))
743
745
744 replacements = {}
746 replacements = {}
745 # avoid import cycle mercurial.cmdutil -> mercurial.context ->
747 # avoid import cycle mercurial.cmdutil -> mercurial.context ->
746 # mercurial.subrepo -> mercurial.cmdutil
748 # mercurial.subrepo -> mercurial.cmdutil
747 from . import context
749 from . import context
748 for rev in revs:
750 for rev in revs:
749 ctx = repo[rev]
751 ctx = repo[rev]
750 oldbranch = ctx.branch()
752 oldbranch = ctx.branch()
751 # check if ctx has same branch
753 # check if ctx has same branch
752 if oldbranch == label:
754 if oldbranch == label:
753 continue
755 continue
754
756
755 def filectxfn(repo, newctx, path):
757 def filectxfn(repo, newctx, path):
756 try:
758 try:
757 return ctx[path]
759 return ctx[path]
758 except error.ManifestLookupError:
760 except error.ManifestLookupError:
759 return None
761 return None
760
762
761 ui.debug("changing branch of '%s' from '%s' to '%s'\n"
763 ui.debug("changing branch of '%s' from '%s' to '%s'\n"
762 % (hex(ctx.node()), oldbranch, label))
764 % (hex(ctx.node()), oldbranch, label))
763 extra = ctx.extra()
765 extra = ctx.extra()
764 extra['branch_change'] = hex(ctx.node())
766 extra['branch_change'] = hex(ctx.node())
765 # While changing branch of set of linear commits, make sure that
767 # While changing branch of set of linear commits, make sure that
766 # we base our commits on new parent rather than old parent which
768 # we base our commits on new parent rather than old parent which
767 # was obsoleted while changing the branch
769 # was obsoleted while changing the branch
768 p1 = ctx.p1().node()
770 p1 = ctx.p1().node()
769 p2 = ctx.p2().node()
771 p2 = ctx.p2().node()
770 if p1 in replacements:
772 if p1 in replacements:
771 p1 = replacements[p1][0]
773 p1 = replacements[p1][0]
772 if p2 in replacements:
774 if p2 in replacements:
773 p2 = replacements[p2][0]
775 p2 = replacements[p2][0]
774
776
775 mc = context.memctx(repo, (p1, p2),
777 mc = context.memctx(repo, (p1, p2),
776 ctx.description(),
778 ctx.description(),
777 ctx.files(),
779 ctx.files(),
778 filectxfn,
780 filectxfn,
779 user=ctx.user(),
781 user=ctx.user(),
780 date=ctx.date(),
782 date=ctx.date(),
781 extra=extra,
783 extra=extra,
782 branch=label)
784 branch=label)
783
785
784 newnode = repo.commitctx(mc)
786 newnode = repo.commitctx(mc)
785 replacements[ctx.node()] = (newnode,)
787 replacements[ctx.node()] = (newnode,)
786 ui.debug('new node id is %s\n' % hex(newnode))
788 ui.debug('new node id is %s\n' % hex(newnode))
787
789
788 # create obsmarkers and move bookmarks
790 # create obsmarkers and move bookmarks
789 scmutil.cleanupnodes(repo, replacements, 'branch-change', fixphase=True)
791 scmutil.cleanupnodes(repo, replacements, 'branch-change', fixphase=True)
790
792
791 # move the working copy too
793 # move the working copy too
792 wctx = repo[None]
794 wctx = repo[None]
793 # in-progress merge is a bit too complex for now.
795 # in-progress merge is a bit too complex for now.
794 if len(wctx.parents()) == 1:
796 if len(wctx.parents()) == 1:
795 newid = replacements.get(wctx.p1().node())
797 newid = replacements.get(wctx.p1().node())
796 if newid is not None:
798 if newid is not None:
797 # avoid import cycle mercurial.cmdutil -> mercurial.hg ->
799 # avoid import cycle mercurial.cmdutil -> mercurial.hg ->
798 # mercurial.cmdutil
800 # mercurial.cmdutil
799 from . import hg
801 from . import hg
800 hg.update(repo, newid[0], quietempty=True)
802 hg.update(repo, newid[0], quietempty=True)
801
803
802 ui.status(_("changed branch on %d changesets\n") % len(replacements))
804 ui.status(_("changed branch on %d changesets\n") % len(replacements))
803
805
804 def findrepo(p):
806 def findrepo(p):
805 while not os.path.isdir(os.path.join(p, ".hg")):
807 while not os.path.isdir(os.path.join(p, ".hg")):
806 oldp, p = p, os.path.dirname(p)
808 oldp, p = p, os.path.dirname(p)
807 if p == oldp:
809 if p == oldp:
808 return None
810 return None
809
811
810 return p
812 return p
811
813
812 def bailifchanged(repo, merge=True, hint=None):
814 def bailifchanged(repo, merge=True, hint=None):
813 """ enforce the precondition that working directory must be clean.
815 """ enforce the precondition that working directory must be clean.
814
816
815 'merge' can be set to false if a pending uncommitted merge should be
817 'merge' can be set to false if a pending uncommitted merge should be
816 ignored (such as when 'update --check' runs).
818 ignored (such as when 'update --check' runs).
817
819
818 'hint' is the usual hint given to Abort exception.
820 'hint' is the usual hint given to Abort exception.
819 """
821 """
820
822
821 if merge and repo.dirstate.p2() != nullid:
823 if merge and repo.dirstate.p2() != nullid:
822 raise error.Abort(_('outstanding uncommitted merge'), hint=hint)
824 raise error.Abort(_('outstanding uncommitted merge'), hint=hint)
823 modified, added, removed, deleted = repo.status()[:4]
825 modified, added, removed, deleted = repo.status()[:4]
824 if modified or added or removed or deleted:
826 if modified or added or removed or deleted:
825 raise error.Abort(_('uncommitted changes'), hint=hint)
827 raise error.Abort(_('uncommitted changes'), hint=hint)
826 ctx = repo[None]
828 ctx = repo[None]
827 for s in sorted(ctx.substate):
829 for s in sorted(ctx.substate):
828 ctx.sub(s).bailifchanged(hint=hint)
830 ctx.sub(s).bailifchanged(hint=hint)
829
831
830 def logmessage(ui, opts):
832 def logmessage(ui, opts):
831 """ get the log message according to -m and -l option """
833 """ get the log message according to -m and -l option """
832 message = opts.get('message')
834 message = opts.get('message')
833 logfile = opts.get('logfile')
835 logfile = opts.get('logfile')
834
836
835 if message and logfile:
837 if message and logfile:
836 raise error.Abort(_('options --message and --logfile are mutually '
838 raise error.Abort(_('options --message and --logfile are mutually '
837 'exclusive'))
839 'exclusive'))
838 if not message and logfile:
840 if not message and logfile:
839 try:
841 try:
840 if isstdiofilename(logfile):
842 if isstdiofilename(logfile):
841 message = ui.fin.read()
843 message = ui.fin.read()
842 else:
844 else:
843 message = '\n'.join(util.readfile(logfile).splitlines())
845 message = '\n'.join(util.readfile(logfile).splitlines())
844 except IOError as inst:
846 except IOError as inst:
845 raise error.Abort(_("can't read commit message '%s': %s") %
847 raise error.Abort(_("can't read commit message '%s': %s") %
846 (logfile, encoding.strtolocal(inst.strerror)))
848 (logfile, encoding.strtolocal(inst.strerror)))
847 return message
849 return message
848
850
849 def mergeeditform(ctxorbool, baseformname):
851 def mergeeditform(ctxorbool, baseformname):
850 """return appropriate editform name (referencing a committemplate)
852 """return appropriate editform name (referencing a committemplate)
851
853
852 'ctxorbool' is either a ctx to be committed, or a bool indicating whether
854 'ctxorbool' is either a ctx to be committed, or a bool indicating whether
853 merging is committed.
855 merging is committed.
854
856
855 This returns baseformname with '.merge' appended if it is a merge,
857 This returns baseformname with '.merge' appended if it is a merge,
856 otherwise '.normal' is appended.
858 otherwise '.normal' is appended.
857 """
859 """
858 if isinstance(ctxorbool, bool):
860 if isinstance(ctxorbool, bool):
859 if ctxorbool:
861 if ctxorbool:
860 return baseformname + ".merge"
862 return baseformname + ".merge"
861 elif len(ctxorbool.parents()) > 1:
863 elif len(ctxorbool.parents()) > 1:
862 return baseformname + ".merge"
864 return baseformname + ".merge"
863
865
864 return baseformname + ".normal"
866 return baseformname + ".normal"
865
867
866 def getcommiteditor(edit=False, finishdesc=None, extramsg=None,
868 def getcommiteditor(edit=False, finishdesc=None, extramsg=None,
867 editform='', **opts):
869 editform='', **opts):
868 """get appropriate commit message editor according to '--edit' option
870 """get appropriate commit message editor according to '--edit' option
869
871
870 'finishdesc' is a function to be called with edited commit message
872 'finishdesc' is a function to be called with edited commit message
871 (= 'description' of the new changeset) just after editing, but
873 (= 'description' of the new changeset) just after editing, but
872 before checking empty-ness. It should return actual text to be
874 before checking empty-ness. It should return actual text to be
873 stored into history. This allows to change description before
875 stored into history. This allows to change description before
874 storing.
876 storing.
875
877
876 'extramsg' is a extra message to be shown in the editor instead of
878 'extramsg' is a extra message to be shown in the editor instead of
877 'Leave message empty to abort commit' line. 'HG: ' prefix and EOL
879 'Leave message empty to abort commit' line. 'HG: ' prefix and EOL
878 is automatically added.
880 is automatically added.
879
881
880 'editform' is a dot-separated list of names, to distinguish
882 'editform' is a dot-separated list of names, to distinguish
881 the purpose of commit text editing.
883 the purpose of commit text editing.
882
884
883 'getcommiteditor' returns 'commitforceeditor' regardless of
885 'getcommiteditor' returns 'commitforceeditor' regardless of
884 'edit', if one of 'finishdesc' or 'extramsg' is specified, because
886 'edit', if one of 'finishdesc' or 'extramsg' is specified, because
885 they are specific for usage in MQ.
887 they are specific for usage in MQ.
886 """
888 """
887 if edit or finishdesc or extramsg:
889 if edit or finishdesc or extramsg:
888 return lambda r, c, s: commitforceeditor(r, c, s,
890 return lambda r, c, s: commitforceeditor(r, c, s,
889 finishdesc=finishdesc,
891 finishdesc=finishdesc,
890 extramsg=extramsg,
892 extramsg=extramsg,
891 editform=editform)
893 editform=editform)
892 elif editform:
894 elif editform:
893 return lambda r, c, s: commiteditor(r, c, s, editform=editform)
895 return lambda r, c, s: commiteditor(r, c, s, editform=editform)
894 else:
896 else:
895 return commiteditor
897 return commiteditor
896
898
897 def _escapecommandtemplate(tmpl):
899 def _escapecommandtemplate(tmpl):
898 parts = []
900 parts = []
899 for typ, start, end in templater.scantemplate(tmpl, raw=True):
901 for typ, start, end in templater.scantemplate(tmpl, raw=True):
900 if typ == b'string':
902 if typ == b'string':
901 parts.append(stringutil.escapestr(tmpl[start:end]))
903 parts.append(stringutil.escapestr(tmpl[start:end]))
902 else:
904 else:
903 parts.append(tmpl[start:end])
905 parts.append(tmpl[start:end])
904 return b''.join(parts)
906 return b''.join(parts)
905
907
906 def rendercommandtemplate(ui, tmpl, props):
908 def rendercommandtemplate(ui, tmpl, props):
907 r"""Expand a literal template 'tmpl' in a way suitable for command line
909 r"""Expand a literal template 'tmpl' in a way suitable for command line
908
910
909 '\' in outermost string is not taken as an escape character because it
911 '\' in outermost string is not taken as an escape character because it
910 is a directory separator on Windows.
912 is a directory separator on Windows.
911
913
912 >>> from . import ui as uimod
914 >>> from . import ui as uimod
913 >>> ui = uimod.ui()
915 >>> ui = uimod.ui()
914 >>> rendercommandtemplate(ui, b'c:\\{path}', {b'path': b'foo'})
916 >>> rendercommandtemplate(ui, b'c:\\{path}', {b'path': b'foo'})
915 'c:\\foo'
917 'c:\\foo'
916 >>> rendercommandtemplate(ui, b'{"c:\\{path}"}', {'path': b'foo'})
918 >>> rendercommandtemplate(ui, b'{"c:\\{path}"}', {'path': b'foo'})
917 'c:{path}'
919 'c:{path}'
918 """
920 """
919 if not tmpl:
921 if not tmpl:
920 return tmpl
922 return tmpl
921 t = formatter.maketemplater(ui, _escapecommandtemplate(tmpl))
923 t = formatter.maketemplater(ui, _escapecommandtemplate(tmpl))
922 return t.renderdefault(props)
924 return t.renderdefault(props)
923
925
924 def rendertemplate(ctx, tmpl, props=None):
926 def rendertemplate(ctx, tmpl, props=None):
925 """Expand a literal template 'tmpl' byte-string against one changeset
927 """Expand a literal template 'tmpl' byte-string against one changeset
926
928
927 Each props item must be a stringify-able value or a callable returning
929 Each props item must be a stringify-able value or a callable returning
928 such value, i.e. no bare list nor dict should be passed.
930 such value, i.e. no bare list nor dict should be passed.
929 """
931 """
930 repo = ctx.repo()
932 repo = ctx.repo()
931 tres = formatter.templateresources(repo.ui, repo)
933 tres = formatter.templateresources(repo.ui, repo)
932 t = formatter.maketemplater(repo.ui, tmpl, defaults=templatekw.keywords,
934 t = formatter.maketemplater(repo.ui, tmpl, defaults=templatekw.keywords,
933 resources=tres)
935 resources=tres)
934 mapping = {'ctx': ctx}
936 mapping = {'ctx': ctx}
935 if props:
937 if props:
936 mapping.update(props)
938 mapping.update(props)
937 return t.renderdefault(mapping)
939 return t.renderdefault(mapping)
938
940
939 def _buildfntemplate(pat, total=None, seqno=None, revwidth=None, pathname=None):
941 def _buildfntemplate(pat, total=None, seqno=None, revwidth=None, pathname=None):
940 r"""Convert old-style filename format string to template string
942 r"""Convert old-style filename format string to template string
941
943
942 >>> _buildfntemplate(b'foo-%b-%n.patch', seqno=0)
944 >>> _buildfntemplate(b'foo-%b-%n.patch', seqno=0)
943 'foo-{reporoot|basename}-{seqno}.patch'
945 'foo-{reporoot|basename}-{seqno}.patch'
944 >>> _buildfntemplate(b'%R{tags % "{tag}"}%H')
946 >>> _buildfntemplate(b'%R{tags % "{tag}"}%H')
945 '{rev}{tags % "{tag}"}{node}'
947 '{rev}{tags % "{tag}"}{node}'
946
948
947 '\' in outermost strings has to be escaped because it is a directory
949 '\' in outermost strings has to be escaped because it is a directory
948 separator on Windows:
950 separator on Windows:
949
951
950 >>> _buildfntemplate(b'c:\\tmp\\%R\\%n.patch', seqno=0)
952 >>> _buildfntemplate(b'c:\\tmp\\%R\\%n.patch', seqno=0)
951 'c:\\\\tmp\\\\{rev}\\\\{seqno}.patch'
953 'c:\\\\tmp\\\\{rev}\\\\{seqno}.patch'
952 >>> _buildfntemplate(b'\\\\foo\\bar.patch')
954 >>> _buildfntemplate(b'\\\\foo\\bar.patch')
953 '\\\\\\\\foo\\\\bar.patch'
955 '\\\\\\\\foo\\\\bar.patch'
954 >>> _buildfntemplate(b'\\{tags % "{tag}"}')
956 >>> _buildfntemplate(b'\\{tags % "{tag}"}')
955 '\\\\{tags % "{tag}"}'
957 '\\\\{tags % "{tag}"}'
956
958
957 but inner strings follow the template rules (i.e. '\' is taken as an
959 but inner strings follow the template rules (i.e. '\' is taken as an
958 escape character):
960 escape character):
959
961
960 >>> _buildfntemplate(br'{"c:\tmp"}', seqno=0)
962 >>> _buildfntemplate(br'{"c:\tmp"}', seqno=0)
961 '{"c:\\tmp"}'
963 '{"c:\\tmp"}'
962 """
964 """
963 expander = {
965 expander = {
964 b'H': b'{node}',
966 b'H': b'{node}',
965 b'R': b'{rev}',
967 b'R': b'{rev}',
966 b'h': b'{node|short}',
968 b'h': b'{node|short}',
967 b'm': br'{sub(r"[^\w]", "_", desc|firstline)}',
969 b'm': br'{sub(r"[^\w]", "_", desc|firstline)}',
968 b'r': b'{if(revwidth, pad(rev, revwidth, "0", left=True), rev)}',
970 b'r': b'{if(revwidth, pad(rev, revwidth, "0", left=True), rev)}',
969 b'%': b'%',
971 b'%': b'%',
970 b'b': b'{reporoot|basename}',
972 b'b': b'{reporoot|basename}',
971 }
973 }
972 if total is not None:
974 if total is not None:
973 expander[b'N'] = b'{total}'
975 expander[b'N'] = b'{total}'
974 if seqno is not None:
976 if seqno is not None:
975 expander[b'n'] = b'{seqno}'
977 expander[b'n'] = b'{seqno}'
976 if total is not None and seqno is not None:
978 if total is not None and seqno is not None:
977 expander[b'n'] = b'{pad(seqno, total|stringify|count, "0", left=True)}'
979 expander[b'n'] = b'{pad(seqno, total|stringify|count, "0", left=True)}'
978 if pathname is not None:
980 if pathname is not None:
979 expander[b's'] = b'{pathname|basename}'
981 expander[b's'] = b'{pathname|basename}'
980 expander[b'd'] = b'{if(pathname|dirname, pathname|dirname, ".")}'
982 expander[b'd'] = b'{if(pathname|dirname, pathname|dirname, ".")}'
981 expander[b'p'] = b'{pathname}'
983 expander[b'p'] = b'{pathname}'
982
984
983 newname = []
985 newname = []
984 for typ, start, end in templater.scantemplate(pat, raw=True):
986 for typ, start, end in templater.scantemplate(pat, raw=True):
985 if typ != b'string':
987 if typ != b'string':
986 newname.append(pat[start:end])
988 newname.append(pat[start:end])
987 continue
989 continue
988 i = start
990 i = start
989 while i < end:
991 while i < end:
990 n = pat.find(b'%', i, end)
992 n = pat.find(b'%', i, end)
991 if n < 0:
993 if n < 0:
992 newname.append(stringutil.escapestr(pat[i:end]))
994 newname.append(stringutil.escapestr(pat[i:end]))
993 break
995 break
994 newname.append(stringutil.escapestr(pat[i:n]))
996 newname.append(stringutil.escapestr(pat[i:n]))
995 if n + 2 > end:
997 if n + 2 > end:
996 raise error.Abort(_("incomplete format spec in output "
998 raise error.Abort(_("incomplete format spec in output "
997 "filename"))
999 "filename"))
998 c = pat[n + 1:n + 2]
1000 c = pat[n + 1:n + 2]
999 i = n + 2
1001 i = n + 2
1000 try:
1002 try:
1001 newname.append(expander[c])
1003 newname.append(expander[c])
1002 except KeyError:
1004 except KeyError:
1003 raise error.Abort(_("invalid format spec '%%%s' in output "
1005 raise error.Abort(_("invalid format spec '%%%s' in output "
1004 "filename") % c)
1006 "filename") % c)
1005 return ''.join(newname)
1007 return ''.join(newname)
1006
1008
1007 def makefilename(ctx, pat, **props):
1009 def makefilename(ctx, pat, **props):
1008 if not pat:
1010 if not pat:
1009 return pat
1011 return pat
1010 tmpl = _buildfntemplate(pat, **props)
1012 tmpl = _buildfntemplate(pat, **props)
1011 # BUG: alias expansion shouldn't be made against template fragments
1013 # BUG: alias expansion shouldn't be made against template fragments
1012 # rewritten from %-format strings, but we have no easy way to partially
1014 # rewritten from %-format strings, but we have no easy way to partially
1013 # disable the expansion.
1015 # disable the expansion.
1014 return rendertemplate(ctx, tmpl, pycompat.byteskwargs(props))
1016 return rendertemplate(ctx, tmpl, pycompat.byteskwargs(props))
1015
1017
1016 def isstdiofilename(pat):
1018 def isstdiofilename(pat):
1017 """True if the given pat looks like a filename denoting stdin/stdout"""
1019 """True if the given pat looks like a filename denoting stdin/stdout"""
1018 return not pat or pat == '-'
1020 return not pat or pat == '-'
1019
1021
1020 class _unclosablefile(object):
1022 class _unclosablefile(object):
1021 def __init__(self, fp):
1023 def __init__(self, fp):
1022 self._fp = fp
1024 self._fp = fp
1023
1025
1024 def close(self):
1026 def close(self):
1025 pass
1027 pass
1026
1028
1027 def __iter__(self):
1029 def __iter__(self):
1028 return iter(self._fp)
1030 return iter(self._fp)
1029
1031
1030 def __getattr__(self, attr):
1032 def __getattr__(self, attr):
1031 return getattr(self._fp, attr)
1033 return getattr(self._fp, attr)
1032
1034
1033 def __enter__(self):
1035 def __enter__(self):
1034 return self
1036 return self
1035
1037
1036 def __exit__(self, exc_type, exc_value, exc_tb):
1038 def __exit__(self, exc_type, exc_value, exc_tb):
1037 pass
1039 pass
1038
1040
1039 def makefileobj(ctx, pat, mode='wb', **props):
1041 def makefileobj(ctx, pat, mode='wb', **props):
1040 writable = mode not in ('r', 'rb')
1042 writable = mode not in ('r', 'rb')
1041
1043
1042 if isstdiofilename(pat):
1044 if isstdiofilename(pat):
1043 repo = ctx.repo()
1045 repo = ctx.repo()
1044 if writable:
1046 if writable:
1045 fp = repo.ui.fout
1047 fp = repo.ui.fout
1046 else:
1048 else:
1047 fp = repo.ui.fin
1049 fp = repo.ui.fin
1048 return _unclosablefile(fp)
1050 return _unclosablefile(fp)
1049 fn = makefilename(ctx, pat, **props)
1051 fn = makefilename(ctx, pat, **props)
1050 return open(fn, mode)
1052 return open(fn, mode)
1051
1053
1052 def openstorage(repo, cmd, file_, opts, returnrevlog=False):
1054 def openstorage(repo, cmd, file_, opts, returnrevlog=False):
1053 """opens the changelog, manifest, a filelog or a given revlog"""
1055 """opens the changelog, manifest, a filelog or a given revlog"""
1054 cl = opts['changelog']
1056 cl = opts['changelog']
1055 mf = opts['manifest']
1057 mf = opts['manifest']
1056 dir = opts['dir']
1058 dir = opts['dir']
1057 msg = None
1059 msg = None
1058 if cl and mf:
1060 if cl and mf:
1059 msg = _('cannot specify --changelog and --manifest at the same time')
1061 msg = _('cannot specify --changelog and --manifest at the same time')
1060 elif cl and dir:
1062 elif cl and dir:
1061 msg = _('cannot specify --changelog and --dir at the same time')
1063 msg = _('cannot specify --changelog and --dir at the same time')
1062 elif cl or mf or dir:
1064 elif cl or mf or dir:
1063 if file_:
1065 if file_:
1064 msg = _('cannot specify filename with --changelog or --manifest')
1066 msg = _('cannot specify filename with --changelog or --manifest')
1065 elif not repo:
1067 elif not repo:
1066 msg = _('cannot specify --changelog or --manifest or --dir '
1068 msg = _('cannot specify --changelog or --manifest or --dir '
1067 'without a repository')
1069 'without a repository')
1068 if msg:
1070 if msg:
1069 raise error.Abort(msg)
1071 raise error.Abort(msg)
1070
1072
1071 r = None
1073 r = None
1072 if repo:
1074 if repo:
1073 if cl:
1075 if cl:
1074 r = repo.unfiltered().changelog
1076 r = repo.unfiltered().changelog
1075 elif dir:
1077 elif dir:
1076 if 'treemanifest' not in repo.requirements:
1078 if 'treemanifest' not in repo.requirements:
1077 raise error.Abort(_("--dir can only be used on repos with "
1079 raise error.Abort(_("--dir can only be used on repos with "
1078 "treemanifest enabled"))
1080 "treemanifest enabled"))
1079 if not dir.endswith('/'):
1081 if not dir.endswith('/'):
1080 dir = dir + '/'
1082 dir = dir + '/'
1081 dirlog = repo.manifestlog.getstorage(dir)
1083 dirlog = repo.manifestlog.getstorage(dir)
1082 if len(dirlog):
1084 if len(dirlog):
1083 r = dirlog
1085 r = dirlog
1084 elif mf:
1086 elif mf:
1085 r = repo.manifestlog.getstorage(b'')
1087 r = repo.manifestlog.getstorage(b'')
1086 elif file_:
1088 elif file_:
1087 filelog = repo.file(file_)
1089 filelog = repo.file(file_)
1088 if len(filelog):
1090 if len(filelog):
1089 r = filelog
1091 r = filelog
1090
1092
1091 # Not all storage may be revlogs. If requested, try to return an actual
1093 # Not all storage may be revlogs. If requested, try to return an actual
1092 # revlog instance.
1094 # revlog instance.
1093 if returnrevlog:
1095 if returnrevlog:
1094 if isinstance(r, revlog.revlog):
1096 if isinstance(r, revlog.revlog):
1095 pass
1097 pass
1096 elif util.safehasattr(r, '_revlog'):
1098 elif util.safehasattr(r, '_revlog'):
1097 r = r._revlog
1099 r = r._revlog
1098 elif r is not None:
1100 elif r is not None:
1099 raise error.Abort(_('%r does not appear to be a revlog') % r)
1101 raise error.Abort(_('%r does not appear to be a revlog') % r)
1100
1102
1101 if not r:
1103 if not r:
1102 if not returnrevlog:
1104 if not returnrevlog:
1103 raise error.Abort(_('cannot give path to non-revlog'))
1105 raise error.Abort(_('cannot give path to non-revlog'))
1104
1106
1105 if not file_:
1107 if not file_:
1106 raise error.CommandError(cmd, _('invalid arguments'))
1108 raise error.CommandError(cmd, _('invalid arguments'))
1107 if not os.path.isfile(file_):
1109 if not os.path.isfile(file_):
1108 raise error.Abort(_("revlog '%s' not found") % file_)
1110 raise error.Abort(_("revlog '%s' not found") % file_)
1109 r = revlog.revlog(vfsmod.vfs(encoding.getcwd(), audit=False),
1111 r = revlog.revlog(vfsmod.vfs(encoding.getcwd(), audit=False),
1110 file_[:-2] + ".i")
1112 file_[:-2] + ".i")
1111 return r
1113 return r
1112
1114
1113 def openrevlog(repo, cmd, file_, opts):
1115 def openrevlog(repo, cmd, file_, opts):
1114 """Obtain a revlog backing storage of an item.
1116 """Obtain a revlog backing storage of an item.
1115
1117
1116 This is similar to ``openstorage()`` except it always returns a revlog.
1118 This is similar to ``openstorage()`` except it always returns a revlog.
1117
1119
1118 In most cases, a caller cares about the main storage object - not the
1120 In most cases, a caller cares about the main storage object - not the
1119 revlog backing it. Therefore, this function should only be used by code
1121 revlog backing it. Therefore, this function should only be used by code
1120 that needs to examine low-level revlog implementation details. e.g. debug
1122 that needs to examine low-level revlog implementation details. e.g. debug
1121 commands.
1123 commands.
1122 """
1124 """
1123 return openstorage(repo, cmd, file_, opts, returnrevlog=True)
1125 return openstorage(repo, cmd, file_, opts, returnrevlog=True)
1124
1126
1125 def copy(ui, repo, pats, opts, rename=False):
1127 def copy(ui, repo, pats, opts, rename=False):
1126 # called with the repo lock held
1128 # called with the repo lock held
1127 #
1129 #
1128 # hgsep => pathname that uses "/" to separate directories
1130 # hgsep => pathname that uses "/" to separate directories
1129 # ossep => pathname that uses os.sep to separate directories
1131 # ossep => pathname that uses os.sep to separate directories
1130 cwd = repo.getcwd()
1132 cwd = repo.getcwd()
1131 targets = {}
1133 targets = {}
1132 after = opts.get("after")
1134 after = opts.get("after")
1133 dryrun = opts.get("dry_run")
1135 dryrun = opts.get("dry_run")
1134 wctx = repo[None]
1136 wctx = repo[None]
1135
1137
1136 def walkpat(pat):
1138 def walkpat(pat):
1137 srcs = []
1139 srcs = []
1138 if after:
1140 if after:
1139 badstates = '?'
1141 badstates = '?'
1140 else:
1142 else:
1141 badstates = '?r'
1143 badstates = '?r'
1142 m = scmutil.match(wctx, [pat], opts, globbed=True)
1144 m = scmutil.match(wctx, [pat], opts, globbed=True)
1143 for abs in wctx.walk(m):
1145 for abs in wctx.walk(m):
1144 state = repo.dirstate[abs]
1146 state = repo.dirstate[abs]
1145 rel = m.rel(abs)
1147 rel = m.rel(abs)
1146 exact = m.exact(abs)
1148 exact = m.exact(abs)
1147 if state in badstates:
1149 if state in badstates:
1148 if exact and state == '?':
1150 if exact and state == '?':
1149 ui.warn(_('%s: not copying - file is not managed\n') % rel)
1151 ui.warn(_('%s: not copying - file is not managed\n') % rel)
1150 if exact and state == 'r':
1152 if exact and state == 'r':
1151 ui.warn(_('%s: not copying - file has been marked for'
1153 ui.warn(_('%s: not copying - file has been marked for'
1152 ' remove\n') % rel)
1154 ' remove\n') % rel)
1153 continue
1155 continue
1154 # abs: hgsep
1156 # abs: hgsep
1155 # rel: ossep
1157 # rel: ossep
1156 srcs.append((abs, rel, exact))
1158 srcs.append((abs, rel, exact))
1157 return srcs
1159 return srcs
1158
1160
1159 # abssrc: hgsep
1161 # abssrc: hgsep
1160 # relsrc: ossep
1162 # relsrc: ossep
1161 # otarget: ossep
1163 # otarget: ossep
1162 def copyfile(abssrc, relsrc, otarget, exact):
1164 def copyfile(abssrc, relsrc, otarget, exact):
1163 abstarget = pathutil.canonpath(repo.root, cwd, otarget)
1165 abstarget = pathutil.canonpath(repo.root, cwd, otarget)
1164 if '/' in abstarget:
1166 if '/' in abstarget:
1165 # We cannot normalize abstarget itself, this would prevent
1167 # We cannot normalize abstarget itself, this would prevent
1166 # case only renames, like a => A.
1168 # case only renames, like a => A.
1167 abspath, absname = abstarget.rsplit('/', 1)
1169 abspath, absname = abstarget.rsplit('/', 1)
1168 abstarget = repo.dirstate.normalize(abspath) + '/' + absname
1170 abstarget = repo.dirstate.normalize(abspath) + '/' + absname
1169 reltarget = repo.pathto(abstarget, cwd)
1171 reltarget = repo.pathto(abstarget, cwd)
1170 target = repo.wjoin(abstarget)
1172 target = repo.wjoin(abstarget)
1171 src = repo.wjoin(abssrc)
1173 src = repo.wjoin(abssrc)
1172 state = repo.dirstate[abstarget]
1174 state = repo.dirstate[abstarget]
1173
1175
1174 scmutil.checkportable(ui, abstarget)
1176 scmutil.checkportable(ui, abstarget)
1175
1177
1176 # check for collisions
1178 # check for collisions
1177 prevsrc = targets.get(abstarget)
1179 prevsrc = targets.get(abstarget)
1178 if prevsrc is not None:
1180 if prevsrc is not None:
1179 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
1181 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
1180 (reltarget, repo.pathto(abssrc, cwd),
1182 (reltarget, repo.pathto(abssrc, cwd),
1181 repo.pathto(prevsrc, cwd)))
1183 repo.pathto(prevsrc, cwd)))
1182 return True # report a failure
1184 return True # report a failure
1183
1185
1184 # check for overwrites
1186 # check for overwrites
1185 exists = os.path.lexists(target)
1187 exists = os.path.lexists(target)
1186 samefile = False
1188 samefile = False
1187 if exists and abssrc != abstarget:
1189 if exists and abssrc != abstarget:
1188 if (repo.dirstate.normalize(abssrc) ==
1190 if (repo.dirstate.normalize(abssrc) ==
1189 repo.dirstate.normalize(abstarget)):
1191 repo.dirstate.normalize(abstarget)):
1190 if not rename:
1192 if not rename:
1191 ui.warn(_("%s: can't copy - same file\n") % reltarget)
1193 ui.warn(_("%s: can't copy - same file\n") % reltarget)
1192 return True # report a failure
1194 return True # report a failure
1193 exists = False
1195 exists = False
1194 samefile = True
1196 samefile = True
1195
1197
1196 if not after and exists or after and state in 'mn':
1198 if not after and exists or after and state in 'mn':
1197 if not opts['force']:
1199 if not opts['force']:
1198 if state in 'mn':
1200 if state in 'mn':
1199 msg = _('%s: not overwriting - file already committed\n')
1201 msg = _('%s: not overwriting - file already committed\n')
1200 if after:
1202 if after:
1201 flags = '--after --force'
1203 flags = '--after --force'
1202 else:
1204 else:
1203 flags = '--force'
1205 flags = '--force'
1204 if rename:
1206 if rename:
1205 hint = _("('hg rename %s' to replace the file by "
1207 hint = _("('hg rename %s' to replace the file by "
1206 'recording a rename)\n') % flags
1208 'recording a rename)\n') % flags
1207 else:
1209 else:
1208 hint = _("('hg copy %s' to replace the file by "
1210 hint = _("('hg copy %s' to replace the file by "
1209 'recording a copy)\n') % flags
1211 'recording a copy)\n') % flags
1210 else:
1212 else:
1211 msg = _('%s: not overwriting - file exists\n')
1213 msg = _('%s: not overwriting - file exists\n')
1212 if rename:
1214 if rename:
1213 hint = _("('hg rename --after' to record the rename)\n")
1215 hint = _("('hg rename --after' to record the rename)\n")
1214 else:
1216 else:
1215 hint = _("('hg copy --after' to record the copy)\n")
1217 hint = _("('hg copy --after' to record the copy)\n")
1216 ui.warn(msg % reltarget)
1218 ui.warn(msg % reltarget)
1217 ui.warn(hint)
1219 ui.warn(hint)
1218 return True # report a failure
1220 return True # report a failure
1219
1221
1220 if after:
1222 if after:
1221 if not exists:
1223 if not exists:
1222 if rename:
1224 if rename:
1223 ui.warn(_('%s: not recording move - %s does not exist\n') %
1225 ui.warn(_('%s: not recording move - %s does not exist\n') %
1224 (relsrc, reltarget))
1226 (relsrc, reltarget))
1225 else:
1227 else:
1226 ui.warn(_('%s: not recording copy - %s does not exist\n') %
1228 ui.warn(_('%s: not recording copy - %s does not exist\n') %
1227 (relsrc, reltarget))
1229 (relsrc, reltarget))
1228 return True # report a failure
1230 return True # report a failure
1229 elif not dryrun:
1231 elif not dryrun:
1230 try:
1232 try:
1231 if exists:
1233 if exists:
1232 os.unlink(target)
1234 os.unlink(target)
1233 targetdir = os.path.dirname(target) or '.'
1235 targetdir = os.path.dirname(target) or '.'
1234 if not os.path.isdir(targetdir):
1236 if not os.path.isdir(targetdir):
1235 os.makedirs(targetdir)
1237 os.makedirs(targetdir)
1236 if samefile:
1238 if samefile:
1237 tmp = target + "~hgrename"
1239 tmp = target + "~hgrename"
1238 os.rename(src, tmp)
1240 os.rename(src, tmp)
1239 os.rename(tmp, target)
1241 os.rename(tmp, target)
1240 else:
1242 else:
1241 # Preserve stat info on renames, not on copies; this matches
1243 # Preserve stat info on renames, not on copies; this matches
1242 # Linux CLI behavior.
1244 # Linux CLI behavior.
1243 util.copyfile(src, target, copystat=rename)
1245 util.copyfile(src, target, copystat=rename)
1244 srcexists = True
1246 srcexists = True
1245 except IOError as inst:
1247 except IOError as inst:
1246 if inst.errno == errno.ENOENT:
1248 if inst.errno == errno.ENOENT:
1247 ui.warn(_('%s: deleted in working directory\n') % relsrc)
1249 ui.warn(_('%s: deleted in working directory\n') % relsrc)
1248 srcexists = False
1250 srcexists = False
1249 else:
1251 else:
1250 ui.warn(_('%s: cannot copy - %s\n') %
1252 ui.warn(_('%s: cannot copy - %s\n') %
1251 (relsrc, encoding.strtolocal(inst.strerror)))
1253 (relsrc, encoding.strtolocal(inst.strerror)))
1252 return True # report a failure
1254 return True # report a failure
1253
1255
1254 if ui.verbose or not exact:
1256 if ui.verbose or not exact:
1255 if rename:
1257 if rename:
1256 ui.status(_('moving %s to %s\n') % (relsrc, reltarget))
1258 ui.status(_('moving %s to %s\n') % (relsrc, reltarget))
1257 else:
1259 else:
1258 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
1260 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
1259
1261
1260 targets[abstarget] = abssrc
1262 targets[abstarget] = abssrc
1261
1263
1262 # fix up dirstate
1264 # fix up dirstate
1263 scmutil.dirstatecopy(ui, repo, wctx, abssrc, abstarget,
1265 scmutil.dirstatecopy(ui, repo, wctx, abssrc, abstarget,
1264 dryrun=dryrun, cwd=cwd)
1266 dryrun=dryrun, cwd=cwd)
1265 if rename and not dryrun:
1267 if rename and not dryrun:
1266 if not after and srcexists and not samefile:
1268 if not after and srcexists and not samefile:
1267 rmdir = repo.ui.configbool('experimental', 'removeemptydirs')
1269 rmdir = repo.ui.configbool('experimental', 'removeemptydirs')
1268 repo.wvfs.unlinkpath(abssrc, rmdir=rmdir)
1270 repo.wvfs.unlinkpath(abssrc, rmdir=rmdir)
1269 wctx.forget([abssrc])
1271 wctx.forget([abssrc])
1270
1272
1271 # pat: ossep
1273 # pat: ossep
1272 # dest ossep
1274 # dest ossep
1273 # srcs: list of (hgsep, hgsep, ossep, bool)
1275 # srcs: list of (hgsep, hgsep, ossep, bool)
1274 # return: function that takes hgsep and returns ossep
1276 # return: function that takes hgsep and returns ossep
1275 def targetpathfn(pat, dest, srcs):
1277 def targetpathfn(pat, dest, srcs):
1276 if os.path.isdir(pat):
1278 if os.path.isdir(pat):
1277 abspfx = pathutil.canonpath(repo.root, cwd, pat)
1279 abspfx = pathutil.canonpath(repo.root, cwd, pat)
1278 abspfx = util.localpath(abspfx)
1280 abspfx = util.localpath(abspfx)
1279 if destdirexists:
1281 if destdirexists:
1280 striplen = len(os.path.split(abspfx)[0])
1282 striplen = len(os.path.split(abspfx)[0])
1281 else:
1283 else:
1282 striplen = len(abspfx)
1284 striplen = len(abspfx)
1283 if striplen:
1285 if striplen:
1284 striplen += len(pycompat.ossep)
1286 striplen += len(pycompat.ossep)
1285 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
1287 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
1286 elif destdirexists:
1288 elif destdirexists:
1287 res = lambda p: os.path.join(dest,
1289 res = lambda p: os.path.join(dest,
1288 os.path.basename(util.localpath(p)))
1290 os.path.basename(util.localpath(p)))
1289 else:
1291 else:
1290 res = lambda p: dest
1292 res = lambda p: dest
1291 return res
1293 return res
1292
1294
1293 # pat: ossep
1295 # pat: ossep
1294 # dest ossep
1296 # dest ossep
1295 # srcs: list of (hgsep, hgsep, ossep, bool)
1297 # srcs: list of (hgsep, hgsep, ossep, bool)
1296 # return: function that takes hgsep and returns ossep
1298 # return: function that takes hgsep and returns ossep
1297 def targetpathafterfn(pat, dest, srcs):
1299 def targetpathafterfn(pat, dest, srcs):
1298 if matchmod.patkind(pat):
1300 if matchmod.patkind(pat):
1299 # a mercurial pattern
1301 # a mercurial pattern
1300 res = lambda p: os.path.join(dest,
1302 res = lambda p: os.path.join(dest,
1301 os.path.basename(util.localpath(p)))
1303 os.path.basename(util.localpath(p)))
1302 else:
1304 else:
1303 abspfx = pathutil.canonpath(repo.root, cwd, pat)
1305 abspfx = pathutil.canonpath(repo.root, cwd, pat)
1304 if len(abspfx) < len(srcs[0][0]):
1306 if len(abspfx) < len(srcs[0][0]):
1305 # A directory. Either the target path contains the last
1307 # A directory. Either the target path contains the last
1306 # component of the source path or it does not.
1308 # component of the source path or it does not.
1307 def evalpath(striplen):
1309 def evalpath(striplen):
1308 score = 0
1310 score = 0
1309 for s in srcs:
1311 for s in srcs:
1310 t = os.path.join(dest, util.localpath(s[0])[striplen:])
1312 t = os.path.join(dest, util.localpath(s[0])[striplen:])
1311 if os.path.lexists(t):
1313 if os.path.lexists(t):
1312 score += 1
1314 score += 1
1313 return score
1315 return score
1314
1316
1315 abspfx = util.localpath(abspfx)
1317 abspfx = util.localpath(abspfx)
1316 striplen = len(abspfx)
1318 striplen = len(abspfx)
1317 if striplen:
1319 if striplen:
1318 striplen += len(pycompat.ossep)
1320 striplen += len(pycompat.ossep)
1319 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
1321 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
1320 score = evalpath(striplen)
1322 score = evalpath(striplen)
1321 striplen1 = len(os.path.split(abspfx)[0])
1323 striplen1 = len(os.path.split(abspfx)[0])
1322 if striplen1:
1324 if striplen1:
1323 striplen1 += len(pycompat.ossep)
1325 striplen1 += len(pycompat.ossep)
1324 if evalpath(striplen1) > score:
1326 if evalpath(striplen1) > score:
1325 striplen = striplen1
1327 striplen = striplen1
1326 res = lambda p: os.path.join(dest,
1328 res = lambda p: os.path.join(dest,
1327 util.localpath(p)[striplen:])
1329 util.localpath(p)[striplen:])
1328 else:
1330 else:
1329 # a file
1331 # a file
1330 if destdirexists:
1332 if destdirexists:
1331 res = lambda p: os.path.join(dest,
1333 res = lambda p: os.path.join(dest,
1332 os.path.basename(util.localpath(p)))
1334 os.path.basename(util.localpath(p)))
1333 else:
1335 else:
1334 res = lambda p: dest
1336 res = lambda p: dest
1335 return res
1337 return res
1336
1338
1337 pats = scmutil.expandpats(pats)
1339 pats = scmutil.expandpats(pats)
1338 if not pats:
1340 if not pats:
1339 raise error.Abort(_('no source or destination specified'))
1341 raise error.Abort(_('no source or destination specified'))
1340 if len(pats) == 1:
1342 if len(pats) == 1:
1341 raise error.Abort(_('no destination specified'))
1343 raise error.Abort(_('no destination specified'))
1342 dest = pats.pop()
1344 dest = pats.pop()
1343 destdirexists = os.path.isdir(dest) and not os.path.islink(dest)
1345 destdirexists = os.path.isdir(dest) and not os.path.islink(dest)
1344 if not destdirexists:
1346 if not destdirexists:
1345 if len(pats) > 1 or matchmod.patkind(pats[0]):
1347 if len(pats) > 1 or matchmod.patkind(pats[0]):
1346 raise error.Abort(_('with multiple sources, destination must be an '
1348 raise error.Abort(_('with multiple sources, destination must be an '
1347 'existing directory'))
1349 'existing directory'))
1348 if util.endswithsep(dest):
1350 if util.endswithsep(dest):
1349 raise error.Abort(_('destination %s is not a directory') % dest)
1351 raise error.Abort(_('destination %s is not a directory') % dest)
1350
1352
1351 tfn = targetpathfn
1353 tfn = targetpathfn
1352 if after:
1354 if after:
1353 tfn = targetpathafterfn
1355 tfn = targetpathafterfn
1354 copylist = []
1356 copylist = []
1355 for pat in pats:
1357 for pat in pats:
1356 srcs = walkpat(pat)
1358 srcs = walkpat(pat)
1357 if not srcs:
1359 if not srcs:
1358 continue
1360 continue
1359 copylist.append((tfn(pat, dest, srcs), srcs))
1361 copylist.append((tfn(pat, dest, srcs), srcs))
1360 if not copylist:
1362 if not copylist:
1361 raise error.Abort(_('no files to copy'))
1363 raise error.Abort(_('no files to copy'))
1362
1364
1363 errors = 0
1365 errors = 0
1364 for targetpath, srcs in copylist:
1366 for targetpath, srcs in copylist:
1365 for abssrc, relsrc, exact in srcs:
1367 for abssrc, relsrc, exact in srcs:
1366 if copyfile(abssrc, relsrc, targetpath(abssrc), exact):
1368 if copyfile(abssrc, relsrc, targetpath(abssrc), exact):
1367 errors += 1
1369 errors += 1
1368
1370
1369 return errors != 0
1371 return errors != 0
1370
1372
1371 ## facility to let extension process additional data into an import patch
1373 ## facility to let extension process additional data into an import patch
1372 # list of identifier to be executed in order
1374 # list of identifier to be executed in order
1373 extrapreimport = [] # run before commit
1375 extrapreimport = [] # run before commit
1374 extrapostimport = [] # run after commit
1376 extrapostimport = [] # run after commit
1375 # mapping from identifier to actual import function
1377 # mapping from identifier to actual import function
1376 #
1378 #
1377 # 'preimport' are run before the commit is made and are provided the following
1379 # 'preimport' are run before the commit is made and are provided the following
1378 # arguments:
1380 # arguments:
1379 # - repo: the localrepository instance,
1381 # - repo: the localrepository instance,
1380 # - patchdata: data extracted from patch header (cf m.patch.patchheadermap),
1382 # - patchdata: data extracted from patch header (cf m.patch.patchheadermap),
1381 # - extra: the future extra dictionary of the changeset, please mutate it,
1383 # - extra: the future extra dictionary of the changeset, please mutate it,
1382 # - opts: the import options.
1384 # - opts: the import options.
1383 # XXX ideally, we would just pass an ctx ready to be computed, that would allow
1385 # XXX ideally, we would just pass an ctx ready to be computed, that would allow
1384 # mutation of in memory commit and more. Feel free to rework the code to get
1386 # mutation of in memory commit and more. Feel free to rework the code to get
1385 # there.
1387 # there.
1386 extrapreimportmap = {}
1388 extrapreimportmap = {}
1387 # 'postimport' are run after the commit is made and are provided the following
1389 # 'postimport' are run after the commit is made and are provided the following
1388 # argument:
1390 # argument:
1389 # - ctx: the changectx created by import.
1391 # - ctx: the changectx created by import.
1390 extrapostimportmap = {}
1392 extrapostimportmap = {}
1391
1393
1392 def tryimportone(ui, repo, patchdata, parents, opts, msgs, updatefunc):
1394 def tryimportone(ui, repo, patchdata, parents, opts, msgs, updatefunc):
1393 """Utility function used by commands.import to import a single patch
1395 """Utility function used by commands.import to import a single patch
1394
1396
1395 This function is explicitly defined here to help the evolve extension to
1397 This function is explicitly defined here to help the evolve extension to
1396 wrap this part of the import logic.
1398 wrap this part of the import logic.
1397
1399
1398 The API is currently a bit ugly because it a simple code translation from
1400 The API is currently a bit ugly because it a simple code translation from
1399 the import command. Feel free to make it better.
1401 the import command. Feel free to make it better.
1400
1402
1401 :patchdata: a dictionary containing parsed patch data (such as from
1403 :patchdata: a dictionary containing parsed patch data (such as from
1402 ``patch.extract()``)
1404 ``patch.extract()``)
1403 :parents: nodes that will be parent of the created commit
1405 :parents: nodes that will be parent of the created commit
1404 :opts: the full dict of option passed to the import command
1406 :opts: the full dict of option passed to the import command
1405 :msgs: list to save commit message to.
1407 :msgs: list to save commit message to.
1406 (used in case we need to save it when failing)
1408 (used in case we need to save it when failing)
1407 :updatefunc: a function that update a repo to a given node
1409 :updatefunc: a function that update a repo to a given node
1408 updatefunc(<repo>, <node>)
1410 updatefunc(<repo>, <node>)
1409 """
1411 """
1410 # avoid cycle context -> subrepo -> cmdutil
1412 # avoid cycle context -> subrepo -> cmdutil
1411 from . import context
1413 from . import context
1412
1414
1413 tmpname = patchdata.get('filename')
1415 tmpname = patchdata.get('filename')
1414 message = patchdata.get('message')
1416 message = patchdata.get('message')
1415 user = opts.get('user') or patchdata.get('user')
1417 user = opts.get('user') or patchdata.get('user')
1416 date = opts.get('date') or patchdata.get('date')
1418 date = opts.get('date') or patchdata.get('date')
1417 branch = patchdata.get('branch')
1419 branch = patchdata.get('branch')
1418 nodeid = patchdata.get('nodeid')
1420 nodeid = patchdata.get('nodeid')
1419 p1 = patchdata.get('p1')
1421 p1 = patchdata.get('p1')
1420 p2 = patchdata.get('p2')
1422 p2 = patchdata.get('p2')
1421
1423
1422 nocommit = opts.get('no_commit')
1424 nocommit = opts.get('no_commit')
1423 importbranch = opts.get('import_branch')
1425 importbranch = opts.get('import_branch')
1424 update = not opts.get('bypass')
1426 update = not opts.get('bypass')
1425 strip = opts["strip"]
1427 strip = opts["strip"]
1426 prefix = opts["prefix"]
1428 prefix = opts["prefix"]
1427 sim = float(opts.get('similarity') or 0)
1429 sim = float(opts.get('similarity') or 0)
1428
1430
1429 if not tmpname:
1431 if not tmpname:
1430 return None, None, False
1432 return None, None, False
1431
1433
1432 rejects = False
1434 rejects = False
1433
1435
1434 cmdline_message = logmessage(ui, opts)
1436 cmdline_message = logmessage(ui, opts)
1435 if cmdline_message:
1437 if cmdline_message:
1436 # pickup the cmdline msg
1438 # pickup the cmdline msg
1437 message = cmdline_message
1439 message = cmdline_message
1438 elif message:
1440 elif message:
1439 # pickup the patch msg
1441 # pickup the patch msg
1440 message = message.strip()
1442 message = message.strip()
1441 else:
1443 else:
1442 # launch the editor
1444 # launch the editor
1443 message = None
1445 message = None
1444 ui.debug('message:\n%s\n' % (message or ''))
1446 ui.debug('message:\n%s\n' % (message or ''))
1445
1447
1446 if len(parents) == 1:
1448 if len(parents) == 1:
1447 parents.append(repo[nullid])
1449 parents.append(repo[nullid])
1448 if opts.get('exact'):
1450 if opts.get('exact'):
1449 if not nodeid or not p1:
1451 if not nodeid or not p1:
1450 raise error.Abort(_('not a Mercurial patch'))
1452 raise error.Abort(_('not a Mercurial patch'))
1451 p1 = repo[p1]
1453 p1 = repo[p1]
1452 p2 = repo[p2 or nullid]
1454 p2 = repo[p2 or nullid]
1453 elif p2:
1455 elif p2:
1454 try:
1456 try:
1455 p1 = repo[p1]
1457 p1 = repo[p1]
1456 p2 = repo[p2]
1458 p2 = repo[p2]
1457 # Without any options, consider p2 only if the
1459 # Without any options, consider p2 only if the
1458 # patch is being applied on top of the recorded
1460 # patch is being applied on top of the recorded
1459 # first parent.
1461 # first parent.
1460 if p1 != parents[0]:
1462 if p1 != parents[0]:
1461 p1 = parents[0]
1463 p1 = parents[0]
1462 p2 = repo[nullid]
1464 p2 = repo[nullid]
1463 except error.RepoError:
1465 except error.RepoError:
1464 p1, p2 = parents
1466 p1, p2 = parents
1465 if p2.node() == nullid:
1467 if p2.node() == nullid:
1466 ui.warn(_("warning: import the patch as a normal revision\n"
1468 ui.warn(_("warning: import the patch as a normal revision\n"
1467 "(use --exact to import the patch as a merge)\n"))
1469 "(use --exact to import the patch as a merge)\n"))
1468 else:
1470 else:
1469 p1, p2 = parents
1471 p1, p2 = parents
1470
1472
1471 n = None
1473 n = None
1472 if update:
1474 if update:
1473 if p1 != parents[0]:
1475 if p1 != parents[0]:
1474 updatefunc(repo, p1.node())
1476 updatefunc(repo, p1.node())
1475 if p2 != parents[1]:
1477 if p2 != parents[1]:
1476 repo.setparents(p1.node(), p2.node())
1478 repo.setparents(p1.node(), p2.node())
1477
1479
1478 if opts.get('exact') or importbranch:
1480 if opts.get('exact') or importbranch:
1479 repo.dirstate.setbranch(branch or 'default')
1481 repo.dirstate.setbranch(branch or 'default')
1480
1482
1481 partial = opts.get('partial', False)
1483 partial = opts.get('partial', False)
1482 files = set()
1484 files = set()
1483 try:
1485 try:
1484 patch.patch(ui, repo, tmpname, strip=strip, prefix=prefix,
1486 patch.patch(ui, repo, tmpname, strip=strip, prefix=prefix,
1485 files=files, eolmode=None, similarity=sim / 100.0)
1487 files=files, eolmode=None, similarity=sim / 100.0)
1486 except error.PatchError as e:
1488 except error.PatchError as e:
1487 if not partial:
1489 if not partial:
1488 raise error.Abort(pycompat.bytestr(e))
1490 raise error.Abort(pycompat.bytestr(e))
1489 if partial:
1491 if partial:
1490 rejects = True
1492 rejects = True
1491
1493
1492 files = list(files)
1494 files = list(files)
1493 if nocommit:
1495 if nocommit:
1494 if message:
1496 if message:
1495 msgs.append(message)
1497 msgs.append(message)
1496 else:
1498 else:
1497 if opts.get('exact') or p2:
1499 if opts.get('exact') or p2:
1498 # If you got here, you either use --force and know what
1500 # If you got here, you either use --force and know what
1499 # you are doing or used --exact or a merge patch while
1501 # you are doing or used --exact or a merge patch while
1500 # being updated to its first parent.
1502 # being updated to its first parent.
1501 m = None
1503 m = None
1502 else:
1504 else:
1503 m = scmutil.matchfiles(repo, files or [])
1505 m = scmutil.matchfiles(repo, files or [])
1504 editform = mergeeditform(repo[None], 'import.normal')
1506 editform = mergeeditform(repo[None], 'import.normal')
1505 if opts.get('exact'):
1507 if opts.get('exact'):
1506 editor = None
1508 editor = None
1507 else:
1509 else:
1508 editor = getcommiteditor(editform=editform,
1510 editor = getcommiteditor(editform=editform,
1509 **pycompat.strkwargs(opts))
1511 **pycompat.strkwargs(opts))
1510 extra = {}
1512 extra = {}
1511 for idfunc in extrapreimport:
1513 for idfunc in extrapreimport:
1512 extrapreimportmap[idfunc](repo, patchdata, extra, opts)
1514 extrapreimportmap[idfunc](repo, patchdata, extra, opts)
1513 overrides = {}
1515 overrides = {}
1514 if partial:
1516 if partial:
1515 overrides[('ui', 'allowemptycommit')] = True
1517 overrides[('ui', 'allowemptycommit')] = True
1516 with repo.ui.configoverride(overrides, 'import'):
1518 with repo.ui.configoverride(overrides, 'import'):
1517 n = repo.commit(message, user,
1519 n = repo.commit(message, user,
1518 date, match=m,
1520 date, match=m,
1519 editor=editor, extra=extra)
1521 editor=editor, extra=extra)
1520 for idfunc in extrapostimport:
1522 for idfunc in extrapostimport:
1521 extrapostimportmap[idfunc](repo[n])
1523 extrapostimportmap[idfunc](repo[n])
1522 else:
1524 else:
1523 if opts.get('exact') or importbranch:
1525 if opts.get('exact') or importbranch:
1524 branch = branch or 'default'
1526 branch = branch or 'default'
1525 else:
1527 else:
1526 branch = p1.branch()
1528 branch = p1.branch()
1527 store = patch.filestore()
1529 store = patch.filestore()
1528 try:
1530 try:
1529 files = set()
1531 files = set()
1530 try:
1532 try:
1531 patch.patchrepo(ui, repo, p1, store, tmpname, strip, prefix,
1533 patch.patchrepo(ui, repo, p1, store, tmpname, strip, prefix,
1532 files, eolmode=None)
1534 files, eolmode=None)
1533 except error.PatchError as e:
1535 except error.PatchError as e:
1534 raise error.Abort(stringutil.forcebytestr(e))
1536 raise error.Abort(stringutil.forcebytestr(e))
1535 if opts.get('exact'):
1537 if opts.get('exact'):
1536 editor = None
1538 editor = None
1537 else:
1539 else:
1538 editor = getcommiteditor(editform='import.bypass')
1540 editor = getcommiteditor(editform='import.bypass')
1539 memctx = context.memctx(repo, (p1.node(), p2.node()),
1541 memctx = context.memctx(repo, (p1.node(), p2.node()),
1540 message,
1542 message,
1541 files=files,
1543 files=files,
1542 filectxfn=store,
1544 filectxfn=store,
1543 user=user,
1545 user=user,
1544 date=date,
1546 date=date,
1545 branch=branch,
1547 branch=branch,
1546 editor=editor)
1548 editor=editor)
1547 n = memctx.commit()
1549 n = memctx.commit()
1548 finally:
1550 finally:
1549 store.close()
1551 store.close()
1550 if opts.get('exact') and nocommit:
1552 if opts.get('exact') and nocommit:
1551 # --exact with --no-commit is still useful in that it does merge
1553 # --exact with --no-commit is still useful in that it does merge
1552 # and branch bits
1554 # and branch bits
1553 ui.warn(_("warning: can't check exact import with --no-commit\n"))
1555 ui.warn(_("warning: can't check exact import with --no-commit\n"))
1554 elif opts.get('exact') and (not n or hex(n) != nodeid):
1556 elif opts.get('exact') and (not n or hex(n) != nodeid):
1555 raise error.Abort(_('patch is damaged or loses information'))
1557 raise error.Abort(_('patch is damaged or loses information'))
1556 msg = _('applied to working directory')
1558 msg = _('applied to working directory')
1557 if n:
1559 if n:
1558 # i18n: refers to a short changeset id
1560 # i18n: refers to a short changeset id
1559 msg = _('created %s') % short(n)
1561 msg = _('created %s') % short(n)
1560 return msg, n, rejects
1562 return msg, n, rejects
1561
1563
1562 # facility to let extensions include additional data in an exported patch
1564 # facility to let extensions include additional data in an exported patch
1563 # list of identifiers to be executed in order
1565 # list of identifiers to be executed in order
1564 extraexport = []
1566 extraexport = []
1565 # mapping from identifier to actual export function
1567 # mapping from identifier to actual export function
1566 # function as to return a string to be added to the header or None
1568 # function as to return a string to be added to the header or None
1567 # it is given two arguments (sequencenumber, changectx)
1569 # it is given two arguments (sequencenumber, changectx)
1568 extraexportmap = {}
1570 extraexportmap = {}
1569
1571
1570 def _exportsingle(repo, ctx, fm, match, switch_parent, seqno, diffopts):
1572 def _exportsingle(repo, ctx, fm, match, switch_parent, seqno, diffopts):
1571 node = scmutil.binnode(ctx)
1573 node = scmutil.binnode(ctx)
1572 parents = [p.node() for p in ctx.parents() if p]
1574 parents = [p.node() for p in ctx.parents() if p]
1573 branch = ctx.branch()
1575 branch = ctx.branch()
1574 if switch_parent:
1576 if switch_parent:
1575 parents.reverse()
1577 parents.reverse()
1576
1578
1577 if parents:
1579 if parents:
1578 prev = parents[0]
1580 prev = parents[0]
1579 else:
1581 else:
1580 prev = nullid
1582 prev = nullid
1581
1583
1582 fm.context(ctx=ctx)
1584 fm.context(ctx=ctx)
1583 fm.plain('# HG changeset patch\n')
1585 fm.plain('# HG changeset patch\n')
1584 fm.write('user', '# User %s\n', ctx.user())
1586 fm.write('user', '# User %s\n', ctx.user())
1585 fm.plain('# Date %d %d\n' % ctx.date())
1587 fm.plain('# Date %d %d\n' % ctx.date())
1586 fm.write('date', '# %s\n', fm.formatdate(ctx.date()))
1588 fm.write('date', '# %s\n', fm.formatdate(ctx.date()))
1587 fm.condwrite(branch and branch != 'default',
1589 fm.condwrite(branch and branch != 'default',
1588 'branch', '# Branch %s\n', branch)
1590 'branch', '# Branch %s\n', branch)
1589 fm.write('node', '# Node ID %s\n', hex(node))
1591 fm.write('node', '# Node ID %s\n', hex(node))
1590 fm.plain('# Parent %s\n' % hex(prev))
1592 fm.plain('# Parent %s\n' % hex(prev))
1591 if len(parents) > 1:
1593 if len(parents) > 1:
1592 fm.plain('# Parent %s\n' % hex(parents[1]))
1594 fm.plain('# Parent %s\n' % hex(parents[1]))
1593 fm.data(parents=fm.formatlist(pycompat.maplist(hex, parents), name='node'))
1595 fm.data(parents=fm.formatlist(pycompat.maplist(hex, parents), name='node'))
1594
1596
1595 # TODO: redesign extraexportmap function to support formatter
1597 # TODO: redesign extraexportmap function to support formatter
1596 for headerid in extraexport:
1598 for headerid in extraexport:
1597 header = extraexportmap[headerid](seqno, ctx)
1599 header = extraexportmap[headerid](seqno, ctx)
1598 if header is not None:
1600 if header is not None:
1599 fm.plain('# %s\n' % header)
1601 fm.plain('# %s\n' % header)
1600
1602
1601 fm.write('desc', '%s\n', ctx.description().rstrip())
1603 fm.write('desc', '%s\n', ctx.description().rstrip())
1602 fm.plain('\n')
1604 fm.plain('\n')
1603
1605
1604 if fm.isplain():
1606 if fm.isplain():
1605 chunkiter = patch.diffui(repo, prev, node, match, opts=diffopts)
1607 chunkiter = patch.diffui(repo, prev, node, match, opts=diffopts)
1606 for chunk, label in chunkiter:
1608 for chunk, label in chunkiter:
1607 fm.plain(chunk, label=label)
1609 fm.plain(chunk, label=label)
1608 else:
1610 else:
1609 chunkiter = patch.diff(repo, prev, node, match, opts=diffopts)
1611 chunkiter = patch.diff(repo, prev, node, match, opts=diffopts)
1610 # TODO: make it structured?
1612 # TODO: make it structured?
1611 fm.data(diff=b''.join(chunkiter))
1613 fm.data(diff=b''.join(chunkiter))
1612
1614
1613 def _exportfile(repo, revs, fm, dest, switch_parent, diffopts, match):
1615 def _exportfile(repo, revs, fm, dest, switch_parent, diffopts, match):
1614 """Export changesets to stdout or a single file"""
1616 """Export changesets to stdout or a single file"""
1615 for seqno, rev in enumerate(revs, 1):
1617 for seqno, rev in enumerate(revs, 1):
1616 ctx = repo[rev]
1618 ctx = repo[rev]
1617 if not dest.startswith('<'):
1619 if not dest.startswith('<'):
1618 repo.ui.note("%s\n" % dest)
1620 repo.ui.note("%s\n" % dest)
1619 fm.startitem()
1621 fm.startitem()
1620 _exportsingle(repo, ctx, fm, match, switch_parent, seqno, diffopts)
1622 _exportsingle(repo, ctx, fm, match, switch_parent, seqno, diffopts)
1621
1623
1622 def _exportfntemplate(repo, revs, basefm, fntemplate, switch_parent, diffopts,
1624 def _exportfntemplate(repo, revs, basefm, fntemplate, switch_parent, diffopts,
1623 match):
1625 match):
1624 """Export changesets to possibly multiple files"""
1626 """Export changesets to possibly multiple files"""
1625 total = len(revs)
1627 total = len(revs)
1626 revwidth = max(len(str(rev)) for rev in revs)
1628 revwidth = max(len(str(rev)) for rev in revs)
1627 filemap = util.sortdict() # filename: [(seqno, rev), ...]
1629 filemap = util.sortdict() # filename: [(seqno, rev), ...]
1628
1630
1629 for seqno, rev in enumerate(revs, 1):
1631 for seqno, rev in enumerate(revs, 1):
1630 ctx = repo[rev]
1632 ctx = repo[rev]
1631 dest = makefilename(ctx, fntemplate,
1633 dest = makefilename(ctx, fntemplate,
1632 total=total, seqno=seqno, revwidth=revwidth)
1634 total=total, seqno=seqno, revwidth=revwidth)
1633 filemap.setdefault(dest, []).append((seqno, rev))
1635 filemap.setdefault(dest, []).append((seqno, rev))
1634
1636
1635 for dest in filemap:
1637 for dest in filemap:
1636 with formatter.maybereopen(basefm, dest) as fm:
1638 with formatter.maybereopen(basefm, dest) as fm:
1637 repo.ui.note("%s\n" % dest)
1639 repo.ui.note("%s\n" % dest)
1638 for seqno, rev in filemap[dest]:
1640 for seqno, rev in filemap[dest]:
1639 fm.startitem()
1641 fm.startitem()
1640 ctx = repo[rev]
1642 ctx = repo[rev]
1641 _exportsingle(repo, ctx, fm, match, switch_parent, seqno,
1643 _exportsingle(repo, ctx, fm, match, switch_parent, seqno,
1642 diffopts)
1644 diffopts)
1643
1645
1644 def export(repo, revs, basefm, fntemplate='hg-%h.patch', switch_parent=False,
1646 def export(repo, revs, basefm, fntemplate='hg-%h.patch', switch_parent=False,
1645 opts=None, match=None):
1647 opts=None, match=None):
1646 '''export changesets as hg patches
1648 '''export changesets as hg patches
1647
1649
1648 Args:
1650 Args:
1649 repo: The repository from which we're exporting revisions.
1651 repo: The repository from which we're exporting revisions.
1650 revs: A list of revisions to export as revision numbers.
1652 revs: A list of revisions to export as revision numbers.
1651 basefm: A formatter to which patches should be written.
1653 basefm: A formatter to which patches should be written.
1652 fntemplate: An optional string to use for generating patch file names.
1654 fntemplate: An optional string to use for generating patch file names.
1653 switch_parent: If True, show diffs against second parent when not nullid.
1655 switch_parent: If True, show diffs against second parent when not nullid.
1654 Default is false, which always shows diff against p1.
1656 Default is false, which always shows diff against p1.
1655 opts: diff options to use for generating the patch.
1657 opts: diff options to use for generating the patch.
1656 match: If specified, only export changes to files matching this matcher.
1658 match: If specified, only export changes to files matching this matcher.
1657
1659
1658 Returns:
1660 Returns:
1659 Nothing.
1661 Nothing.
1660
1662
1661 Side Effect:
1663 Side Effect:
1662 "HG Changeset Patch" data is emitted to one of the following
1664 "HG Changeset Patch" data is emitted to one of the following
1663 destinations:
1665 destinations:
1664 fntemplate specified: Each rev is written to a unique file named using
1666 fntemplate specified: Each rev is written to a unique file named using
1665 the given template.
1667 the given template.
1666 Otherwise: All revs will be written to basefm.
1668 Otherwise: All revs will be written to basefm.
1667 '''
1669 '''
1668 scmutil.prefetchfiles(repo, revs, match)
1670 scmutil.prefetchfiles(repo, revs, match)
1669
1671
1670 if not fntemplate:
1672 if not fntemplate:
1671 _exportfile(repo, revs, basefm, '<unnamed>', switch_parent, opts, match)
1673 _exportfile(repo, revs, basefm, '<unnamed>', switch_parent, opts, match)
1672 else:
1674 else:
1673 _exportfntemplate(repo, revs, basefm, fntemplate, switch_parent, opts,
1675 _exportfntemplate(repo, revs, basefm, fntemplate, switch_parent, opts,
1674 match)
1676 match)
1675
1677
1676 def exportfile(repo, revs, fp, switch_parent=False, opts=None, match=None):
1678 def exportfile(repo, revs, fp, switch_parent=False, opts=None, match=None):
1677 """Export changesets to the given file stream"""
1679 """Export changesets to the given file stream"""
1678 scmutil.prefetchfiles(repo, revs, match)
1680 scmutil.prefetchfiles(repo, revs, match)
1679
1681
1680 dest = getattr(fp, 'name', '<unnamed>')
1682 dest = getattr(fp, 'name', '<unnamed>')
1681 with formatter.formatter(repo.ui, fp, 'export', {}) as fm:
1683 with formatter.formatter(repo.ui, fp, 'export', {}) as fm:
1682 _exportfile(repo, revs, fm, dest, switch_parent, opts, match)
1684 _exportfile(repo, revs, fm, dest, switch_parent, opts, match)
1683
1685
1684 def showmarker(fm, marker, index=None):
1686 def showmarker(fm, marker, index=None):
1685 """utility function to display obsolescence marker in a readable way
1687 """utility function to display obsolescence marker in a readable way
1686
1688
1687 To be used by debug function."""
1689 To be used by debug function."""
1688 if index is not None:
1690 if index is not None:
1689 fm.write('index', '%i ', index)
1691 fm.write('index', '%i ', index)
1690 fm.write('prednode', '%s ', hex(marker.prednode()))
1692 fm.write('prednode', '%s ', hex(marker.prednode()))
1691 succs = marker.succnodes()
1693 succs = marker.succnodes()
1692 fm.condwrite(succs, 'succnodes', '%s ',
1694 fm.condwrite(succs, 'succnodes', '%s ',
1693 fm.formatlist(map(hex, succs), name='node'))
1695 fm.formatlist(map(hex, succs), name='node'))
1694 fm.write('flag', '%X ', marker.flags())
1696 fm.write('flag', '%X ', marker.flags())
1695 parents = marker.parentnodes()
1697 parents = marker.parentnodes()
1696 if parents is not None:
1698 if parents is not None:
1697 fm.write('parentnodes', '{%s} ',
1699 fm.write('parentnodes', '{%s} ',
1698 fm.formatlist(map(hex, parents), name='node', sep=', '))
1700 fm.formatlist(map(hex, parents), name='node', sep=', '))
1699 fm.write('date', '(%s) ', fm.formatdate(marker.date()))
1701 fm.write('date', '(%s) ', fm.formatdate(marker.date()))
1700 meta = marker.metadata().copy()
1702 meta = marker.metadata().copy()
1701 meta.pop('date', None)
1703 meta.pop('date', None)
1702 smeta = pycompat.rapply(pycompat.maybebytestr, meta)
1704 smeta = pycompat.rapply(pycompat.maybebytestr, meta)
1703 fm.write('metadata', '{%s}', fm.formatdict(smeta, fmt='%r: %r', sep=', '))
1705 fm.write('metadata', '{%s}', fm.formatdict(smeta, fmt='%r: %r', sep=', '))
1704 fm.plain('\n')
1706 fm.plain('\n')
1705
1707
1706 def finddate(ui, repo, date):
1708 def finddate(ui, repo, date):
1707 """Find the tipmost changeset that matches the given date spec"""
1709 """Find the tipmost changeset that matches the given date spec"""
1708
1710
1709 df = dateutil.matchdate(date)
1711 df = dateutil.matchdate(date)
1710 m = scmutil.matchall(repo)
1712 m = scmutil.matchall(repo)
1711 results = {}
1713 results = {}
1712
1714
1713 def prep(ctx, fns):
1715 def prep(ctx, fns):
1714 d = ctx.date()
1716 d = ctx.date()
1715 if df(d[0]):
1717 if df(d[0]):
1716 results[ctx.rev()] = d
1718 results[ctx.rev()] = d
1717
1719
1718 for ctx in walkchangerevs(repo, m, {'rev': None}, prep):
1720 for ctx in walkchangerevs(repo, m, {'rev': None}, prep):
1719 rev = ctx.rev()
1721 rev = ctx.rev()
1720 if rev in results:
1722 if rev in results:
1721 ui.status(_("found revision %s from %s\n") %
1723 ui.status(_("found revision %s from %s\n") %
1722 (rev, dateutil.datestr(results[rev])))
1724 (rev, dateutil.datestr(results[rev])))
1723 return '%d' % rev
1725 return '%d' % rev
1724
1726
1725 raise error.Abort(_("revision matching date not found"))
1727 raise error.Abort(_("revision matching date not found"))
1726
1728
1727 def increasingwindows(windowsize=8, sizelimit=512):
1729 def increasingwindows(windowsize=8, sizelimit=512):
1728 while True:
1730 while True:
1729 yield windowsize
1731 yield windowsize
1730 if windowsize < sizelimit:
1732 if windowsize < sizelimit:
1731 windowsize *= 2
1733 windowsize *= 2
1732
1734
1733 def _walkrevs(repo, opts):
1735 def _walkrevs(repo, opts):
1734 # Default --rev value depends on --follow but --follow behavior
1736 # Default --rev value depends on --follow but --follow behavior
1735 # depends on revisions resolved from --rev...
1737 # depends on revisions resolved from --rev...
1736 follow = opts.get('follow') or opts.get('follow_first')
1738 follow = opts.get('follow') or opts.get('follow_first')
1737 if opts.get('rev'):
1739 if opts.get('rev'):
1738 revs = scmutil.revrange(repo, opts['rev'])
1740 revs = scmutil.revrange(repo, opts['rev'])
1739 elif follow and repo.dirstate.p1() == nullid:
1741 elif follow and repo.dirstate.p1() == nullid:
1740 revs = smartset.baseset()
1742 revs = smartset.baseset()
1741 elif follow:
1743 elif follow:
1742 revs = repo.revs('reverse(:.)')
1744 revs = repo.revs('reverse(:.)')
1743 else:
1745 else:
1744 revs = smartset.spanset(repo)
1746 revs = smartset.spanset(repo)
1745 revs.reverse()
1747 revs.reverse()
1746 return revs
1748 return revs
1747
1749
1748 class FileWalkError(Exception):
1750 class FileWalkError(Exception):
1749 pass
1751 pass
1750
1752
1751 def walkfilerevs(repo, match, follow, revs, fncache):
1753 def walkfilerevs(repo, match, follow, revs, fncache):
1752 '''Walks the file history for the matched files.
1754 '''Walks the file history for the matched files.
1753
1755
1754 Returns the changeset revs that are involved in the file history.
1756 Returns the changeset revs that are involved in the file history.
1755
1757
1756 Throws FileWalkError if the file history can't be walked using
1758 Throws FileWalkError if the file history can't be walked using
1757 filelogs alone.
1759 filelogs alone.
1758 '''
1760 '''
1759 wanted = set()
1761 wanted = set()
1760 copies = []
1762 copies = []
1761 minrev, maxrev = min(revs), max(revs)
1763 minrev, maxrev = min(revs), max(revs)
1762 def filerevgen(filelog, last):
1764 def filerevgen(filelog, last):
1763 """
1765 """
1764 Only files, no patterns. Check the history of each file.
1766 Only files, no patterns. Check the history of each file.
1765
1767
1766 Examines filelog entries within minrev, maxrev linkrev range
1768 Examines filelog entries within minrev, maxrev linkrev range
1767 Returns an iterator yielding (linkrev, parentlinkrevs, copied)
1769 Returns an iterator yielding (linkrev, parentlinkrevs, copied)
1768 tuples in backwards order
1770 tuples in backwards order
1769 """
1771 """
1770 cl_count = len(repo)
1772 cl_count = len(repo)
1771 revs = []
1773 revs = []
1772 for j in pycompat.xrange(0, last + 1):
1774 for j in pycompat.xrange(0, last + 1):
1773 linkrev = filelog.linkrev(j)
1775 linkrev = filelog.linkrev(j)
1774 if linkrev < minrev:
1776 if linkrev < minrev:
1775 continue
1777 continue
1776 # only yield rev for which we have the changelog, it can
1778 # only yield rev for which we have the changelog, it can
1777 # happen while doing "hg log" during a pull or commit
1779 # happen while doing "hg log" during a pull or commit
1778 if linkrev >= cl_count:
1780 if linkrev >= cl_count:
1779 break
1781 break
1780
1782
1781 parentlinkrevs = []
1783 parentlinkrevs = []
1782 for p in filelog.parentrevs(j):
1784 for p in filelog.parentrevs(j):
1783 if p != nullrev:
1785 if p != nullrev:
1784 parentlinkrevs.append(filelog.linkrev(p))
1786 parentlinkrevs.append(filelog.linkrev(p))
1785 n = filelog.node(j)
1787 n = filelog.node(j)
1786 revs.append((linkrev, parentlinkrevs,
1788 revs.append((linkrev, parentlinkrevs,
1787 follow and filelog.renamed(n)))
1789 follow and filelog.renamed(n)))
1788
1790
1789 return reversed(revs)
1791 return reversed(revs)
1790 def iterfiles():
1792 def iterfiles():
1791 pctx = repo['.']
1793 pctx = repo['.']
1792 for filename in match.files():
1794 for filename in match.files():
1793 if follow:
1795 if follow:
1794 if filename not in pctx:
1796 if filename not in pctx:
1795 raise error.Abort(_('cannot follow file not in parent '
1797 raise error.Abort(_('cannot follow file not in parent '
1796 'revision: "%s"') % filename)
1798 'revision: "%s"') % filename)
1797 yield filename, pctx[filename].filenode()
1799 yield filename, pctx[filename].filenode()
1798 else:
1800 else:
1799 yield filename, None
1801 yield filename, None
1800 for filename_node in copies:
1802 for filename_node in copies:
1801 yield filename_node
1803 yield filename_node
1802
1804
1803 for file_, node in iterfiles():
1805 for file_, node in iterfiles():
1804 filelog = repo.file(file_)
1806 filelog = repo.file(file_)
1805 if not len(filelog):
1807 if not len(filelog):
1806 if node is None:
1808 if node is None:
1807 # A zero count may be a directory or deleted file, so
1809 # A zero count may be a directory or deleted file, so
1808 # try to find matching entries on the slow path.
1810 # try to find matching entries on the slow path.
1809 if follow:
1811 if follow:
1810 raise error.Abort(
1812 raise error.Abort(
1811 _('cannot follow nonexistent file: "%s"') % file_)
1813 _('cannot follow nonexistent file: "%s"') % file_)
1812 raise FileWalkError("Cannot walk via filelog")
1814 raise FileWalkError("Cannot walk via filelog")
1813 else:
1815 else:
1814 continue
1816 continue
1815
1817
1816 if node is None:
1818 if node is None:
1817 last = len(filelog) - 1
1819 last = len(filelog) - 1
1818 else:
1820 else:
1819 last = filelog.rev(node)
1821 last = filelog.rev(node)
1820
1822
1821 # keep track of all ancestors of the file
1823 # keep track of all ancestors of the file
1822 ancestors = {filelog.linkrev(last)}
1824 ancestors = {filelog.linkrev(last)}
1823
1825
1824 # iterate from latest to oldest revision
1826 # iterate from latest to oldest revision
1825 for rev, flparentlinkrevs, copied in filerevgen(filelog, last):
1827 for rev, flparentlinkrevs, copied in filerevgen(filelog, last):
1826 if not follow:
1828 if not follow:
1827 if rev > maxrev:
1829 if rev > maxrev:
1828 continue
1830 continue
1829 else:
1831 else:
1830 # Note that last might not be the first interesting
1832 # Note that last might not be the first interesting
1831 # rev to us:
1833 # rev to us:
1832 # if the file has been changed after maxrev, we'll
1834 # if the file has been changed after maxrev, we'll
1833 # have linkrev(last) > maxrev, and we still need
1835 # have linkrev(last) > maxrev, and we still need
1834 # to explore the file graph
1836 # to explore the file graph
1835 if rev not in ancestors:
1837 if rev not in ancestors:
1836 continue
1838 continue
1837 # XXX insert 1327 fix here
1839 # XXX insert 1327 fix here
1838 if flparentlinkrevs:
1840 if flparentlinkrevs:
1839 ancestors.update(flparentlinkrevs)
1841 ancestors.update(flparentlinkrevs)
1840
1842
1841 fncache.setdefault(rev, []).append(file_)
1843 fncache.setdefault(rev, []).append(file_)
1842 wanted.add(rev)
1844 wanted.add(rev)
1843 if copied:
1845 if copied:
1844 copies.append(copied)
1846 copies.append(copied)
1845
1847
1846 return wanted
1848 return wanted
1847
1849
1848 class _followfilter(object):
1850 class _followfilter(object):
1849 def __init__(self, repo, onlyfirst=False):
1851 def __init__(self, repo, onlyfirst=False):
1850 self.repo = repo
1852 self.repo = repo
1851 self.startrev = nullrev
1853 self.startrev = nullrev
1852 self.roots = set()
1854 self.roots = set()
1853 self.onlyfirst = onlyfirst
1855 self.onlyfirst = onlyfirst
1854
1856
1855 def match(self, rev):
1857 def match(self, rev):
1856 def realparents(rev):
1858 def realparents(rev):
1857 if self.onlyfirst:
1859 if self.onlyfirst:
1858 return self.repo.changelog.parentrevs(rev)[0:1]
1860 return self.repo.changelog.parentrevs(rev)[0:1]
1859 else:
1861 else:
1860 return filter(lambda x: x != nullrev,
1862 return filter(lambda x: x != nullrev,
1861 self.repo.changelog.parentrevs(rev))
1863 self.repo.changelog.parentrevs(rev))
1862
1864
1863 if self.startrev == nullrev:
1865 if self.startrev == nullrev:
1864 self.startrev = rev
1866 self.startrev = rev
1865 return True
1867 return True
1866
1868
1867 if rev > self.startrev:
1869 if rev > self.startrev:
1868 # forward: all descendants
1870 # forward: all descendants
1869 if not self.roots:
1871 if not self.roots:
1870 self.roots.add(self.startrev)
1872 self.roots.add(self.startrev)
1871 for parent in realparents(rev):
1873 for parent in realparents(rev):
1872 if parent in self.roots:
1874 if parent in self.roots:
1873 self.roots.add(rev)
1875 self.roots.add(rev)
1874 return True
1876 return True
1875 else:
1877 else:
1876 # backwards: all parents
1878 # backwards: all parents
1877 if not self.roots:
1879 if not self.roots:
1878 self.roots.update(realparents(self.startrev))
1880 self.roots.update(realparents(self.startrev))
1879 if rev in self.roots:
1881 if rev in self.roots:
1880 self.roots.remove(rev)
1882 self.roots.remove(rev)
1881 self.roots.update(realparents(rev))
1883 self.roots.update(realparents(rev))
1882 return True
1884 return True
1883
1885
1884 return False
1886 return False
1885
1887
1886 def walkchangerevs(repo, match, opts, prepare):
1888 def walkchangerevs(repo, match, opts, prepare):
1887 '''Iterate over files and the revs in which they changed.
1889 '''Iterate over files and the revs in which they changed.
1888
1890
1889 Callers most commonly need to iterate backwards over the history
1891 Callers most commonly need to iterate backwards over the history
1890 in which they are interested. Doing so has awful (quadratic-looking)
1892 in which they are interested. Doing so has awful (quadratic-looking)
1891 performance, so we use iterators in a "windowed" way.
1893 performance, so we use iterators in a "windowed" way.
1892
1894
1893 We walk a window of revisions in the desired order. Within the
1895 We walk a window of revisions in the desired order. Within the
1894 window, we first walk forwards to gather data, then in the desired
1896 window, we first walk forwards to gather data, then in the desired
1895 order (usually backwards) to display it.
1897 order (usually backwards) to display it.
1896
1898
1897 This function returns an iterator yielding contexts. Before
1899 This function returns an iterator yielding contexts. Before
1898 yielding each context, the iterator will first call the prepare
1900 yielding each context, the iterator will first call the prepare
1899 function on each context in the window in forward order.'''
1901 function on each context in the window in forward order.'''
1900
1902
1901 allfiles = opts.get('all_files')
1903 allfiles = opts.get('all_files')
1902 follow = opts.get('follow') or opts.get('follow_first')
1904 follow = opts.get('follow') or opts.get('follow_first')
1903 revs = _walkrevs(repo, opts)
1905 revs = _walkrevs(repo, opts)
1904 if not revs:
1906 if not revs:
1905 return []
1907 return []
1906 wanted = set()
1908 wanted = set()
1907 slowpath = match.anypats() or (not match.always() and opts.get('removed'))
1909 slowpath = match.anypats() or (not match.always() and opts.get('removed'))
1908 fncache = {}
1910 fncache = {}
1909 change = repo.__getitem__
1911 change = repo.__getitem__
1910
1912
1911 # First step is to fill wanted, the set of revisions that we want to yield.
1913 # First step is to fill wanted, the set of revisions that we want to yield.
1912 # When it does not induce extra cost, we also fill fncache for revisions in
1914 # When it does not induce extra cost, we also fill fncache for revisions in
1913 # wanted: a cache of filenames that were changed (ctx.files()) and that
1915 # wanted: a cache of filenames that were changed (ctx.files()) and that
1914 # match the file filtering conditions.
1916 # match the file filtering conditions.
1915
1917
1916 if match.always() or allfiles:
1918 if match.always() or allfiles:
1917 # No files, no patterns. Display all revs.
1919 # No files, no patterns. Display all revs.
1918 wanted = revs
1920 wanted = revs
1919 elif not slowpath:
1921 elif not slowpath:
1920 # We only have to read through the filelog to find wanted revisions
1922 # We only have to read through the filelog to find wanted revisions
1921
1923
1922 try:
1924 try:
1923 wanted = walkfilerevs(repo, match, follow, revs, fncache)
1925 wanted = walkfilerevs(repo, match, follow, revs, fncache)
1924 except FileWalkError:
1926 except FileWalkError:
1925 slowpath = True
1927 slowpath = True
1926
1928
1927 # We decided to fall back to the slowpath because at least one
1929 # We decided to fall back to the slowpath because at least one
1928 # of the paths was not a file. Check to see if at least one of them
1930 # of the paths was not a file. Check to see if at least one of them
1929 # existed in history, otherwise simply return
1931 # existed in history, otherwise simply return
1930 for path in match.files():
1932 for path in match.files():
1931 if path == '.' or path in repo.store:
1933 if path == '.' or path in repo.store:
1932 break
1934 break
1933 else:
1935 else:
1934 return []
1936 return []
1935
1937
1936 if slowpath:
1938 if slowpath:
1937 # We have to read the changelog to match filenames against
1939 # We have to read the changelog to match filenames against
1938 # changed files
1940 # changed files
1939
1941
1940 if follow:
1942 if follow:
1941 raise error.Abort(_('can only follow copies/renames for explicit '
1943 raise error.Abort(_('can only follow copies/renames for explicit '
1942 'filenames'))
1944 'filenames'))
1943
1945
1944 # The slow path checks files modified in every changeset.
1946 # The slow path checks files modified in every changeset.
1945 # This is really slow on large repos, so compute the set lazily.
1947 # This is really slow on large repos, so compute the set lazily.
1946 class lazywantedset(object):
1948 class lazywantedset(object):
1947 def __init__(self):
1949 def __init__(self):
1948 self.set = set()
1950 self.set = set()
1949 self.revs = set(revs)
1951 self.revs = set(revs)
1950
1952
1951 # No need to worry about locality here because it will be accessed
1953 # No need to worry about locality here because it will be accessed
1952 # in the same order as the increasing window below.
1954 # in the same order as the increasing window below.
1953 def __contains__(self, value):
1955 def __contains__(self, value):
1954 if value in self.set:
1956 if value in self.set:
1955 return True
1957 return True
1956 elif not value in self.revs:
1958 elif not value in self.revs:
1957 return False
1959 return False
1958 else:
1960 else:
1959 self.revs.discard(value)
1961 self.revs.discard(value)
1960 ctx = change(value)
1962 ctx = change(value)
1961 matches = [f for f in ctx.files() if match(f)]
1963 matches = [f for f in ctx.files() if match(f)]
1962 if matches:
1964 if matches:
1963 fncache[value] = matches
1965 fncache[value] = matches
1964 self.set.add(value)
1966 self.set.add(value)
1965 return True
1967 return True
1966 return False
1968 return False
1967
1969
1968 def discard(self, value):
1970 def discard(self, value):
1969 self.revs.discard(value)
1971 self.revs.discard(value)
1970 self.set.discard(value)
1972 self.set.discard(value)
1971
1973
1972 wanted = lazywantedset()
1974 wanted = lazywantedset()
1973
1975
1974 # it might be worthwhile to do this in the iterator if the rev range
1976 # it might be worthwhile to do this in the iterator if the rev range
1975 # is descending and the prune args are all within that range
1977 # is descending and the prune args are all within that range
1976 for rev in opts.get('prune', ()):
1978 for rev in opts.get('prune', ()):
1977 rev = repo[rev].rev()
1979 rev = repo[rev].rev()
1978 ff = _followfilter(repo)
1980 ff = _followfilter(repo)
1979 stop = min(revs[0], revs[-1])
1981 stop = min(revs[0], revs[-1])
1980 for x in pycompat.xrange(rev, stop - 1, -1):
1982 for x in pycompat.xrange(rev, stop - 1, -1):
1981 if ff.match(x):
1983 if ff.match(x):
1982 wanted = wanted - [x]
1984 wanted = wanted - [x]
1983
1985
1984 # Now that wanted is correctly initialized, we can iterate over the
1986 # Now that wanted is correctly initialized, we can iterate over the
1985 # revision range, yielding only revisions in wanted.
1987 # revision range, yielding only revisions in wanted.
1986 def iterate():
1988 def iterate():
1987 if follow and match.always():
1989 if follow and match.always():
1988 ff = _followfilter(repo, onlyfirst=opts.get('follow_first'))
1990 ff = _followfilter(repo, onlyfirst=opts.get('follow_first'))
1989 def want(rev):
1991 def want(rev):
1990 return ff.match(rev) and rev in wanted
1992 return ff.match(rev) and rev in wanted
1991 else:
1993 else:
1992 def want(rev):
1994 def want(rev):
1993 return rev in wanted
1995 return rev in wanted
1994
1996
1995 it = iter(revs)
1997 it = iter(revs)
1996 stopiteration = False
1998 stopiteration = False
1997 for windowsize in increasingwindows():
1999 for windowsize in increasingwindows():
1998 nrevs = []
2000 nrevs = []
1999 for i in pycompat.xrange(windowsize):
2001 for i in pycompat.xrange(windowsize):
2000 rev = next(it, None)
2002 rev = next(it, None)
2001 if rev is None:
2003 if rev is None:
2002 stopiteration = True
2004 stopiteration = True
2003 break
2005 break
2004 elif want(rev):
2006 elif want(rev):
2005 nrevs.append(rev)
2007 nrevs.append(rev)
2006 for rev in sorted(nrevs):
2008 for rev in sorted(nrevs):
2007 fns = fncache.get(rev)
2009 fns = fncache.get(rev)
2008 ctx = change(rev)
2010 ctx = change(rev)
2009 if not fns:
2011 if not fns:
2010 def fns_generator():
2012 def fns_generator():
2011 if allfiles:
2013 if allfiles:
2012 fiter = iter(ctx)
2014 fiter = iter(ctx)
2013 else:
2015 else:
2014 fiter = ctx.files()
2016 fiter = ctx.files()
2015 for f in fiter:
2017 for f in fiter:
2016 if match(f):
2018 if match(f):
2017 yield f
2019 yield f
2018 fns = fns_generator()
2020 fns = fns_generator()
2019 prepare(ctx, fns)
2021 prepare(ctx, fns)
2020 for rev in nrevs:
2022 for rev in nrevs:
2021 yield change(rev)
2023 yield change(rev)
2022
2024
2023 if stopiteration:
2025 if stopiteration:
2024 break
2026 break
2025
2027
2026 return iterate()
2028 return iterate()
2027
2029
2028 def add(ui, repo, match, prefix, explicitonly, **opts):
2030 def add(ui, repo, match, prefix, explicitonly, **opts):
2029 join = lambda f: os.path.join(prefix, f)
2031 join = lambda f: os.path.join(prefix, f)
2030 bad = []
2032 bad = []
2031
2033
2032 badfn = lambda x, y: bad.append(x) or match.bad(x, y)
2034 badfn = lambda x, y: bad.append(x) or match.bad(x, y)
2033 names = []
2035 names = []
2034 wctx = repo[None]
2036 wctx = repo[None]
2035 cca = None
2037 cca = None
2036 abort, warn = scmutil.checkportabilityalert(ui)
2038 abort, warn = scmutil.checkportabilityalert(ui)
2037 if abort or warn:
2039 if abort or warn:
2038 cca = scmutil.casecollisionauditor(ui, abort, repo.dirstate)
2040 cca = scmutil.casecollisionauditor(ui, abort, repo.dirstate)
2039
2041
2040 match = repo.narrowmatch(match, includeexact=True)
2042 match = repo.narrowmatch(match, includeexact=True)
2041 badmatch = matchmod.badmatch(match, badfn)
2043 badmatch = matchmod.badmatch(match, badfn)
2042 dirstate = repo.dirstate
2044 dirstate = repo.dirstate
2043 # We don't want to just call wctx.walk here, since it would return a lot of
2045 # We don't want to just call wctx.walk here, since it would return a lot of
2044 # clean files, which we aren't interested in and takes time.
2046 # clean files, which we aren't interested in and takes time.
2045 for f in sorted(dirstate.walk(badmatch, subrepos=sorted(wctx.substate),
2047 for f in sorted(dirstate.walk(badmatch, subrepos=sorted(wctx.substate),
2046 unknown=True, ignored=False, full=False)):
2048 unknown=True, ignored=False, full=False)):
2047 exact = match.exact(f)
2049 exact = match.exact(f)
2048 if exact or not explicitonly and f not in wctx and repo.wvfs.lexists(f):
2050 if exact or not explicitonly and f not in wctx and repo.wvfs.lexists(f):
2049 if cca:
2051 if cca:
2050 cca(f)
2052 cca(f)
2051 names.append(f)
2053 names.append(f)
2052 if ui.verbose or not exact:
2054 if ui.verbose or not exact:
2053 ui.status(_('adding %s\n') % match.rel(f),
2055 ui.status(_('adding %s\n') % match.rel(f),
2054 label='ui.addremove.added')
2056 label='ui.addremove.added')
2055
2057
2056 for subpath in sorted(wctx.substate):
2058 for subpath in sorted(wctx.substate):
2057 sub = wctx.sub(subpath)
2059 sub = wctx.sub(subpath)
2058 try:
2060 try:
2059 submatch = matchmod.subdirmatcher(subpath, match)
2061 submatch = matchmod.subdirmatcher(subpath, match)
2060 if opts.get(r'subrepos'):
2062 if opts.get(r'subrepos'):
2061 bad.extend(sub.add(ui, submatch, prefix, False, **opts))
2063 bad.extend(sub.add(ui, submatch, prefix, False, **opts))
2062 else:
2064 else:
2063 bad.extend(sub.add(ui, submatch, prefix, True, **opts))
2065 bad.extend(sub.add(ui, submatch, prefix, True, **opts))
2064 except error.LookupError:
2066 except error.LookupError:
2065 ui.status(_("skipping missing subrepository: %s\n")
2067 ui.status(_("skipping missing subrepository: %s\n")
2066 % join(subpath))
2068 % join(subpath))
2067
2069
2068 if not opts.get(r'dry_run'):
2070 if not opts.get(r'dry_run'):
2069 rejected = wctx.add(names, prefix)
2071 rejected = wctx.add(names, prefix)
2070 bad.extend(f for f in rejected if f in match.files())
2072 bad.extend(f for f in rejected if f in match.files())
2071 return bad
2073 return bad
2072
2074
2073 def addwebdirpath(repo, serverpath, webconf):
2075 def addwebdirpath(repo, serverpath, webconf):
2074 webconf[serverpath] = repo.root
2076 webconf[serverpath] = repo.root
2075 repo.ui.debug('adding %s = %s\n' % (serverpath, repo.root))
2077 repo.ui.debug('adding %s = %s\n' % (serverpath, repo.root))
2076
2078
2077 for r in repo.revs('filelog("path:.hgsub")'):
2079 for r in repo.revs('filelog("path:.hgsub")'):
2078 ctx = repo[r]
2080 ctx = repo[r]
2079 for subpath in ctx.substate:
2081 for subpath in ctx.substate:
2080 ctx.sub(subpath).addwebdirpath(serverpath, webconf)
2082 ctx.sub(subpath).addwebdirpath(serverpath, webconf)
2081
2083
2082 def forget(ui, repo, match, prefix, explicitonly, dryrun, interactive):
2084 def forget(ui, repo, match, prefix, explicitonly, dryrun, interactive):
2083 if dryrun and interactive:
2085 if dryrun and interactive:
2084 raise error.Abort(_("cannot specify both --dry-run and --interactive"))
2086 raise error.Abort(_("cannot specify both --dry-run and --interactive"))
2085 join = lambda f: os.path.join(prefix, f)
2087 join = lambda f: os.path.join(prefix, f)
2086 bad = []
2088 bad = []
2087 badfn = lambda x, y: bad.append(x) or match.bad(x, y)
2089 badfn = lambda x, y: bad.append(x) or match.bad(x, y)
2088 wctx = repo[None]
2090 wctx = repo[None]
2089 forgot = []
2091 forgot = []
2090
2092
2091 s = repo.status(match=matchmod.badmatch(match, badfn), clean=True)
2093 s = repo.status(match=matchmod.badmatch(match, badfn), clean=True)
2092 forget = sorted(s.modified + s.added + s.deleted + s.clean)
2094 forget = sorted(s.modified + s.added + s.deleted + s.clean)
2093 if explicitonly:
2095 if explicitonly:
2094 forget = [f for f in forget if match.exact(f)]
2096 forget = [f for f in forget if match.exact(f)]
2095
2097
2096 for subpath in sorted(wctx.substate):
2098 for subpath in sorted(wctx.substate):
2097 sub = wctx.sub(subpath)
2099 sub = wctx.sub(subpath)
2098 try:
2100 try:
2099 submatch = matchmod.subdirmatcher(subpath, match)
2101 submatch = matchmod.subdirmatcher(subpath, match)
2100 subbad, subforgot = sub.forget(submatch, prefix, dryrun=dryrun,
2102 subbad, subforgot = sub.forget(submatch, prefix, dryrun=dryrun,
2101 interactive=interactive)
2103 interactive=interactive)
2102 bad.extend([subpath + '/' + f for f in subbad])
2104 bad.extend([subpath + '/' + f for f in subbad])
2103 forgot.extend([subpath + '/' + f for f in subforgot])
2105 forgot.extend([subpath + '/' + f for f in subforgot])
2104 except error.LookupError:
2106 except error.LookupError:
2105 ui.status(_("skipping missing subrepository: %s\n")
2107 ui.status(_("skipping missing subrepository: %s\n")
2106 % join(subpath))
2108 % join(subpath))
2107
2109
2108 if not explicitonly:
2110 if not explicitonly:
2109 for f in match.files():
2111 for f in match.files():
2110 if f not in repo.dirstate and not repo.wvfs.isdir(f):
2112 if f not in repo.dirstate and not repo.wvfs.isdir(f):
2111 if f not in forgot:
2113 if f not in forgot:
2112 if repo.wvfs.exists(f):
2114 if repo.wvfs.exists(f):
2113 # Don't complain if the exact case match wasn't given.
2115 # Don't complain if the exact case match wasn't given.
2114 # But don't do this until after checking 'forgot', so
2116 # But don't do this until after checking 'forgot', so
2115 # that subrepo files aren't normalized, and this op is
2117 # that subrepo files aren't normalized, and this op is
2116 # purely from data cached by the status walk above.
2118 # purely from data cached by the status walk above.
2117 if repo.dirstate.normalize(f) in repo.dirstate:
2119 if repo.dirstate.normalize(f) in repo.dirstate:
2118 continue
2120 continue
2119 ui.warn(_('not removing %s: '
2121 ui.warn(_('not removing %s: '
2120 'file is already untracked\n')
2122 'file is already untracked\n')
2121 % match.rel(f))
2123 % match.rel(f))
2122 bad.append(f)
2124 bad.append(f)
2123
2125
2124 if interactive:
2126 if interactive:
2125 responses = _('[Ynsa?]'
2127 responses = _('[Ynsa?]'
2126 '$$ &Yes, forget this file'
2128 '$$ &Yes, forget this file'
2127 '$$ &No, skip this file'
2129 '$$ &No, skip this file'
2128 '$$ &Skip remaining files'
2130 '$$ &Skip remaining files'
2129 '$$ Include &all remaining files'
2131 '$$ Include &all remaining files'
2130 '$$ &? (display help)')
2132 '$$ &? (display help)')
2131 for filename in forget[:]:
2133 for filename in forget[:]:
2132 r = ui.promptchoice(_('forget %s %s') % (filename, responses))
2134 r = ui.promptchoice(_('forget %s %s') % (filename, responses))
2133 if r == 4: # ?
2135 if r == 4: # ?
2134 while r == 4:
2136 while r == 4:
2135 for c, t in ui.extractchoices(responses)[1]:
2137 for c, t in ui.extractchoices(responses)[1]:
2136 ui.write('%s - %s\n' % (c, encoding.lower(t)))
2138 ui.write('%s - %s\n' % (c, encoding.lower(t)))
2137 r = ui.promptchoice(_('forget %s %s') % (filename,
2139 r = ui.promptchoice(_('forget %s %s') % (filename,
2138 responses))
2140 responses))
2139 if r == 0: # yes
2141 if r == 0: # yes
2140 continue
2142 continue
2141 elif r == 1: # no
2143 elif r == 1: # no
2142 forget.remove(filename)
2144 forget.remove(filename)
2143 elif r == 2: # Skip
2145 elif r == 2: # Skip
2144 fnindex = forget.index(filename)
2146 fnindex = forget.index(filename)
2145 del forget[fnindex:]
2147 del forget[fnindex:]
2146 break
2148 break
2147 elif r == 3: # All
2149 elif r == 3: # All
2148 break
2150 break
2149
2151
2150 for f in forget:
2152 for f in forget:
2151 if ui.verbose or not match.exact(f) or interactive:
2153 if ui.verbose or not match.exact(f) or interactive:
2152 ui.status(_('removing %s\n') % match.rel(f),
2154 ui.status(_('removing %s\n') % match.rel(f),
2153 label='ui.addremove.removed')
2155 label='ui.addremove.removed')
2154
2156
2155 if not dryrun:
2157 if not dryrun:
2156 rejected = wctx.forget(forget, prefix)
2158 rejected = wctx.forget(forget, prefix)
2157 bad.extend(f for f in rejected if f in match.files())
2159 bad.extend(f for f in rejected if f in match.files())
2158 forgot.extend(f for f in forget if f not in rejected)
2160 forgot.extend(f for f in forget if f not in rejected)
2159 return bad, forgot
2161 return bad, forgot
2160
2162
2161 def files(ui, ctx, m, fm, fmt, subrepos):
2163 def files(ui, ctx, m, fm, fmt, subrepos):
2162 ret = 1
2164 ret = 1
2163
2165
2164 needsfctx = ui.verbose or {'size', 'flags'} & fm.datahint()
2166 needsfctx = ui.verbose or {'size', 'flags'} & fm.datahint()
2165 for f in ctx.matches(m):
2167 for f in ctx.matches(m):
2166 fm.startitem()
2168 fm.startitem()
2167 fm.context(ctx=ctx)
2169 fm.context(ctx=ctx)
2168 if needsfctx:
2170 if needsfctx:
2169 fc = ctx[f]
2171 fc = ctx[f]
2170 fm.write('size flags', '% 10d % 1s ', fc.size(), fc.flags())
2172 fm.write('size flags', '% 10d % 1s ', fc.size(), fc.flags())
2171 fm.data(path=f)
2173 fm.data(path=f)
2172 fm.plain(fmt % m.rel(f))
2174 fm.plain(fmt % m.rel(f))
2173 ret = 0
2175 ret = 0
2174
2176
2175 for subpath in sorted(ctx.substate):
2177 for subpath in sorted(ctx.substate):
2176 submatch = matchmod.subdirmatcher(subpath, m)
2178 submatch = matchmod.subdirmatcher(subpath, m)
2177 if (subrepos or m.exact(subpath) or any(submatch.files())):
2179 if (subrepos or m.exact(subpath) or any(submatch.files())):
2178 sub = ctx.sub(subpath)
2180 sub = ctx.sub(subpath)
2179 try:
2181 try:
2180 recurse = m.exact(subpath) or subrepos
2182 recurse = m.exact(subpath) or subrepos
2181 if sub.printfiles(ui, submatch, fm, fmt, recurse) == 0:
2183 if sub.printfiles(ui, submatch, fm, fmt, recurse) == 0:
2182 ret = 0
2184 ret = 0
2183 except error.LookupError:
2185 except error.LookupError:
2184 ui.status(_("skipping missing subrepository: %s\n")
2186 ui.status(_("skipping missing subrepository: %s\n")
2185 % m.abs(subpath))
2187 % m.abs(subpath))
2186
2188
2187 return ret
2189 return ret
2188
2190
2189 def remove(ui, repo, m, prefix, after, force, subrepos, dryrun, warnings=None):
2191 def remove(ui, repo, m, prefix, after, force, subrepos, dryrun, warnings=None):
2190 join = lambda f: os.path.join(prefix, f)
2192 join = lambda f: os.path.join(prefix, f)
2191 ret = 0
2193 ret = 0
2192 s = repo.status(match=m, clean=True)
2194 s = repo.status(match=m, clean=True)
2193 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
2195 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
2194
2196
2195 wctx = repo[None]
2197 wctx = repo[None]
2196
2198
2197 if warnings is None:
2199 if warnings is None:
2198 warnings = []
2200 warnings = []
2199 warn = True
2201 warn = True
2200 else:
2202 else:
2201 warn = False
2203 warn = False
2202
2204
2203 subs = sorted(wctx.substate)
2205 subs = sorted(wctx.substate)
2204 progress = ui.makeprogress(_('searching'), total=len(subs),
2206 progress = ui.makeprogress(_('searching'), total=len(subs),
2205 unit=_('subrepos'))
2207 unit=_('subrepos'))
2206 for subpath in subs:
2208 for subpath in subs:
2207 submatch = matchmod.subdirmatcher(subpath, m)
2209 submatch = matchmod.subdirmatcher(subpath, m)
2208 if subrepos or m.exact(subpath) or any(submatch.files()):
2210 if subrepos or m.exact(subpath) or any(submatch.files()):
2209 progress.increment()
2211 progress.increment()
2210 sub = wctx.sub(subpath)
2212 sub = wctx.sub(subpath)
2211 try:
2213 try:
2212 if sub.removefiles(submatch, prefix, after, force, subrepos,
2214 if sub.removefiles(submatch, prefix, after, force, subrepos,
2213 dryrun, warnings):
2215 dryrun, warnings):
2214 ret = 1
2216 ret = 1
2215 except error.LookupError:
2217 except error.LookupError:
2216 warnings.append(_("skipping missing subrepository: %s\n")
2218 warnings.append(_("skipping missing subrepository: %s\n")
2217 % join(subpath))
2219 % join(subpath))
2218 progress.complete()
2220 progress.complete()
2219
2221
2220 # warn about failure to delete explicit files/dirs
2222 # warn about failure to delete explicit files/dirs
2221 deleteddirs = util.dirs(deleted)
2223 deleteddirs = util.dirs(deleted)
2222 files = m.files()
2224 files = m.files()
2223 progress = ui.makeprogress(_('deleting'), total=len(files),
2225 progress = ui.makeprogress(_('deleting'), total=len(files),
2224 unit=_('files'))
2226 unit=_('files'))
2225 for f in files:
2227 for f in files:
2226 def insubrepo():
2228 def insubrepo():
2227 for subpath in wctx.substate:
2229 for subpath in wctx.substate:
2228 if f.startswith(subpath + '/'):
2230 if f.startswith(subpath + '/'):
2229 return True
2231 return True
2230 return False
2232 return False
2231
2233
2232 progress.increment()
2234 progress.increment()
2233 isdir = f in deleteddirs or wctx.hasdir(f)
2235 isdir = f in deleteddirs or wctx.hasdir(f)
2234 if (f in repo.dirstate or isdir or f == '.'
2236 if (f in repo.dirstate or isdir or f == '.'
2235 or insubrepo() or f in subs):
2237 or insubrepo() or f in subs):
2236 continue
2238 continue
2237
2239
2238 if repo.wvfs.exists(f):
2240 if repo.wvfs.exists(f):
2239 if repo.wvfs.isdir(f):
2241 if repo.wvfs.isdir(f):
2240 warnings.append(_('not removing %s: no tracked files\n')
2242 warnings.append(_('not removing %s: no tracked files\n')
2241 % m.rel(f))
2243 % m.rel(f))
2242 else:
2244 else:
2243 warnings.append(_('not removing %s: file is untracked\n')
2245 warnings.append(_('not removing %s: file is untracked\n')
2244 % m.rel(f))
2246 % m.rel(f))
2245 # missing files will generate a warning elsewhere
2247 # missing files will generate a warning elsewhere
2246 ret = 1
2248 ret = 1
2247 progress.complete()
2249 progress.complete()
2248
2250
2249 if force:
2251 if force:
2250 list = modified + deleted + clean + added
2252 list = modified + deleted + clean + added
2251 elif after:
2253 elif after:
2252 list = deleted
2254 list = deleted
2253 remaining = modified + added + clean
2255 remaining = modified + added + clean
2254 progress = ui.makeprogress(_('skipping'), total=len(remaining),
2256 progress = ui.makeprogress(_('skipping'), total=len(remaining),
2255 unit=_('files'))
2257 unit=_('files'))
2256 for f in remaining:
2258 for f in remaining:
2257 progress.increment()
2259 progress.increment()
2258 if ui.verbose or (f in files):
2260 if ui.verbose or (f in files):
2259 warnings.append(_('not removing %s: file still exists\n')
2261 warnings.append(_('not removing %s: file still exists\n')
2260 % m.rel(f))
2262 % m.rel(f))
2261 ret = 1
2263 ret = 1
2262 progress.complete()
2264 progress.complete()
2263 else:
2265 else:
2264 list = deleted + clean
2266 list = deleted + clean
2265 progress = ui.makeprogress(_('skipping'),
2267 progress = ui.makeprogress(_('skipping'),
2266 total=(len(modified) + len(added)),
2268 total=(len(modified) + len(added)),
2267 unit=_('files'))
2269 unit=_('files'))
2268 for f in modified:
2270 for f in modified:
2269 progress.increment()
2271 progress.increment()
2270 warnings.append(_('not removing %s: file is modified (use -f'
2272 warnings.append(_('not removing %s: file is modified (use -f'
2271 ' to force removal)\n') % m.rel(f))
2273 ' to force removal)\n') % m.rel(f))
2272 ret = 1
2274 ret = 1
2273 for f in added:
2275 for f in added:
2274 progress.increment()
2276 progress.increment()
2275 warnings.append(_("not removing %s: file has been marked for add"
2277 warnings.append(_("not removing %s: file has been marked for add"
2276 " (use 'hg forget' to undo add)\n") % m.rel(f))
2278 " (use 'hg forget' to undo add)\n") % m.rel(f))
2277 ret = 1
2279 ret = 1
2278 progress.complete()
2280 progress.complete()
2279
2281
2280 list = sorted(list)
2282 list = sorted(list)
2281 progress = ui.makeprogress(_('deleting'), total=len(list),
2283 progress = ui.makeprogress(_('deleting'), total=len(list),
2282 unit=_('files'))
2284 unit=_('files'))
2283 for f in list:
2285 for f in list:
2284 if ui.verbose or not m.exact(f):
2286 if ui.verbose or not m.exact(f):
2285 progress.increment()
2287 progress.increment()
2286 ui.status(_('removing %s\n') % m.rel(f),
2288 ui.status(_('removing %s\n') % m.rel(f),
2287 label='ui.addremove.removed')
2289 label='ui.addremove.removed')
2288 progress.complete()
2290 progress.complete()
2289
2291
2290 if not dryrun:
2292 if not dryrun:
2291 with repo.wlock():
2293 with repo.wlock():
2292 if not after:
2294 if not after:
2293 for f in list:
2295 for f in list:
2294 if f in added:
2296 if f in added:
2295 continue # we never unlink added files on remove
2297 continue # we never unlink added files on remove
2296 rmdir = repo.ui.configbool('experimental',
2298 rmdir = repo.ui.configbool('experimental',
2297 'removeemptydirs')
2299 'removeemptydirs')
2298 repo.wvfs.unlinkpath(f, ignoremissing=True, rmdir=rmdir)
2300 repo.wvfs.unlinkpath(f, ignoremissing=True, rmdir=rmdir)
2299 repo[None].forget(list)
2301 repo[None].forget(list)
2300
2302
2301 if warn:
2303 if warn:
2302 for warning in warnings:
2304 for warning in warnings:
2303 ui.warn(warning)
2305 ui.warn(warning)
2304
2306
2305 return ret
2307 return ret
2306
2308
2307 def _updatecatformatter(fm, ctx, matcher, path, decode):
2309 def _updatecatformatter(fm, ctx, matcher, path, decode):
2308 """Hook for adding data to the formatter used by ``hg cat``.
2310 """Hook for adding data to the formatter used by ``hg cat``.
2309
2311
2310 Extensions (e.g., lfs) can wrap this to inject keywords/data, but must call
2312 Extensions (e.g., lfs) can wrap this to inject keywords/data, but must call
2311 this method first."""
2313 this method first."""
2312 data = ctx[path].data()
2314 data = ctx[path].data()
2313 if decode:
2315 if decode:
2314 data = ctx.repo().wwritedata(path, data)
2316 data = ctx.repo().wwritedata(path, data)
2315 fm.startitem()
2317 fm.startitem()
2316 fm.context(ctx=ctx)
2318 fm.context(ctx=ctx)
2317 fm.write('data', '%s', data)
2319 fm.write('data', '%s', data)
2318 fm.data(path=path)
2320 fm.data(path=path)
2319
2321
2320 def cat(ui, repo, ctx, matcher, basefm, fntemplate, prefix, **opts):
2322 def cat(ui, repo, ctx, matcher, basefm, fntemplate, prefix, **opts):
2321 err = 1
2323 err = 1
2322 opts = pycompat.byteskwargs(opts)
2324 opts = pycompat.byteskwargs(opts)
2323
2325
2324 def write(path):
2326 def write(path):
2325 filename = None
2327 filename = None
2326 if fntemplate:
2328 if fntemplate:
2327 filename = makefilename(ctx, fntemplate,
2329 filename = makefilename(ctx, fntemplate,
2328 pathname=os.path.join(prefix, path))
2330 pathname=os.path.join(prefix, path))
2329 # attempt to create the directory if it does not already exist
2331 # attempt to create the directory if it does not already exist
2330 try:
2332 try:
2331 os.makedirs(os.path.dirname(filename))
2333 os.makedirs(os.path.dirname(filename))
2332 except OSError:
2334 except OSError:
2333 pass
2335 pass
2334 with formatter.maybereopen(basefm, filename) as fm:
2336 with formatter.maybereopen(basefm, filename) as fm:
2335 _updatecatformatter(fm, ctx, matcher, path, opts.get('decode'))
2337 _updatecatformatter(fm, ctx, matcher, path, opts.get('decode'))
2336
2338
2337 # Automation often uses hg cat on single files, so special case it
2339 # Automation often uses hg cat on single files, so special case it
2338 # for performance to avoid the cost of parsing the manifest.
2340 # for performance to avoid the cost of parsing the manifest.
2339 if len(matcher.files()) == 1 and not matcher.anypats():
2341 if len(matcher.files()) == 1 and not matcher.anypats():
2340 file = matcher.files()[0]
2342 file = matcher.files()[0]
2341 mfl = repo.manifestlog
2343 mfl = repo.manifestlog
2342 mfnode = ctx.manifestnode()
2344 mfnode = ctx.manifestnode()
2343 try:
2345 try:
2344 if mfnode and mfl[mfnode].find(file)[0]:
2346 if mfnode and mfl[mfnode].find(file)[0]:
2345 scmutil.prefetchfiles(repo, [ctx.rev()], matcher)
2347 scmutil.prefetchfiles(repo, [ctx.rev()], matcher)
2346 write(file)
2348 write(file)
2347 return 0
2349 return 0
2348 except KeyError:
2350 except KeyError:
2349 pass
2351 pass
2350
2352
2351 scmutil.prefetchfiles(repo, [ctx.rev()], matcher)
2353 scmutil.prefetchfiles(repo, [ctx.rev()], matcher)
2352
2354
2353 for abs in ctx.walk(matcher):
2355 for abs in ctx.walk(matcher):
2354 write(abs)
2356 write(abs)
2355 err = 0
2357 err = 0
2356
2358
2357 for subpath in sorted(ctx.substate):
2359 for subpath in sorted(ctx.substate):
2358 sub = ctx.sub(subpath)
2360 sub = ctx.sub(subpath)
2359 try:
2361 try:
2360 submatch = matchmod.subdirmatcher(subpath, matcher)
2362 submatch = matchmod.subdirmatcher(subpath, matcher)
2361
2363
2362 if not sub.cat(submatch, basefm, fntemplate,
2364 if not sub.cat(submatch, basefm, fntemplate,
2363 os.path.join(prefix, sub._path),
2365 os.path.join(prefix, sub._path),
2364 **pycompat.strkwargs(opts)):
2366 **pycompat.strkwargs(opts)):
2365 err = 0
2367 err = 0
2366 except error.RepoLookupError:
2368 except error.RepoLookupError:
2367 ui.status(_("skipping missing subrepository: %s\n")
2369 ui.status(_("skipping missing subrepository: %s\n")
2368 % os.path.join(prefix, subpath))
2370 % os.path.join(prefix, subpath))
2369
2371
2370 return err
2372 return err
2371
2373
2372 def commit(ui, repo, commitfunc, pats, opts):
2374 def commit(ui, repo, commitfunc, pats, opts):
2373 '''commit the specified files or all outstanding changes'''
2375 '''commit the specified files or all outstanding changes'''
2374 date = opts.get('date')
2376 date = opts.get('date')
2375 if date:
2377 if date:
2376 opts['date'] = dateutil.parsedate(date)
2378 opts['date'] = dateutil.parsedate(date)
2377 message = logmessage(ui, opts)
2379 message = logmessage(ui, opts)
2378 matcher = scmutil.match(repo[None], pats, opts)
2380 matcher = scmutil.match(repo[None], pats, opts)
2379
2381
2380 dsguard = None
2382 dsguard = None
2381 # extract addremove carefully -- this function can be called from a command
2383 # extract addremove carefully -- this function can be called from a command
2382 # that doesn't support addremove
2384 # that doesn't support addremove
2383 if opts.get('addremove'):
2385 if opts.get('addremove'):
2384 dsguard = dirstateguard.dirstateguard(repo, 'commit')
2386 dsguard = dirstateguard.dirstateguard(repo, 'commit')
2385 with dsguard or util.nullcontextmanager():
2387 with dsguard or util.nullcontextmanager():
2386 if dsguard:
2388 if dsguard:
2387 if scmutil.addremove(repo, matcher, "", opts) != 0:
2389 if scmutil.addremove(repo, matcher, "", opts) != 0:
2388 raise error.Abort(
2390 raise error.Abort(
2389 _("failed to mark all new/missing files as added/removed"))
2391 _("failed to mark all new/missing files as added/removed"))
2390
2392
2391 return commitfunc(ui, repo, message, matcher, opts)
2393 return commitfunc(ui, repo, message, matcher, opts)
2392
2394
2393 def samefile(f, ctx1, ctx2):
2395 def samefile(f, ctx1, ctx2):
2394 if f in ctx1.manifest():
2396 if f in ctx1.manifest():
2395 a = ctx1.filectx(f)
2397 a = ctx1.filectx(f)
2396 if f in ctx2.manifest():
2398 if f in ctx2.manifest():
2397 b = ctx2.filectx(f)
2399 b = ctx2.filectx(f)
2398 return (not a.cmp(b)
2400 return (not a.cmp(b)
2399 and a.flags() == b.flags())
2401 and a.flags() == b.flags())
2400 else:
2402 else:
2401 return False
2403 return False
2402 else:
2404 else:
2403 return f not in ctx2.manifest()
2405 return f not in ctx2.manifest()
2404
2406
2405 def amend(ui, repo, old, extra, pats, opts):
2407 def amend(ui, repo, old, extra, pats, opts):
2406 # avoid cycle context -> subrepo -> cmdutil
2408 # avoid cycle context -> subrepo -> cmdutil
2407 from . import context
2409 from . import context
2408
2410
2409 # amend will reuse the existing user if not specified, but the obsolete
2411 # amend will reuse the existing user if not specified, but the obsolete
2410 # marker creation requires that the current user's name is specified.
2412 # marker creation requires that the current user's name is specified.
2411 if obsolete.isenabled(repo, obsolete.createmarkersopt):
2413 if obsolete.isenabled(repo, obsolete.createmarkersopt):
2412 ui.username() # raise exception if username not set
2414 ui.username() # raise exception if username not set
2413
2415
2414 ui.note(_('amending changeset %s\n') % old)
2416 ui.note(_('amending changeset %s\n') % old)
2415 base = old.p1()
2417 base = old.p1()
2416
2418
2417 with repo.wlock(), repo.lock(), repo.transaction('amend'):
2419 with repo.wlock(), repo.lock(), repo.transaction('amend'):
2418 # Participating changesets:
2420 # Participating changesets:
2419 #
2421 #
2420 # wctx o - workingctx that contains changes from working copy
2422 # wctx o - workingctx that contains changes from working copy
2421 # | to go into amending commit
2423 # | to go into amending commit
2422 # |
2424 # |
2423 # old o - changeset to amend
2425 # old o - changeset to amend
2424 # |
2426 # |
2425 # base o - first parent of the changeset to amend
2427 # base o - first parent of the changeset to amend
2426 wctx = repo[None]
2428 wctx = repo[None]
2427
2429
2428 # Copy to avoid mutating input
2430 # Copy to avoid mutating input
2429 extra = extra.copy()
2431 extra = extra.copy()
2430 # Update extra dict from amended commit (e.g. to preserve graft
2432 # Update extra dict from amended commit (e.g. to preserve graft
2431 # source)
2433 # source)
2432 extra.update(old.extra())
2434 extra.update(old.extra())
2433
2435
2434 # Also update it from the from the wctx
2436 # Also update it from the from the wctx
2435 extra.update(wctx.extra())
2437 extra.update(wctx.extra())
2436
2438
2437 user = opts.get('user') or old.user()
2439 user = opts.get('user') or old.user()
2438
2440
2439 datemaydiffer = False # date-only change should be ignored?
2441 datemaydiffer = False # date-only change should be ignored?
2440 if opts.get('date') and opts.get('currentdate'):
2442 if opts.get('date') and opts.get('currentdate'):
2441 raise error.Abort(_('--date and --currentdate are mutually '
2443 raise error.Abort(_('--date and --currentdate are mutually '
2442 'exclusive'))
2444 'exclusive'))
2443 if opts.get('date'):
2445 if opts.get('date'):
2444 date = dateutil.parsedate(opts.get('date'))
2446 date = dateutil.parsedate(opts.get('date'))
2445 elif opts.get('currentdate'):
2447 elif opts.get('currentdate'):
2446 date = dateutil.makedate()
2448 date = dateutil.makedate()
2447 elif (ui.configbool('rewrite', 'update-timestamp')
2449 elif (ui.configbool('rewrite', 'update-timestamp')
2448 and opts.get('currentdate') is None):
2450 and opts.get('currentdate') is None):
2449 date = dateutil.makedate()
2451 date = dateutil.makedate()
2450 datemaydiffer = True
2452 datemaydiffer = True
2451 else:
2453 else:
2452 date = old.date()
2454 date = old.date()
2453
2455
2454 if len(old.parents()) > 1:
2456 if len(old.parents()) > 1:
2455 # ctx.files() isn't reliable for merges, so fall back to the
2457 # ctx.files() isn't reliable for merges, so fall back to the
2456 # slower repo.status() method
2458 # slower repo.status() method
2457 files = set([fn for st in base.status(old)[:3]
2459 files = set([fn for st in base.status(old)[:3]
2458 for fn in st])
2460 for fn in st])
2459 else:
2461 else:
2460 files = set(old.files())
2462 files = set(old.files())
2461
2463
2462 # add/remove the files to the working copy if the "addremove" option
2464 # add/remove the files to the working copy if the "addremove" option
2463 # was specified.
2465 # was specified.
2464 matcher = scmutil.match(wctx, pats, opts)
2466 matcher = scmutil.match(wctx, pats, opts)
2465 if (opts.get('addremove')
2467 if (opts.get('addremove')
2466 and scmutil.addremove(repo, matcher, "", opts)):
2468 and scmutil.addremove(repo, matcher, "", opts)):
2467 raise error.Abort(
2469 raise error.Abort(
2468 _("failed to mark all new/missing files as added/removed"))
2470 _("failed to mark all new/missing files as added/removed"))
2469
2471
2470 # Check subrepos. This depends on in-place wctx._status update in
2472 # Check subrepos. This depends on in-place wctx._status update in
2471 # subrepo.precommit(). To minimize the risk of this hack, we do
2473 # subrepo.precommit(). To minimize the risk of this hack, we do
2472 # nothing if .hgsub does not exist.
2474 # nothing if .hgsub does not exist.
2473 if '.hgsub' in wctx or '.hgsub' in old:
2475 if '.hgsub' in wctx or '.hgsub' in old:
2474 subs, commitsubs, newsubstate = subrepoutil.precommit(
2476 subs, commitsubs, newsubstate = subrepoutil.precommit(
2475 ui, wctx, wctx._status, matcher)
2477 ui, wctx, wctx._status, matcher)
2476 # amend should abort if commitsubrepos is enabled
2478 # amend should abort if commitsubrepos is enabled
2477 assert not commitsubs
2479 assert not commitsubs
2478 if subs:
2480 if subs:
2479 subrepoutil.writestate(repo, newsubstate)
2481 subrepoutil.writestate(repo, newsubstate)
2480
2482
2481 ms = mergemod.mergestate.read(repo)
2483 ms = mergemod.mergestate.read(repo)
2482 mergeutil.checkunresolved(ms)
2484 mergeutil.checkunresolved(ms)
2483
2485
2484 filestoamend = set(f for f in wctx.files() if matcher(f))
2486 filestoamend = set(f for f in wctx.files() if matcher(f))
2485
2487
2486 changes = (len(filestoamend) > 0)
2488 changes = (len(filestoamend) > 0)
2487 if changes:
2489 if changes:
2488 # Recompute copies (avoid recording a -> b -> a)
2490 # Recompute copies (avoid recording a -> b -> a)
2489 copied = copies.pathcopies(base, wctx, matcher)
2491 copied = copies.pathcopies(base, wctx, matcher)
2490 if old.p2:
2492 if old.p2:
2491 copied.update(copies.pathcopies(old.p2(), wctx, matcher))
2493 copied.update(copies.pathcopies(old.p2(), wctx, matcher))
2492
2494
2493 # Prune files which were reverted by the updates: if old
2495 # Prune files which were reverted by the updates: if old
2494 # introduced file X and the file was renamed in the working
2496 # introduced file X and the file was renamed in the working
2495 # copy, then those two files are the same and
2497 # copy, then those two files are the same and
2496 # we can discard X from our list of files. Likewise if X
2498 # we can discard X from our list of files. Likewise if X
2497 # was removed, it's no longer relevant. If X is missing (aka
2499 # was removed, it's no longer relevant. If X is missing (aka
2498 # deleted), old X must be preserved.
2500 # deleted), old X must be preserved.
2499 files.update(filestoamend)
2501 files.update(filestoamend)
2500 files = [f for f in files if (not samefile(f, wctx, base)
2502 files = [f for f in files if (not samefile(f, wctx, base)
2501 or f in wctx.deleted())]
2503 or f in wctx.deleted())]
2502
2504
2503 def filectxfn(repo, ctx_, path):
2505 def filectxfn(repo, ctx_, path):
2504 try:
2506 try:
2505 # If the file being considered is not amongst the files
2507 # If the file being considered is not amongst the files
2506 # to be amended, we should return the file context from the
2508 # to be amended, we should return the file context from the
2507 # old changeset. This avoids issues when only some files in
2509 # old changeset. This avoids issues when only some files in
2508 # the working copy are being amended but there are also
2510 # the working copy are being amended but there are also
2509 # changes to other files from the old changeset.
2511 # changes to other files from the old changeset.
2510 if path not in filestoamend:
2512 if path not in filestoamend:
2511 return old.filectx(path)
2513 return old.filectx(path)
2512
2514
2513 # Return None for removed files.
2515 # Return None for removed files.
2514 if path in wctx.removed():
2516 if path in wctx.removed():
2515 return None
2517 return None
2516
2518
2517 fctx = wctx[path]
2519 fctx = wctx[path]
2518 flags = fctx.flags()
2520 flags = fctx.flags()
2519 mctx = context.memfilectx(repo, ctx_,
2521 mctx = context.memfilectx(repo, ctx_,
2520 fctx.path(), fctx.data(),
2522 fctx.path(), fctx.data(),
2521 islink='l' in flags,
2523 islink='l' in flags,
2522 isexec='x' in flags,
2524 isexec='x' in flags,
2523 copied=copied.get(path))
2525 copied=copied.get(path))
2524 return mctx
2526 return mctx
2525 except KeyError:
2527 except KeyError:
2526 return None
2528 return None
2527 else:
2529 else:
2528 ui.note(_('copying changeset %s to %s\n') % (old, base))
2530 ui.note(_('copying changeset %s to %s\n') % (old, base))
2529
2531
2530 # Use version of files as in the old cset
2532 # Use version of files as in the old cset
2531 def filectxfn(repo, ctx_, path):
2533 def filectxfn(repo, ctx_, path):
2532 try:
2534 try:
2533 return old.filectx(path)
2535 return old.filectx(path)
2534 except KeyError:
2536 except KeyError:
2535 return None
2537 return None
2536
2538
2537 # See if we got a message from -m or -l, if not, open the editor with
2539 # See if we got a message from -m or -l, if not, open the editor with
2538 # the message of the changeset to amend.
2540 # the message of the changeset to amend.
2539 message = logmessage(ui, opts)
2541 message = logmessage(ui, opts)
2540
2542
2541 editform = mergeeditform(old, 'commit.amend')
2543 editform = mergeeditform(old, 'commit.amend')
2542 editor = getcommiteditor(editform=editform,
2544 editor = getcommiteditor(editform=editform,
2543 **pycompat.strkwargs(opts))
2545 **pycompat.strkwargs(opts))
2544
2546
2545 if not message:
2547 if not message:
2546 editor = getcommiteditor(edit=True, editform=editform)
2548 editor = getcommiteditor(edit=True, editform=editform)
2547 message = old.description()
2549 message = old.description()
2548
2550
2549 pureextra = extra.copy()
2551 pureextra = extra.copy()
2550 extra['amend_source'] = old.hex()
2552 extra['amend_source'] = old.hex()
2551
2553
2552 new = context.memctx(repo,
2554 new = context.memctx(repo,
2553 parents=[base.node(), old.p2().node()],
2555 parents=[base.node(), old.p2().node()],
2554 text=message,
2556 text=message,
2555 files=files,
2557 files=files,
2556 filectxfn=filectxfn,
2558 filectxfn=filectxfn,
2557 user=user,
2559 user=user,
2558 date=date,
2560 date=date,
2559 extra=extra,
2561 extra=extra,
2560 editor=editor)
2562 editor=editor)
2561
2563
2562 newdesc = changelog.stripdesc(new.description())
2564 newdesc = changelog.stripdesc(new.description())
2563 if ((not changes)
2565 if ((not changes)
2564 and newdesc == old.description()
2566 and newdesc == old.description()
2565 and user == old.user()
2567 and user == old.user()
2566 and (date == old.date() or datemaydiffer)
2568 and (date == old.date() or datemaydiffer)
2567 and pureextra == old.extra()):
2569 and pureextra == old.extra()):
2568 # nothing changed. continuing here would create a new node
2570 # nothing changed. continuing here would create a new node
2569 # anyway because of the amend_source noise.
2571 # anyway because of the amend_source noise.
2570 #
2572 #
2571 # This not what we expect from amend.
2573 # This not what we expect from amend.
2572 return old.node()
2574 return old.node()
2573
2575
2574 commitphase = None
2576 commitphase = None
2575 if opts.get('secret'):
2577 if opts.get('secret'):
2576 commitphase = phases.secret
2578 commitphase = phases.secret
2577 newid = repo.commitctx(new)
2579 newid = repo.commitctx(new)
2578
2580
2579 # Reroute the working copy parent to the new changeset
2581 # Reroute the working copy parent to the new changeset
2580 repo.setparents(newid, nullid)
2582 repo.setparents(newid, nullid)
2581 mapping = {old.node(): (newid,)}
2583 mapping = {old.node(): (newid,)}
2582 obsmetadata = None
2584 obsmetadata = None
2583 if opts.get('note'):
2585 if opts.get('note'):
2584 obsmetadata = {'note': encoding.fromlocal(opts['note'])}
2586 obsmetadata = {'note': encoding.fromlocal(opts['note'])}
2585 backup = ui.configbool('rewrite', 'backup-bundle')
2587 backup = ui.configbool('rewrite', 'backup-bundle')
2586 scmutil.cleanupnodes(repo, mapping, 'amend', metadata=obsmetadata,
2588 scmutil.cleanupnodes(repo, mapping, 'amend', metadata=obsmetadata,
2587 fixphase=True, targetphase=commitphase,
2589 fixphase=True, targetphase=commitphase,
2588 backup=backup)
2590 backup=backup)
2589
2591
2590 # Fixing the dirstate because localrepo.commitctx does not update
2592 # Fixing the dirstate because localrepo.commitctx does not update
2591 # it. This is rather convenient because we did not need to update
2593 # it. This is rather convenient because we did not need to update
2592 # the dirstate for all the files in the new commit which commitctx
2594 # the dirstate for all the files in the new commit which commitctx
2593 # could have done if it updated the dirstate. Now, we can
2595 # could have done if it updated the dirstate. Now, we can
2594 # selectively update the dirstate only for the amended files.
2596 # selectively update the dirstate only for the amended files.
2595 dirstate = repo.dirstate
2597 dirstate = repo.dirstate
2596
2598
2597 # Update the state of the files which were added and
2599 # Update the state of the files which were added and
2598 # and modified in the amend to "normal" in the dirstate.
2600 # and modified in the amend to "normal" in the dirstate.
2599 normalfiles = set(wctx.modified() + wctx.added()) & filestoamend
2601 normalfiles = set(wctx.modified() + wctx.added()) & filestoamend
2600 for f in normalfiles:
2602 for f in normalfiles:
2601 dirstate.normal(f)
2603 dirstate.normal(f)
2602
2604
2603 # Update the state of files which were removed in the amend
2605 # Update the state of files which were removed in the amend
2604 # to "removed" in the dirstate.
2606 # to "removed" in the dirstate.
2605 removedfiles = set(wctx.removed()) & filestoamend
2607 removedfiles = set(wctx.removed()) & filestoamend
2606 for f in removedfiles:
2608 for f in removedfiles:
2607 dirstate.drop(f)
2609 dirstate.drop(f)
2608
2610
2609 return newid
2611 return newid
2610
2612
2611 def commiteditor(repo, ctx, subs, editform=''):
2613 def commiteditor(repo, ctx, subs, editform=''):
2612 if ctx.description():
2614 if ctx.description():
2613 return ctx.description()
2615 return ctx.description()
2614 return commitforceeditor(repo, ctx, subs, editform=editform,
2616 return commitforceeditor(repo, ctx, subs, editform=editform,
2615 unchangedmessagedetection=True)
2617 unchangedmessagedetection=True)
2616
2618
2617 def commitforceeditor(repo, ctx, subs, finishdesc=None, extramsg=None,
2619 def commitforceeditor(repo, ctx, subs, finishdesc=None, extramsg=None,
2618 editform='', unchangedmessagedetection=False):
2620 editform='', unchangedmessagedetection=False):
2619 if not extramsg:
2621 if not extramsg:
2620 extramsg = _("Leave message empty to abort commit.")
2622 extramsg = _("Leave message empty to abort commit.")
2621
2623
2622 forms = [e for e in editform.split('.') if e]
2624 forms = [e for e in editform.split('.') if e]
2623 forms.insert(0, 'changeset')
2625 forms.insert(0, 'changeset')
2624 templatetext = None
2626 templatetext = None
2625 while forms:
2627 while forms:
2626 ref = '.'.join(forms)
2628 ref = '.'.join(forms)
2627 if repo.ui.config('committemplate', ref):
2629 if repo.ui.config('committemplate', ref):
2628 templatetext = committext = buildcommittemplate(
2630 templatetext = committext = buildcommittemplate(
2629 repo, ctx, subs, extramsg, ref)
2631 repo, ctx, subs, extramsg, ref)
2630 break
2632 break
2631 forms.pop()
2633 forms.pop()
2632 else:
2634 else:
2633 committext = buildcommittext(repo, ctx, subs, extramsg)
2635 committext = buildcommittext(repo, ctx, subs, extramsg)
2634
2636
2635 # run editor in the repository root
2637 # run editor in the repository root
2636 olddir = encoding.getcwd()
2638 olddir = encoding.getcwd()
2637 os.chdir(repo.root)
2639 os.chdir(repo.root)
2638
2640
2639 # make in-memory changes visible to external process
2641 # make in-memory changes visible to external process
2640 tr = repo.currenttransaction()
2642 tr = repo.currenttransaction()
2641 repo.dirstate.write(tr)
2643 repo.dirstate.write(tr)
2642 pending = tr and tr.writepending() and repo.root
2644 pending = tr and tr.writepending() and repo.root
2643
2645
2644 editortext = repo.ui.edit(committext, ctx.user(), ctx.extra(),
2646 editortext = repo.ui.edit(committext, ctx.user(), ctx.extra(),
2645 editform=editform, pending=pending,
2647 editform=editform, pending=pending,
2646 repopath=repo.path, action='commit')
2648 repopath=repo.path, action='commit')
2647 text = editortext
2649 text = editortext
2648
2650
2649 # strip away anything below this special string (used for editors that want
2651 # strip away anything below this special string (used for editors that want
2650 # to display the diff)
2652 # to display the diff)
2651 stripbelow = re.search(_linebelow, text, flags=re.MULTILINE)
2653 stripbelow = re.search(_linebelow, text, flags=re.MULTILINE)
2652 if stripbelow:
2654 if stripbelow:
2653 text = text[:stripbelow.start()]
2655 text = text[:stripbelow.start()]
2654
2656
2655 text = re.sub("(?m)^HG:.*(\n|$)", "", text)
2657 text = re.sub("(?m)^HG:.*(\n|$)", "", text)
2656 os.chdir(olddir)
2658 os.chdir(olddir)
2657
2659
2658 if finishdesc:
2660 if finishdesc:
2659 text = finishdesc(text)
2661 text = finishdesc(text)
2660 if not text.strip():
2662 if not text.strip():
2661 raise error.Abort(_("empty commit message"))
2663 raise error.Abort(_("empty commit message"))
2662 if unchangedmessagedetection and editortext == templatetext:
2664 if unchangedmessagedetection and editortext == templatetext:
2663 raise error.Abort(_("commit message unchanged"))
2665 raise error.Abort(_("commit message unchanged"))
2664
2666
2665 return text
2667 return text
2666
2668
2667 def buildcommittemplate(repo, ctx, subs, extramsg, ref):
2669 def buildcommittemplate(repo, ctx, subs, extramsg, ref):
2668 ui = repo.ui
2670 ui = repo.ui
2669 spec = formatter.templatespec(ref, None, None)
2671 spec = formatter.templatespec(ref, None, None)
2670 t = logcmdutil.changesettemplater(ui, repo, spec)
2672 t = logcmdutil.changesettemplater(ui, repo, spec)
2671 t.t.cache.update((k, templater.unquotestring(v))
2673 t.t.cache.update((k, templater.unquotestring(v))
2672 for k, v in repo.ui.configitems('committemplate'))
2674 for k, v in repo.ui.configitems('committemplate'))
2673
2675
2674 if not extramsg:
2676 if not extramsg:
2675 extramsg = '' # ensure that extramsg is string
2677 extramsg = '' # ensure that extramsg is string
2676
2678
2677 ui.pushbuffer()
2679 ui.pushbuffer()
2678 t.show(ctx, extramsg=extramsg)
2680 t.show(ctx, extramsg=extramsg)
2679 return ui.popbuffer()
2681 return ui.popbuffer()
2680
2682
2681 def hgprefix(msg):
2683 def hgprefix(msg):
2682 return "\n".join(["HG: %s" % a for a in msg.split("\n") if a])
2684 return "\n".join(["HG: %s" % a for a in msg.split("\n") if a])
2683
2685
2684 def buildcommittext(repo, ctx, subs, extramsg):
2686 def buildcommittext(repo, ctx, subs, extramsg):
2685 edittext = []
2687 edittext = []
2686 modified, added, removed = ctx.modified(), ctx.added(), ctx.removed()
2688 modified, added, removed = ctx.modified(), ctx.added(), ctx.removed()
2687 if ctx.description():
2689 if ctx.description():
2688 edittext.append(ctx.description())
2690 edittext.append(ctx.description())
2689 edittext.append("")
2691 edittext.append("")
2690 edittext.append("") # Empty line between message and comments.
2692 edittext.append("") # Empty line between message and comments.
2691 edittext.append(hgprefix(_("Enter commit message."
2693 edittext.append(hgprefix(_("Enter commit message."
2692 " Lines beginning with 'HG:' are removed.")))
2694 " Lines beginning with 'HG:' are removed.")))
2693 edittext.append(hgprefix(extramsg))
2695 edittext.append(hgprefix(extramsg))
2694 edittext.append("HG: --")
2696 edittext.append("HG: --")
2695 edittext.append(hgprefix(_("user: %s") % ctx.user()))
2697 edittext.append(hgprefix(_("user: %s") % ctx.user()))
2696 if ctx.p2():
2698 if ctx.p2():
2697 edittext.append(hgprefix(_("branch merge")))
2699 edittext.append(hgprefix(_("branch merge")))
2698 if ctx.branch():
2700 if ctx.branch():
2699 edittext.append(hgprefix(_("branch '%s'") % ctx.branch()))
2701 edittext.append(hgprefix(_("branch '%s'") % ctx.branch()))
2700 if bookmarks.isactivewdirparent(repo):
2702 if bookmarks.isactivewdirparent(repo):
2701 edittext.append(hgprefix(_("bookmark '%s'") % repo._activebookmark))
2703 edittext.append(hgprefix(_("bookmark '%s'") % repo._activebookmark))
2702 edittext.extend([hgprefix(_("subrepo %s") % s) for s in subs])
2704 edittext.extend([hgprefix(_("subrepo %s") % s) for s in subs])
2703 edittext.extend([hgprefix(_("added %s") % f) for f in added])
2705 edittext.extend([hgprefix(_("added %s") % f) for f in added])
2704 edittext.extend([hgprefix(_("changed %s") % f) for f in modified])
2706 edittext.extend([hgprefix(_("changed %s") % f) for f in modified])
2705 edittext.extend([hgprefix(_("removed %s") % f) for f in removed])
2707 edittext.extend([hgprefix(_("removed %s") % f) for f in removed])
2706 if not added and not modified and not removed:
2708 if not added and not modified and not removed:
2707 edittext.append(hgprefix(_("no files changed")))
2709 edittext.append(hgprefix(_("no files changed")))
2708 edittext.append("")
2710 edittext.append("")
2709
2711
2710 return "\n".join(edittext)
2712 return "\n".join(edittext)
2711
2713
2712 def commitstatus(repo, node, branch, bheads=None, opts=None):
2714 def commitstatus(repo, node, branch, bheads=None, opts=None):
2713 if opts is None:
2715 if opts is None:
2714 opts = {}
2716 opts = {}
2715 ctx = repo[node]
2717 ctx = repo[node]
2716 parents = ctx.parents()
2718 parents = ctx.parents()
2717
2719
2718 if (not opts.get('amend') and bheads and node not in bheads and not
2720 if (not opts.get('amend') and bheads and node not in bheads and not
2719 [x for x in parents if x.node() in bheads and x.branch() == branch]):
2721 [x for x in parents if x.node() in bheads and x.branch() == branch]):
2720 repo.ui.status(_('created new head\n'))
2722 repo.ui.status(_('created new head\n'))
2721 # The message is not printed for initial roots. For the other
2723 # The message is not printed for initial roots. For the other
2722 # changesets, it is printed in the following situations:
2724 # changesets, it is printed in the following situations:
2723 #
2725 #
2724 # Par column: for the 2 parents with ...
2726 # Par column: for the 2 parents with ...
2725 # N: null or no parent
2727 # N: null or no parent
2726 # B: parent is on another named branch
2728 # B: parent is on another named branch
2727 # C: parent is a regular non head changeset
2729 # C: parent is a regular non head changeset
2728 # H: parent was a branch head of the current branch
2730 # H: parent was a branch head of the current branch
2729 # Msg column: whether we print "created new head" message
2731 # Msg column: whether we print "created new head" message
2730 # In the following, it is assumed that there already exists some
2732 # In the following, it is assumed that there already exists some
2731 # initial branch heads of the current branch, otherwise nothing is
2733 # initial branch heads of the current branch, otherwise nothing is
2732 # printed anyway.
2734 # printed anyway.
2733 #
2735 #
2734 # Par Msg Comment
2736 # Par Msg Comment
2735 # N N y additional topo root
2737 # N N y additional topo root
2736 #
2738 #
2737 # B N y additional branch root
2739 # B N y additional branch root
2738 # C N y additional topo head
2740 # C N y additional topo head
2739 # H N n usual case
2741 # H N n usual case
2740 #
2742 #
2741 # B B y weird additional branch root
2743 # B B y weird additional branch root
2742 # C B y branch merge
2744 # C B y branch merge
2743 # H B n merge with named branch
2745 # H B n merge with named branch
2744 #
2746 #
2745 # C C y additional head from merge
2747 # C C y additional head from merge
2746 # C H n merge with a head
2748 # C H n merge with a head
2747 #
2749 #
2748 # H H n head merge: head count decreases
2750 # H H n head merge: head count decreases
2749
2751
2750 if not opts.get('close_branch'):
2752 if not opts.get('close_branch'):
2751 for r in parents:
2753 for r in parents:
2752 if r.closesbranch() and r.branch() == branch:
2754 if r.closesbranch() and r.branch() == branch:
2753 repo.ui.status(_('reopening closed branch head %d\n') % r.rev())
2755 repo.ui.status(_('reopening closed branch head %d\n') % r.rev())
2754
2756
2755 if repo.ui.debugflag:
2757 if repo.ui.debugflag:
2756 repo.ui.write(_('committed changeset %d:%s\n') % (ctx.rev(), ctx.hex()))
2758 repo.ui.write(_('committed changeset %d:%s\n') % (ctx.rev(), ctx.hex()))
2757 elif repo.ui.verbose:
2759 elif repo.ui.verbose:
2758 repo.ui.write(_('committed changeset %d:%s\n') % (ctx.rev(), ctx))
2760 repo.ui.write(_('committed changeset %d:%s\n') % (ctx.rev(), ctx))
2759
2761
2760 def postcommitstatus(repo, pats, opts):
2762 def postcommitstatus(repo, pats, opts):
2761 return repo.status(match=scmutil.match(repo[None], pats, opts))
2763 return repo.status(match=scmutil.match(repo[None], pats, opts))
2762
2764
2763 def revert(ui, repo, ctx, parents, *pats, **opts):
2765 def revert(ui, repo, ctx, parents, *pats, **opts):
2764 opts = pycompat.byteskwargs(opts)
2766 opts = pycompat.byteskwargs(opts)
2765 parent, p2 = parents
2767 parent, p2 = parents
2766 node = ctx.node()
2768 node = ctx.node()
2767
2769
2768 mf = ctx.manifest()
2770 mf = ctx.manifest()
2769 if node == p2:
2771 if node == p2:
2770 parent = p2
2772 parent = p2
2771
2773
2772 # need all matching names in dirstate and manifest of target rev,
2774 # need all matching names in dirstate and manifest of target rev,
2773 # so have to walk both. do not print errors if files exist in one
2775 # so have to walk both. do not print errors if files exist in one
2774 # but not other. in both cases, filesets should be evaluated against
2776 # but not other. in both cases, filesets should be evaluated against
2775 # workingctx to get consistent result (issue4497). this means 'set:**'
2777 # workingctx to get consistent result (issue4497). this means 'set:**'
2776 # cannot be used to select missing files from target rev.
2778 # cannot be used to select missing files from target rev.
2777
2779
2778 # `names` is a mapping for all elements in working copy and target revision
2780 # `names` is a mapping for all elements in working copy and target revision
2779 # The mapping is in the form:
2781 # The mapping is in the form:
2780 # <abs path in repo> -> (<path from CWD>, <exactly specified by matcher?>)
2782 # <abs path in repo> -> (<path from CWD>, <exactly specified by matcher?>)
2781 names = {}
2783 names = {}
2782
2784
2783 with repo.wlock():
2785 with repo.wlock():
2784 ## filling of the `names` mapping
2786 ## filling of the `names` mapping
2785 # walk dirstate to fill `names`
2787 # walk dirstate to fill `names`
2786
2788
2787 interactive = opts.get('interactive', False)
2789 interactive = opts.get('interactive', False)
2788 wctx = repo[None]
2790 wctx = repo[None]
2789 m = scmutil.match(wctx, pats, opts)
2791 m = scmutil.match(wctx, pats, opts)
2790
2792
2791 # we'll need this later
2793 # we'll need this later
2792 targetsubs = sorted(s for s in wctx.substate if m(s))
2794 targetsubs = sorted(s for s in wctx.substate if m(s))
2793
2795
2794 if not m.always():
2796 if not m.always():
2795 matcher = matchmod.badmatch(m, lambda x, y: False)
2797 matcher = matchmod.badmatch(m, lambda x, y: False)
2796 for abs in wctx.walk(matcher):
2798 for abs in wctx.walk(matcher):
2797 names[abs] = m.rel(abs), m.exact(abs)
2799 names[abs] = m.rel(abs), m.exact(abs)
2798
2800
2799 # walk target manifest to fill `names`
2801 # walk target manifest to fill `names`
2800
2802
2801 def badfn(path, msg):
2803 def badfn(path, msg):
2802 if path in names:
2804 if path in names:
2803 return
2805 return
2804 if path in ctx.substate:
2806 if path in ctx.substate:
2805 return
2807 return
2806 path_ = path + '/'
2808 path_ = path + '/'
2807 for f in names:
2809 for f in names:
2808 if f.startswith(path_):
2810 if f.startswith(path_):
2809 return
2811 return
2810 ui.warn("%s: %s\n" % (m.rel(path), msg))
2812 ui.warn("%s: %s\n" % (m.rel(path), msg))
2811
2813
2812 for abs in ctx.walk(matchmod.badmatch(m, badfn)):
2814 for abs in ctx.walk(matchmod.badmatch(m, badfn)):
2813 if abs not in names:
2815 if abs not in names:
2814 names[abs] = m.rel(abs), m.exact(abs)
2816 names[abs] = m.rel(abs), m.exact(abs)
2815
2817
2816 # Find status of all file in `names`.
2818 # Find status of all file in `names`.
2817 m = scmutil.matchfiles(repo, names)
2819 m = scmutil.matchfiles(repo, names)
2818
2820
2819 changes = repo.status(node1=node, match=m,
2821 changes = repo.status(node1=node, match=m,
2820 unknown=True, ignored=True, clean=True)
2822 unknown=True, ignored=True, clean=True)
2821 else:
2823 else:
2822 changes = repo.status(node1=node, match=m)
2824 changes = repo.status(node1=node, match=m)
2823 for kind in changes:
2825 for kind in changes:
2824 for abs in kind:
2826 for abs in kind:
2825 names[abs] = m.rel(abs), m.exact(abs)
2827 names[abs] = m.rel(abs), m.exact(abs)
2826
2828
2827 m = scmutil.matchfiles(repo, names)
2829 m = scmutil.matchfiles(repo, names)
2828
2830
2829 modified = set(changes.modified)
2831 modified = set(changes.modified)
2830 added = set(changes.added)
2832 added = set(changes.added)
2831 removed = set(changes.removed)
2833 removed = set(changes.removed)
2832 _deleted = set(changes.deleted)
2834 _deleted = set(changes.deleted)
2833 unknown = set(changes.unknown)
2835 unknown = set(changes.unknown)
2834 unknown.update(changes.ignored)
2836 unknown.update(changes.ignored)
2835 clean = set(changes.clean)
2837 clean = set(changes.clean)
2836 modadded = set()
2838 modadded = set()
2837
2839
2838 # We need to account for the state of the file in the dirstate,
2840 # We need to account for the state of the file in the dirstate,
2839 # even when we revert against something else than parent. This will
2841 # even when we revert against something else than parent. This will
2840 # slightly alter the behavior of revert (doing back up or not, delete
2842 # slightly alter the behavior of revert (doing back up or not, delete
2841 # or just forget etc).
2843 # or just forget etc).
2842 if parent == node:
2844 if parent == node:
2843 dsmodified = modified
2845 dsmodified = modified
2844 dsadded = added
2846 dsadded = added
2845 dsremoved = removed
2847 dsremoved = removed
2846 # store all local modifications, useful later for rename detection
2848 # store all local modifications, useful later for rename detection
2847 localchanges = dsmodified | dsadded
2849 localchanges = dsmodified | dsadded
2848 modified, added, removed = set(), set(), set()
2850 modified, added, removed = set(), set(), set()
2849 else:
2851 else:
2850 changes = repo.status(node1=parent, match=m)
2852 changes = repo.status(node1=parent, match=m)
2851 dsmodified = set(changes.modified)
2853 dsmodified = set(changes.modified)
2852 dsadded = set(changes.added)
2854 dsadded = set(changes.added)
2853 dsremoved = set(changes.removed)
2855 dsremoved = set(changes.removed)
2854 # store all local modifications, useful later for rename detection
2856 # store all local modifications, useful later for rename detection
2855 localchanges = dsmodified | dsadded
2857 localchanges = dsmodified | dsadded
2856
2858
2857 # only take into account for removes between wc and target
2859 # only take into account for removes between wc and target
2858 clean |= dsremoved - removed
2860 clean |= dsremoved - removed
2859 dsremoved &= removed
2861 dsremoved &= removed
2860 # distinct between dirstate remove and other
2862 # distinct between dirstate remove and other
2861 removed -= dsremoved
2863 removed -= dsremoved
2862
2864
2863 modadded = added & dsmodified
2865 modadded = added & dsmodified
2864 added -= modadded
2866 added -= modadded
2865
2867
2866 # tell newly modified apart.
2868 # tell newly modified apart.
2867 dsmodified &= modified
2869 dsmodified &= modified
2868 dsmodified |= modified & dsadded # dirstate added may need backup
2870 dsmodified |= modified & dsadded # dirstate added may need backup
2869 modified -= dsmodified
2871 modified -= dsmodified
2870
2872
2871 # We need to wait for some post-processing to update this set
2873 # We need to wait for some post-processing to update this set
2872 # before making the distinction. The dirstate will be used for
2874 # before making the distinction. The dirstate will be used for
2873 # that purpose.
2875 # that purpose.
2874 dsadded = added
2876 dsadded = added
2875
2877
2876 # in case of merge, files that are actually added can be reported as
2878 # in case of merge, files that are actually added can be reported as
2877 # modified, we need to post process the result
2879 # modified, we need to post process the result
2878 if p2 != nullid:
2880 if p2 != nullid:
2879 mergeadd = set(dsmodified)
2881 mergeadd = set(dsmodified)
2880 for path in dsmodified:
2882 for path in dsmodified:
2881 if path in mf:
2883 if path in mf:
2882 mergeadd.remove(path)
2884 mergeadd.remove(path)
2883 dsadded |= mergeadd
2885 dsadded |= mergeadd
2884 dsmodified -= mergeadd
2886 dsmodified -= mergeadd
2885
2887
2886 # if f is a rename, update `names` to also revert the source
2888 # if f is a rename, update `names` to also revert the source
2887 cwd = repo.getcwd()
2889 cwd = repo.getcwd()
2888 for f in localchanges:
2890 for f in localchanges:
2889 src = repo.dirstate.copied(f)
2891 src = repo.dirstate.copied(f)
2890 # XXX should we check for rename down to target node?
2892 # XXX should we check for rename down to target node?
2891 if src and src not in names and repo.dirstate[src] == 'r':
2893 if src and src not in names and repo.dirstate[src] == 'r':
2892 dsremoved.add(src)
2894 dsremoved.add(src)
2893 names[src] = (repo.pathto(src, cwd), True)
2895 names[src] = (repo.pathto(src, cwd), True)
2894
2896
2895 # determine the exact nature of the deleted changesets
2897 # determine the exact nature of the deleted changesets
2896 deladded = set(_deleted)
2898 deladded = set(_deleted)
2897 for path in _deleted:
2899 for path in _deleted:
2898 if path in mf:
2900 if path in mf:
2899 deladded.remove(path)
2901 deladded.remove(path)
2900 deleted = _deleted - deladded
2902 deleted = _deleted - deladded
2901
2903
2902 # distinguish between file to forget and the other
2904 # distinguish between file to forget and the other
2903 added = set()
2905 added = set()
2904 for abs in dsadded:
2906 for abs in dsadded:
2905 if repo.dirstate[abs] != 'a':
2907 if repo.dirstate[abs] != 'a':
2906 added.add(abs)
2908 added.add(abs)
2907 dsadded -= added
2909 dsadded -= added
2908
2910
2909 for abs in deladded:
2911 for abs in deladded:
2910 if repo.dirstate[abs] == 'a':
2912 if repo.dirstate[abs] == 'a':
2911 dsadded.add(abs)
2913 dsadded.add(abs)
2912 deladded -= dsadded
2914 deladded -= dsadded
2913
2915
2914 # For files marked as removed, we check if an unknown file is present at
2916 # For files marked as removed, we check if an unknown file is present at
2915 # the same path. If a such file exists it may need to be backed up.
2917 # the same path. If a such file exists it may need to be backed up.
2916 # Making the distinction at this stage helps have simpler backup
2918 # Making the distinction at this stage helps have simpler backup
2917 # logic.
2919 # logic.
2918 removunk = set()
2920 removunk = set()
2919 for abs in removed:
2921 for abs in removed:
2920 target = repo.wjoin(abs)
2922 target = repo.wjoin(abs)
2921 if os.path.lexists(target):
2923 if os.path.lexists(target):
2922 removunk.add(abs)
2924 removunk.add(abs)
2923 removed -= removunk
2925 removed -= removunk
2924
2926
2925 dsremovunk = set()
2927 dsremovunk = set()
2926 for abs in dsremoved:
2928 for abs in dsremoved:
2927 target = repo.wjoin(abs)
2929 target = repo.wjoin(abs)
2928 if os.path.lexists(target):
2930 if os.path.lexists(target):
2929 dsremovunk.add(abs)
2931 dsremovunk.add(abs)
2930 dsremoved -= dsremovunk
2932 dsremoved -= dsremovunk
2931
2933
2932 # action to be actually performed by revert
2934 # action to be actually performed by revert
2933 # (<list of file>, message>) tuple
2935 # (<list of file>, message>) tuple
2934 actions = {'revert': ([], _('reverting %s\n')),
2936 actions = {'revert': ([], _('reverting %s\n')),
2935 'add': ([], _('adding %s\n')),
2937 'add': ([], _('adding %s\n')),
2936 'remove': ([], _('removing %s\n')),
2938 'remove': ([], _('removing %s\n')),
2937 'drop': ([], _('removing %s\n')),
2939 'drop': ([], _('removing %s\n')),
2938 'forget': ([], _('forgetting %s\n')),
2940 'forget': ([], _('forgetting %s\n')),
2939 'undelete': ([], _('undeleting %s\n')),
2941 'undelete': ([], _('undeleting %s\n')),
2940 'noop': (None, _('no changes needed to %s\n')),
2942 'noop': (None, _('no changes needed to %s\n')),
2941 'unknown': (None, _('file not managed: %s\n')),
2943 'unknown': (None, _('file not managed: %s\n')),
2942 }
2944 }
2943
2945
2944 # "constant" that convey the backup strategy.
2946 # "constant" that convey the backup strategy.
2945 # All set to `discard` if `no-backup` is set do avoid checking
2947 # All set to `discard` if `no-backup` is set do avoid checking
2946 # no_backup lower in the code.
2948 # no_backup lower in the code.
2947 # These values are ordered for comparison purposes
2949 # These values are ordered for comparison purposes
2948 backupinteractive = 3 # do backup if interactively modified
2950 backupinteractive = 3 # do backup if interactively modified
2949 backup = 2 # unconditionally do backup
2951 backup = 2 # unconditionally do backup
2950 check = 1 # check if the existing file differs from target
2952 check = 1 # check if the existing file differs from target
2951 discard = 0 # never do backup
2953 discard = 0 # never do backup
2952 if opts.get('no_backup'):
2954 if opts.get('no_backup'):
2953 backupinteractive = backup = check = discard
2955 backupinteractive = backup = check = discard
2954 if interactive:
2956 if interactive:
2955 dsmodifiedbackup = backupinteractive
2957 dsmodifiedbackup = backupinteractive
2956 else:
2958 else:
2957 dsmodifiedbackup = backup
2959 dsmodifiedbackup = backup
2958 tobackup = set()
2960 tobackup = set()
2959
2961
2960 backupanddel = actions['remove']
2962 backupanddel = actions['remove']
2961 if not opts.get('no_backup'):
2963 if not opts.get('no_backup'):
2962 backupanddel = actions['drop']
2964 backupanddel = actions['drop']
2963
2965
2964 disptable = (
2966 disptable = (
2965 # dispatch table:
2967 # dispatch table:
2966 # file state
2968 # file state
2967 # action
2969 # action
2968 # make backup
2970 # make backup
2969
2971
2970 ## Sets that results that will change file on disk
2972 ## Sets that results that will change file on disk
2971 # Modified compared to target, no local change
2973 # Modified compared to target, no local change
2972 (modified, actions['revert'], discard),
2974 (modified, actions['revert'], discard),
2973 # Modified compared to target, but local file is deleted
2975 # Modified compared to target, but local file is deleted
2974 (deleted, actions['revert'], discard),
2976 (deleted, actions['revert'], discard),
2975 # Modified compared to target, local change
2977 # Modified compared to target, local change
2976 (dsmodified, actions['revert'], dsmodifiedbackup),
2978 (dsmodified, actions['revert'], dsmodifiedbackup),
2977 # Added since target
2979 # Added since target
2978 (added, actions['remove'], discard),
2980 (added, actions['remove'], discard),
2979 # Added in working directory
2981 # Added in working directory
2980 (dsadded, actions['forget'], discard),
2982 (dsadded, actions['forget'], discard),
2981 # Added since target, have local modification
2983 # Added since target, have local modification
2982 (modadded, backupanddel, backup),
2984 (modadded, backupanddel, backup),
2983 # Added since target but file is missing in working directory
2985 # Added since target but file is missing in working directory
2984 (deladded, actions['drop'], discard),
2986 (deladded, actions['drop'], discard),
2985 # Removed since target, before working copy parent
2987 # Removed since target, before working copy parent
2986 (removed, actions['add'], discard),
2988 (removed, actions['add'], discard),
2987 # Same as `removed` but an unknown file exists at the same path
2989 # Same as `removed` but an unknown file exists at the same path
2988 (removunk, actions['add'], check),
2990 (removunk, actions['add'], check),
2989 # Removed since targe, marked as such in working copy parent
2991 # Removed since targe, marked as such in working copy parent
2990 (dsremoved, actions['undelete'], discard),
2992 (dsremoved, actions['undelete'], discard),
2991 # Same as `dsremoved` but an unknown file exists at the same path
2993 # Same as `dsremoved` but an unknown file exists at the same path
2992 (dsremovunk, actions['undelete'], check),
2994 (dsremovunk, actions['undelete'], check),
2993 ## the following sets does not result in any file changes
2995 ## the following sets does not result in any file changes
2994 # File with no modification
2996 # File with no modification
2995 (clean, actions['noop'], discard),
2997 (clean, actions['noop'], discard),
2996 # Existing file, not tracked anywhere
2998 # Existing file, not tracked anywhere
2997 (unknown, actions['unknown'], discard),
2999 (unknown, actions['unknown'], discard),
2998 )
3000 )
2999
3001
3000 for abs, (rel, exact) in sorted(names.items()):
3002 for abs, (rel, exact) in sorted(names.items()):
3001 # target file to be touch on disk (relative to cwd)
3003 # target file to be touch on disk (relative to cwd)
3002 target = repo.wjoin(abs)
3004 target = repo.wjoin(abs)
3003 # search the entry in the dispatch table.
3005 # search the entry in the dispatch table.
3004 # if the file is in any of these sets, it was touched in the working
3006 # if the file is in any of these sets, it was touched in the working
3005 # directory parent and we are sure it needs to be reverted.
3007 # directory parent and we are sure it needs to be reverted.
3006 for table, (xlist, msg), dobackup in disptable:
3008 for table, (xlist, msg), dobackup in disptable:
3007 if abs not in table:
3009 if abs not in table:
3008 continue
3010 continue
3009 if xlist is not None:
3011 if xlist is not None:
3010 xlist.append(abs)
3012 xlist.append(abs)
3011 if dobackup:
3013 if dobackup:
3012 # If in interactive mode, don't automatically create
3014 # If in interactive mode, don't automatically create
3013 # .orig files (issue4793)
3015 # .orig files (issue4793)
3014 if dobackup == backupinteractive:
3016 if dobackup == backupinteractive:
3015 tobackup.add(abs)
3017 tobackup.add(abs)
3016 elif (backup <= dobackup or wctx[abs].cmp(ctx[abs])):
3018 elif (backup <= dobackup or wctx[abs].cmp(ctx[abs])):
3017 bakname = scmutil.origpath(ui, repo, rel)
3019 bakname = scmutil.origpath(ui, repo, rel)
3018 ui.note(_('saving current version of %s as %s\n') %
3020 ui.note(_('saving current version of %s as %s\n') %
3019 (rel, bakname))
3021 (rel, bakname))
3020 if not opts.get('dry_run'):
3022 if not opts.get('dry_run'):
3021 if interactive:
3023 if interactive:
3022 util.copyfile(target, bakname)
3024 util.copyfile(target, bakname)
3023 else:
3025 else:
3024 util.rename(target, bakname)
3026 util.rename(target, bakname)
3025 if opts.get('dry_run'):
3027 if opts.get('dry_run'):
3026 if ui.verbose or not exact:
3028 if ui.verbose or not exact:
3027 ui.status(msg % rel)
3029 ui.status(msg % rel)
3028 elif exact:
3030 elif exact:
3029 ui.warn(msg % rel)
3031 ui.warn(msg % rel)
3030 break
3032 break
3031
3033
3032 if not opts.get('dry_run'):
3034 if not opts.get('dry_run'):
3033 needdata = ('revert', 'add', 'undelete')
3035 needdata = ('revert', 'add', 'undelete')
3034 oplist = [actions[name][0] for name in needdata]
3036 oplist = [actions[name][0] for name in needdata]
3035 prefetch = scmutil.prefetchfiles
3037 prefetch = scmutil.prefetchfiles
3036 matchfiles = scmutil.matchfiles
3038 matchfiles = scmutil.matchfiles
3037 prefetch(repo, [ctx.rev()],
3039 prefetch(repo, [ctx.rev()],
3038 matchfiles(repo,
3040 matchfiles(repo,
3039 [f for sublist in oplist for f in sublist]))
3041 [f for sublist in oplist for f in sublist]))
3040 _performrevert(repo, parents, ctx, names, actions, interactive,
3042 _performrevert(repo, parents, ctx, names, actions, interactive,
3041 tobackup)
3043 tobackup)
3042
3044
3043 if targetsubs:
3045 if targetsubs:
3044 # Revert the subrepos on the revert list
3046 # Revert the subrepos on the revert list
3045 for sub in targetsubs:
3047 for sub in targetsubs:
3046 try:
3048 try:
3047 wctx.sub(sub).revert(ctx.substate[sub], *pats,
3049 wctx.sub(sub).revert(ctx.substate[sub], *pats,
3048 **pycompat.strkwargs(opts))
3050 **pycompat.strkwargs(opts))
3049 except KeyError:
3051 except KeyError:
3050 raise error.Abort("subrepository '%s' does not exist in %s!"
3052 raise error.Abort("subrepository '%s' does not exist in %s!"
3051 % (sub, short(ctx.node())))
3053 % (sub, short(ctx.node())))
3052
3054
3053 def _performrevert(repo, parents, ctx, names, actions, interactive=False,
3055 def _performrevert(repo, parents, ctx, names, actions, interactive=False,
3054 tobackup=None):
3056 tobackup=None):
3055 """function that actually perform all the actions computed for revert
3057 """function that actually perform all the actions computed for revert
3056
3058
3057 This is an independent function to let extension to plug in and react to
3059 This is an independent function to let extension to plug in and react to
3058 the imminent revert.
3060 the imminent revert.
3059
3061
3060 Make sure you have the working directory locked when calling this function.
3062 Make sure you have the working directory locked when calling this function.
3061 """
3063 """
3062 parent, p2 = parents
3064 parent, p2 = parents
3063 node = ctx.node()
3065 node = ctx.node()
3064 excluded_files = []
3066 excluded_files = []
3065
3067
3066 def checkout(f):
3068 def checkout(f):
3067 fc = ctx[f]
3069 fc = ctx[f]
3068 repo.wwrite(f, fc.data(), fc.flags())
3070 repo.wwrite(f, fc.data(), fc.flags())
3069
3071
3070 def doremove(f):
3072 def doremove(f):
3071 try:
3073 try:
3072 rmdir = repo.ui.configbool('experimental', 'removeemptydirs')
3074 rmdir = repo.ui.configbool('experimental', 'removeemptydirs')
3073 repo.wvfs.unlinkpath(f, rmdir=rmdir)
3075 repo.wvfs.unlinkpath(f, rmdir=rmdir)
3074 except OSError:
3076 except OSError:
3075 pass
3077 pass
3076 repo.dirstate.remove(f)
3078 repo.dirstate.remove(f)
3077
3079
3078 def prntstatusmsg(action, f):
3080 def prntstatusmsg(action, f):
3079 rel, exact = names[f]
3081 rel, exact = names[f]
3080 if repo.ui.verbose or not exact:
3082 if repo.ui.verbose or not exact:
3081 repo.ui.status(actions[action][1] % rel)
3083 repo.ui.status(actions[action][1] % rel)
3082
3084
3083 audit_path = pathutil.pathauditor(repo.root, cached=True)
3085 audit_path = pathutil.pathauditor(repo.root, cached=True)
3084 for f in actions['forget'][0]:
3086 for f in actions['forget'][0]:
3085 if interactive:
3087 if interactive:
3086 choice = repo.ui.promptchoice(
3088 choice = repo.ui.promptchoice(
3087 _("forget added file %s (Yn)?$$ &Yes $$ &No") % f)
3089 _("forget added file %s (Yn)?$$ &Yes $$ &No") % f)
3088 if choice == 0:
3090 if choice == 0:
3089 prntstatusmsg('forget', f)
3091 prntstatusmsg('forget', f)
3090 repo.dirstate.drop(f)
3092 repo.dirstate.drop(f)
3091 else:
3093 else:
3092 excluded_files.append(f)
3094 excluded_files.append(f)
3093 else:
3095 else:
3094 prntstatusmsg('forget', f)
3096 prntstatusmsg('forget', f)
3095 repo.dirstate.drop(f)
3097 repo.dirstate.drop(f)
3096 for f in actions['remove'][0]:
3098 for f in actions['remove'][0]:
3097 audit_path(f)
3099 audit_path(f)
3098 if interactive:
3100 if interactive:
3099 choice = repo.ui.promptchoice(
3101 choice = repo.ui.promptchoice(
3100 _("remove added file %s (Yn)?$$ &Yes $$ &No") % f)
3102 _("remove added file %s (Yn)?$$ &Yes $$ &No") % f)
3101 if choice == 0:
3103 if choice == 0:
3102 prntstatusmsg('remove', f)
3104 prntstatusmsg('remove', f)
3103 doremove(f)
3105 doremove(f)
3104 else:
3106 else:
3105 excluded_files.append(f)
3107 excluded_files.append(f)
3106 else:
3108 else:
3107 prntstatusmsg('remove', f)
3109 prntstatusmsg('remove', f)
3108 doremove(f)
3110 doremove(f)
3109 for f in actions['drop'][0]:
3111 for f in actions['drop'][0]:
3110 audit_path(f)
3112 audit_path(f)
3111 prntstatusmsg('drop', f)
3113 prntstatusmsg('drop', f)
3112 repo.dirstate.remove(f)
3114 repo.dirstate.remove(f)
3113
3115
3114 normal = None
3116 normal = None
3115 if node == parent:
3117 if node == parent:
3116 # We're reverting to our parent. If possible, we'd like status
3118 # We're reverting to our parent. If possible, we'd like status
3117 # to report the file as clean. We have to use normallookup for
3119 # to report the file as clean. We have to use normallookup for
3118 # merges to avoid losing information about merged/dirty files.
3120 # merges to avoid losing information about merged/dirty files.
3119 if p2 != nullid:
3121 if p2 != nullid:
3120 normal = repo.dirstate.normallookup
3122 normal = repo.dirstate.normallookup
3121 else:
3123 else:
3122 normal = repo.dirstate.normal
3124 normal = repo.dirstate.normal
3123
3125
3124 newlyaddedandmodifiedfiles = set()
3126 newlyaddedandmodifiedfiles = set()
3125 if interactive:
3127 if interactive:
3126 # Prompt the user for changes to revert
3128 # Prompt the user for changes to revert
3127 torevert = [f for f in actions['revert'][0] if f not in excluded_files]
3129 torevert = [f for f in actions['revert'][0] if f not in excluded_files]
3128 m = scmutil.matchfiles(repo, torevert)
3130 m = scmutil.matchfiles(repo, torevert)
3129 diffopts = patch.difffeatureopts(repo.ui)
3131 diffopts = patch.difffeatureopts(repo.ui, whitespace=True,
3132 section='commands',
3133 configprefix='revert.interactive.')
3130 diffopts.nodates = True
3134 diffopts.nodates = True
3131 diffopts.git = True
3135 diffopts.git = True
3132 operation = 'discard'
3136 operation = 'discard'
3133 reversehunks = True
3137 reversehunks = True
3134 if node != parent:
3138 if node != parent:
3135 operation = 'apply'
3139 operation = 'apply'
3136 reversehunks = False
3140 reversehunks = False
3137 if reversehunks:
3141 if reversehunks:
3138 diff = patch.diff(repo, ctx.node(), None, m, opts=diffopts)
3142 diff = patch.diff(repo, ctx.node(), None, m, opts=diffopts)
3139 else:
3143 else:
3140 diff = patch.diff(repo, None, ctx.node(), m, opts=diffopts)
3144 diff = patch.diff(repo, None, ctx.node(), m, opts=diffopts)
3141 originalchunks = patch.parsepatch(diff)
3145 originalchunks = patch.parsepatch(diff)
3142
3146
3143 try:
3147 try:
3144
3148
3145 chunks, opts = recordfilter(repo.ui, originalchunks,
3149 chunks, opts = recordfilter(repo.ui, originalchunks,
3146 operation=operation)
3150 operation=operation)
3147 if reversehunks:
3151 if reversehunks:
3148 chunks = patch.reversehunks(chunks)
3152 chunks = patch.reversehunks(chunks)
3149
3153
3150 except error.PatchError as err:
3154 except error.PatchError as err:
3151 raise error.Abort(_('error parsing patch: %s') % err)
3155 raise error.Abort(_('error parsing patch: %s') % err)
3152
3156
3153 newlyaddedandmodifiedfiles = newandmodified(chunks, originalchunks)
3157 newlyaddedandmodifiedfiles = newandmodified(chunks, originalchunks)
3154 if tobackup is None:
3158 if tobackup is None:
3155 tobackup = set()
3159 tobackup = set()
3156 # Apply changes
3160 # Apply changes
3157 fp = stringio()
3161 fp = stringio()
3158 # chunks are serialized per file, but files aren't sorted
3162 # chunks are serialized per file, but files aren't sorted
3159 for f in sorted(set(c.header.filename() for c in chunks if ishunk(c))):
3163 for f in sorted(set(c.header.filename() for c in chunks if ishunk(c))):
3160 prntstatusmsg('revert', f)
3164 prntstatusmsg('revert', f)
3161 for c in chunks:
3165 for c in chunks:
3162 if ishunk(c):
3166 if ishunk(c):
3163 abs = c.header.filename()
3167 abs = c.header.filename()
3164 # Create a backup file only if this hunk should be backed up
3168 # Create a backup file only if this hunk should be backed up
3165 if c.header.filename() in tobackup:
3169 if c.header.filename() in tobackup:
3166 target = repo.wjoin(abs)
3170 target = repo.wjoin(abs)
3167 bakname = scmutil.origpath(repo.ui, repo, m.rel(abs))
3171 bakname = scmutil.origpath(repo.ui, repo, m.rel(abs))
3168 util.copyfile(target, bakname)
3172 util.copyfile(target, bakname)
3169 tobackup.remove(abs)
3173 tobackup.remove(abs)
3170 c.write(fp)
3174 c.write(fp)
3171 dopatch = fp.tell()
3175 dopatch = fp.tell()
3172 fp.seek(0)
3176 fp.seek(0)
3173 if dopatch:
3177 if dopatch:
3174 try:
3178 try:
3175 patch.internalpatch(repo.ui, repo, fp, 1, eolmode=None)
3179 patch.internalpatch(repo.ui, repo, fp, 1, eolmode=None)
3176 except error.PatchError as err:
3180 except error.PatchError as err:
3177 raise error.Abort(pycompat.bytestr(err))
3181 raise error.Abort(pycompat.bytestr(err))
3178 del fp
3182 del fp
3179 else:
3183 else:
3180 for f in actions['revert'][0]:
3184 for f in actions['revert'][0]:
3181 prntstatusmsg('revert', f)
3185 prntstatusmsg('revert', f)
3182 checkout(f)
3186 checkout(f)
3183 if normal:
3187 if normal:
3184 normal(f)
3188 normal(f)
3185
3189
3186 for f in actions['add'][0]:
3190 for f in actions['add'][0]:
3187 # Don't checkout modified files, they are already created by the diff
3191 # Don't checkout modified files, they are already created by the diff
3188 if f not in newlyaddedandmodifiedfiles:
3192 if f not in newlyaddedandmodifiedfiles:
3189 prntstatusmsg('add', f)
3193 prntstatusmsg('add', f)
3190 checkout(f)
3194 checkout(f)
3191 repo.dirstate.add(f)
3195 repo.dirstate.add(f)
3192
3196
3193 normal = repo.dirstate.normallookup
3197 normal = repo.dirstate.normallookup
3194 if node == parent and p2 == nullid:
3198 if node == parent and p2 == nullid:
3195 normal = repo.dirstate.normal
3199 normal = repo.dirstate.normal
3196 for f in actions['undelete'][0]:
3200 for f in actions['undelete'][0]:
3197 if interactive:
3201 if interactive:
3198 choice = repo.ui.promptchoice(
3202 choice = repo.ui.promptchoice(
3199 _("add back removed file %s (Yn)?$$ &Yes $$ &No") % f)
3203 _("add back removed file %s (Yn)?$$ &Yes $$ &No") % f)
3200 if choice == 0:
3204 if choice == 0:
3201 prntstatusmsg('undelete', f)
3205 prntstatusmsg('undelete', f)
3202 checkout(f)
3206 checkout(f)
3203 normal(f)
3207 normal(f)
3204 else:
3208 else:
3205 excluded_files.append(f)
3209 excluded_files.append(f)
3206 else:
3210 else:
3207 prntstatusmsg('undelete', f)
3211 prntstatusmsg('undelete', f)
3208 checkout(f)
3212 checkout(f)
3209 normal(f)
3213 normal(f)
3210
3214
3211 copied = copies.pathcopies(repo[parent], ctx)
3215 copied = copies.pathcopies(repo[parent], ctx)
3212
3216
3213 for f in actions['add'][0] + actions['undelete'][0] + actions['revert'][0]:
3217 for f in actions['add'][0] + actions['undelete'][0] + actions['revert'][0]:
3214 if f in copied:
3218 if f in copied:
3215 repo.dirstate.copy(copied[f], f)
3219 repo.dirstate.copy(copied[f], f)
3216
3220
3217 # a list of (ui, repo, otherpeer, opts, missing) functions called by
3221 # a list of (ui, repo, otherpeer, opts, missing) functions called by
3218 # commands.outgoing. "missing" is "missing" of the result of
3222 # commands.outgoing. "missing" is "missing" of the result of
3219 # "findcommonoutgoing()"
3223 # "findcommonoutgoing()"
3220 outgoinghooks = util.hooks()
3224 outgoinghooks = util.hooks()
3221
3225
3222 # a list of (ui, repo) functions called by commands.summary
3226 # a list of (ui, repo) functions called by commands.summary
3223 summaryhooks = util.hooks()
3227 summaryhooks = util.hooks()
3224
3228
3225 # a list of (ui, repo, opts, changes) functions called by commands.summary.
3229 # a list of (ui, repo, opts, changes) functions called by commands.summary.
3226 #
3230 #
3227 # functions should return tuple of booleans below, if 'changes' is None:
3231 # functions should return tuple of booleans below, if 'changes' is None:
3228 # (whether-incomings-are-needed, whether-outgoings-are-needed)
3232 # (whether-incomings-are-needed, whether-outgoings-are-needed)
3229 #
3233 #
3230 # otherwise, 'changes' is a tuple of tuples below:
3234 # otherwise, 'changes' is a tuple of tuples below:
3231 # - (sourceurl, sourcebranch, sourcepeer, incoming)
3235 # - (sourceurl, sourcebranch, sourcepeer, incoming)
3232 # - (desturl, destbranch, destpeer, outgoing)
3236 # - (desturl, destbranch, destpeer, outgoing)
3233 summaryremotehooks = util.hooks()
3237 summaryremotehooks = util.hooks()
3234
3238
3235 # A list of state files kept by multistep operations like graft.
3239 # A list of state files kept by multistep operations like graft.
3236 # Since graft cannot be aborted, it is considered 'clearable' by update.
3240 # Since graft cannot be aborted, it is considered 'clearable' by update.
3237 # note: bisect is intentionally excluded
3241 # note: bisect is intentionally excluded
3238 # (state file, clearable, allowcommit, error, hint)
3242 # (state file, clearable, allowcommit, error, hint)
3239 unfinishedstates = [
3243 unfinishedstates = [
3240 ('graftstate', True, False, _('graft in progress'),
3244 ('graftstate', True, False, _('graft in progress'),
3241 _("use 'hg graft --continue' or 'hg graft --stop' to stop")),
3245 _("use 'hg graft --continue' or 'hg graft --stop' to stop")),
3242 ('updatestate', True, False, _('last update was interrupted'),
3246 ('updatestate', True, False, _('last update was interrupted'),
3243 _("use 'hg update' to get a consistent checkout"))
3247 _("use 'hg update' to get a consistent checkout"))
3244 ]
3248 ]
3245
3249
3246 def checkunfinished(repo, commit=False):
3250 def checkunfinished(repo, commit=False):
3247 '''Look for an unfinished multistep operation, like graft, and abort
3251 '''Look for an unfinished multistep operation, like graft, and abort
3248 if found. It's probably good to check this right before
3252 if found. It's probably good to check this right before
3249 bailifchanged().
3253 bailifchanged().
3250 '''
3254 '''
3251 # Check for non-clearable states first, so things like rebase will take
3255 # Check for non-clearable states first, so things like rebase will take
3252 # precedence over update.
3256 # precedence over update.
3253 for f, clearable, allowcommit, msg, hint in unfinishedstates:
3257 for f, clearable, allowcommit, msg, hint in unfinishedstates:
3254 if clearable or (commit and allowcommit):
3258 if clearable or (commit and allowcommit):
3255 continue
3259 continue
3256 if repo.vfs.exists(f):
3260 if repo.vfs.exists(f):
3257 raise error.Abort(msg, hint=hint)
3261 raise error.Abort(msg, hint=hint)
3258
3262
3259 for f, clearable, allowcommit, msg, hint in unfinishedstates:
3263 for f, clearable, allowcommit, msg, hint in unfinishedstates:
3260 if not clearable or (commit and allowcommit):
3264 if not clearable or (commit and allowcommit):
3261 continue
3265 continue
3262 if repo.vfs.exists(f):
3266 if repo.vfs.exists(f):
3263 raise error.Abort(msg, hint=hint)
3267 raise error.Abort(msg, hint=hint)
3264
3268
3265 def clearunfinished(repo):
3269 def clearunfinished(repo):
3266 '''Check for unfinished operations (as above), and clear the ones
3270 '''Check for unfinished operations (as above), and clear the ones
3267 that are clearable.
3271 that are clearable.
3268 '''
3272 '''
3269 for f, clearable, allowcommit, msg, hint in unfinishedstates:
3273 for f, clearable, allowcommit, msg, hint in unfinishedstates:
3270 if not clearable and repo.vfs.exists(f):
3274 if not clearable and repo.vfs.exists(f):
3271 raise error.Abort(msg, hint=hint)
3275 raise error.Abort(msg, hint=hint)
3272 for f, clearable, allowcommit, msg, hint in unfinishedstates:
3276 for f, clearable, allowcommit, msg, hint in unfinishedstates:
3273 if clearable and repo.vfs.exists(f):
3277 if clearable and repo.vfs.exists(f):
3274 util.unlink(repo.vfs.join(f))
3278 util.unlink(repo.vfs.join(f))
3275
3279
3276 afterresolvedstates = [
3280 afterresolvedstates = [
3277 ('graftstate',
3281 ('graftstate',
3278 _('hg graft --continue')),
3282 _('hg graft --continue')),
3279 ]
3283 ]
3280
3284
3281 def howtocontinue(repo):
3285 def howtocontinue(repo):
3282 '''Check for an unfinished operation and return the command to finish
3286 '''Check for an unfinished operation and return the command to finish
3283 it.
3287 it.
3284
3288
3285 afterresolvedstates tuples define a .hg/{file} and the corresponding
3289 afterresolvedstates tuples define a .hg/{file} and the corresponding
3286 command needed to finish it.
3290 command needed to finish it.
3287
3291
3288 Returns a (msg, warning) tuple. 'msg' is a string and 'warning' is
3292 Returns a (msg, warning) tuple. 'msg' is a string and 'warning' is
3289 a boolean.
3293 a boolean.
3290 '''
3294 '''
3291 contmsg = _("continue: %s")
3295 contmsg = _("continue: %s")
3292 for f, msg in afterresolvedstates:
3296 for f, msg in afterresolvedstates:
3293 if repo.vfs.exists(f):
3297 if repo.vfs.exists(f):
3294 return contmsg % msg, True
3298 return contmsg % msg, True
3295 if repo[None].dirty(missing=True, merge=False, branch=False):
3299 if repo[None].dirty(missing=True, merge=False, branch=False):
3296 return contmsg % _("hg commit"), False
3300 return contmsg % _("hg commit"), False
3297 return None, None
3301 return None, None
3298
3302
3299 def checkafterresolved(repo):
3303 def checkafterresolved(repo):
3300 '''Inform the user about the next action after completing hg resolve
3304 '''Inform the user about the next action after completing hg resolve
3301
3305
3302 If there's a matching afterresolvedstates, howtocontinue will yield
3306 If there's a matching afterresolvedstates, howtocontinue will yield
3303 repo.ui.warn as the reporter.
3307 repo.ui.warn as the reporter.
3304
3308
3305 Otherwise, it will yield repo.ui.note.
3309 Otherwise, it will yield repo.ui.note.
3306 '''
3310 '''
3307 msg, warning = howtocontinue(repo)
3311 msg, warning = howtocontinue(repo)
3308 if msg is not None:
3312 if msg is not None:
3309 if warning:
3313 if warning:
3310 repo.ui.warn("%s\n" % msg)
3314 repo.ui.warn("%s\n" % msg)
3311 else:
3315 else:
3312 repo.ui.note("%s\n" % msg)
3316 repo.ui.note("%s\n" % msg)
3313
3317
3314 def wrongtooltocontinue(repo, task):
3318 def wrongtooltocontinue(repo, task):
3315 '''Raise an abort suggesting how to properly continue if there is an
3319 '''Raise an abort suggesting how to properly continue if there is an
3316 active task.
3320 active task.
3317
3321
3318 Uses howtocontinue() to find the active task.
3322 Uses howtocontinue() to find the active task.
3319
3323
3320 If there's no task (repo.ui.note for 'hg commit'), it does not offer
3324 If there's no task (repo.ui.note for 'hg commit'), it does not offer
3321 a hint.
3325 a hint.
3322 '''
3326 '''
3323 after = howtocontinue(repo)
3327 after = howtocontinue(repo)
3324 hint = None
3328 hint = None
3325 if after[1]:
3329 if after[1]:
3326 hint = after[0]
3330 hint = after[0]
3327 raise error.Abort(_('no %s in progress') % task, hint=hint)
3331 raise error.Abort(_('no %s in progress') % task, hint=hint)
@@ -1,1443 +1,1445 b''
1 # configitems.py - centralized declaration of configuration option
1 # configitems.py - centralized declaration of configuration option
2 #
2 #
3 # Copyright 2017 Pierre-Yves David <pierre-yves.david@octobus.net>
3 # Copyright 2017 Pierre-Yves David <pierre-yves.david@octobus.net>
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 functools
10 import functools
11 import re
11 import re
12
12
13 from . import (
13 from . import (
14 encoding,
14 encoding,
15 error,
15 error,
16 )
16 )
17
17
18 def loadconfigtable(ui, extname, configtable):
18 def loadconfigtable(ui, extname, configtable):
19 """update config item known to the ui with the extension ones"""
19 """update config item known to the ui with the extension ones"""
20 for section, items in sorted(configtable.items()):
20 for section, items in sorted(configtable.items()):
21 knownitems = ui._knownconfig.setdefault(section, itemregister())
21 knownitems = ui._knownconfig.setdefault(section, itemregister())
22 knownkeys = set(knownitems)
22 knownkeys = set(knownitems)
23 newkeys = set(items)
23 newkeys = set(items)
24 for key in sorted(knownkeys & newkeys):
24 for key in sorted(knownkeys & newkeys):
25 msg = "extension '%s' overwrite config item '%s.%s'"
25 msg = "extension '%s' overwrite config item '%s.%s'"
26 msg %= (extname, section, key)
26 msg %= (extname, section, key)
27 ui.develwarn(msg, config='warn-config')
27 ui.develwarn(msg, config='warn-config')
28
28
29 knownitems.update(items)
29 knownitems.update(items)
30
30
31 class configitem(object):
31 class configitem(object):
32 """represent a known config item
32 """represent a known config item
33
33
34 :section: the official config section where to find this item,
34 :section: the official config section where to find this item,
35 :name: the official name within the section,
35 :name: the official name within the section,
36 :default: default value for this item,
36 :default: default value for this item,
37 :alias: optional list of tuples as alternatives,
37 :alias: optional list of tuples as alternatives,
38 :generic: this is a generic definition, match name using regular expression.
38 :generic: this is a generic definition, match name using regular expression.
39 """
39 """
40
40
41 def __init__(self, section, name, default=None, alias=(),
41 def __init__(self, section, name, default=None, alias=(),
42 generic=False, priority=0):
42 generic=False, priority=0):
43 self.section = section
43 self.section = section
44 self.name = name
44 self.name = name
45 self.default = default
45 self.default = default
46 self.alias = list(alias)
46 self.alias = list(alias)
47 self.generic = generic
47 self.generic = generic
48 self.priority = priority
48 self.priority = priority
49 self._re = None
49 self._re = None
50 if generic:
50 if generic:
51 self._re = re.compile(self.name)
51 self._re = re.compile(self.name)
52
52
53 class itemregister(dict):
53 class itemregister(dict):
54 """A specialized dictionary that can handle wild-card selection"""
54 """A specialized dictionary that can handle wild-card selection"""
55
55
56 def __init__(self):
56 def __init__(self):
57 super(itemregister, self).__init__()
57 super(itemregister, self).__init__()
58 self._generics = set()
58 self._generics = set()
59
59
60 def update(self, other):
60 def update(self, other):
61 super(itemregister, self).update(other)
61 super(itemregister, self).update(other)
62 self._generics.update(other._generics)
62 self._generics.update(other._generics)
63
63
64 def __setitem__(self, key, item):
64 def __setitem__(self, key, item):
65 super(itemregister, self).__setitem__(key, item)
65 super(itemregister, self).__setitem__(key, item)
66 if item.generic:
66 if item.generic:
67 self._generics.add(item)
67 self._generics.add(item)
68
68
69 def get(self, key):
69 def get(self, key):
70 baseitem = super(itemregister, self).get(key)
70 baseitem = super(itemregister, self).get(key)
71 if baseitem is not None and not baseitem.generic:
71 if baseitem is not None and not baseitem.generic:
72 return baseitem
72 return baseitem
73
73
74 # search for a matching generic item
74 # search for a matching generic item
75 generics = sorted(self._generics, key=(lambda x: (x.priority, x.name)))
75 generics = sorted(self._generics, key=(lambda x: (x.priority, x.name)))
76 for item in generics:
76 for item in generics:
77 # we use 'match' instead of 'search' to make the matching simpler
77 # we use 'match' instead of 'search' to make the matching simpler
78 # for people unfamiliar with regular expression. Having the match
78 # for people unfamiliar with regular expression. Having the match
79 # rooted to the start of the string will produce less surprising
79 # rooted to the start of the string will produce less surprising
80 # result for user writing simple regex for sub-attribute.
80 # result for user writing simple regex for sub-attribute.
81 #
81 #
82 # For example using "color\..*" match produces an unsurprising
82 # For example using "color\..*" match produces an unsurprising
83 # result, while using search could suddenly match apparently
83 # result, while using search could suddenly match apparently
84 # unrelated configuration that happens to contains "color."
84 # unrelated configuration that happens to contains "color."
85 # anywhere. This is a tradeoff where we favor requiring ".*" on
85 # anywhere. This is a tradeoff where we favor requiring ".*" on
86 # some match to avoid the need to prefix most pattern with "^".
86 # some match to avoid the need to prefix most pattern with "^".
87 # The "^" seems more error prone.
87 # The "^" seems more error prone.
88 if item._re.match(key):
88 if item._re.match(key):
89 return item
89 return item
90
90
91 return None
91 return None
92
92
93 coreitems = {}
93 coreitems = {}
94
94
95 def _register(configtable, *args, **kwargs):
95 def _register(configtable, *args, **kwargs):
96 item = configitem(*args, **kwargs)
96 item = configitem(*args, **kwargs)
97 section = configtable.setdefault(item.section, itemregister())
97 section = configtable.setdefault(item.section, itemregister())
98 if item.name in section:
98 if item.name in section:
99 msg = "duplicated config item registration for '%s.%s'"
99 msg = "duplicated config item registration for '%s.%s'"
100 raise error.ProgrammingError(msg % (item.section, item.name))
100 raise error.ProgrammingError(msg % (item.section, item.name))
101 section[item.name] = item
101 section[item.name] = item
102
102
103 # special value for case where the default is derived from other values
103 # special value for case where the default is derived from other values
104 dynamicdefault = object()
104 dynamicdefault = object()
105
105
106 # Registering actual config items
106 # Registering actual config items
107
107
108 def getitemregister(configtable):
108 def getitemregister(configtable):
109 f = functools.partial(_register, configtable)
109 f = functools.partial(_register, configtable)
110 # export pseudo enum as configitem.*
110 # export pseudo enum as configitem.*
111 f.dynamicdefault = dynamicdefault
111 f.dynamicdefault = dynamicdefault
112 return f
112 return f
113
113
114 coreconfigitem = getitemregister(coreitems)
114 coreconfigitem = getitemregister(coreitems)
115
115
116 def _registerdiffopts(section, configprefix=''):
116 def _registerdiffopts(section, configprefix=''):
117 coreconfigitem(section, configprefix + 'nodates',
117 coreconfigitem(section, configprefix + 'nodates',
118 default=False,
118 default=False,
119 )
119 )
120 coreconfigitem(section, configprefix + 'showfunc',
120 coreconfigitem(section, configprefix + 'showfunc',
121 default=False,
121 default=False,
122 )
122 )
123 coreconfigitem(section, configprefix + 'unified',
123 coreconfigitem(section, configprefix + 'unified',
124 default=None,
124 default=None,
125 )
125 )
126 coreconfigitem(section, configprefix + 'git',
126 coreconfigitem(section, configprefix + 'git',
127 default=False,
127 default=False,
128 )
128 )
129 coreconfigitem(section, configprefix + 'ignorews',
129 coreconfigitem(section, configprefix + 'ignorews',
130 default=False,
130 default=False,
131 )
131 )
132 coreconfigitem(section, configprefix + 'ignorewsamount',
132 coreconfigitem(section, configprefix + 'ignorewsamount',
133 default=False,
133 default=False,
134 )
134 )
135 coreconfigitem(section, configprefix + 'ignoreblanklines',
135 coreconfigitem(section, configprefix + 'ignoreblanklines',
136 default=False,
136 default=False,
137 )
137 )
138 coreconfigitem(section, configprefix + 'ignorewseol',
138 coreconfigitem(section, configprefix + 'ignorewseol',
139 default=False,
139 default=False,
140 )
140 )
141 coreconfigitem(section, configprefix + 'nobinary',
141 coreconfigitem(section, configprefix + 'nobinary',
142 default=False,
142 default=False,
143 )
143 )
144 coreconfigitem(section, configprefix + 'noprefix',
144 coreconfigitem(section, configprefix + 'noprefix',
145 default=False,
145 default=False,
146 )
146 )
147 coreconfigitem(section, configprefix + 'word-diff',
147 coreconfigitem(section, configprefix + 'word-diff',
148 default=False,
148 default=False,
149 )
149 )
150
150
151 coreconfigitem('alias', '.*',
151 coreconfigitem('alias', '.*',
152 default=dynamicdefault,
152 default=dynamicdefault,
153 generic=True,
153 generic=True,
154 )
154 )
155 coreconfigitem('auth', 'cookiefile',
155 coreconfigitem('auth', 'cookiefile',
156 default=None,
156 default=None,
157 )
157 )
158 _registerdiffopts(section='annotate')
158 _registerdiffopts(section='annotate')
159 # bookmarks.pushing: internal hack for discovery
159 # bookmarks.pushing: internal hack for discovery
160 coreconfigitem('bookmarks', 'pushing',
160 coreconfigitem('bookmarks', 'pushing',
161 default=list,
161 default=list,
162 )
162 )
163 # bundle.mainreporoot: internal hack for bundlerepo
163 # bundle.mainreporoot: internal hack for bundlerepo
164 coreconfigitem('bundle', 'mainreporoot',
164 coreconfigitem('bundle', 'mainreporoot',
165 default='',
165 default='',
166 )
166 )
167 coreconfigitem('censor', 'policy',
167 coreconfigitem('censor', 'policy',
168 default='abort',
168 default='abort',
169 )
169 )
170 coreconfigitem('chgserver', 'idletimeout',
170 coreconfigitem('chgserver', 'idletimeout',
171 default=3600,
171 default=3600,
172 )
172 )
173 coreconfigitem('chgserver', 'skiphash',
173 coreconfigitem('chgserver', 'skiphash',
174 default=False,
174 default=False,
175 )
175 )
176 coreconfigitem('cmdserver', 'log',
176 coreconfigitem('cmdserver', 'log',
177 default=None,
177 default=None,
178 )
178 )
179 coreconfigitem('cmdserver', 'max-log-files',
179 coreconfigitem('cmdserver', 'max-log-files',
180 default=7,
180 default=7,
181 )
181 )
182 coreconfigitem('cmdserver', 'max-log-size',
182 coreconfigitem('cmdserver', 'max-log-size',
183 default='1 MB',
183 default='1 MB',
184 )
184 )
185 coreconfigitem('cmdserver', 'max-repo-cache',
185 coreconfigitem('cmdserver', 'max-repo-cache',
186 default=0,
186 default=0,
187 )
187 )
188 coreconfigitem('cmdserver', 'message-encodings',
188 coreconfigitem('cmdserver', 'message-encodings',
189 default=list,
189 default=list,
190 )
190 )
191 coreconfigitem('cmdserver', 'track-log',
191 coreconfigitem('cmdserver', 'track-log',
192 default=lambda: ['chgserver', 'cmdserver', 'repocache'],
192 default=lambda: ['chgserver', 'cmdserver', 'repocache'],
193 )
193 )
194 coreconfigitem('color', '.*',
194 coreconfigitem('color', '.*',
195 default=None,
195 default=None,
196 generic=True,
196 generic=True,
197 )
197 )
198 coreconfigitem('color', 'mode',
198 coreconfigitem('color', 'mode',
199 default='auto',
199 default='auto',
200 )
200 )
201 coreconfigitem('color', 'pagermode',
201 coreconfigitem('color', 'pagermode',
202 default=dynamicdefault,
202 default=dynamicdefault,
203 )
203 )
204 _registerdiffopts(section='commands', configprefix='commit.interactive.')
204 coreconfigitem('commands', 'grep.all-files',
205 coreconfigitem('commands', 'grep.all-files',
205 default=False,
206 default=False,
206 )
207 )
207 coreconfigitem('commands', 'resolve.confirm',
208 coreconfigitem('commands', 'resolve.confirm',
208 default=False,
209 default=False,
209 )
210 )
210 coreconfigitem('commands', 'resolve.explicit-re-merge',
211 coreconfigitem('commands', 'resolve.explicit-re-merge',
211 default=False,
212 default=False,
212 )
213 )
213 coreconfigitem('commands', 'resolve.mark-check',
214 coreconfigitem('commands', 'resolve.mark-check',
214 default='none',
215 default='none',
215 )
216 )
217 _registerdiffopts(section='commands', configprefix='revert.interactive.')
216 coreconfigitem('commands', 'show.aliasprefix',
218 coreconfigitem('commands', 'show.aliasprefix',
217 default=list,
219 default=list,
218 )
220 )
219 coreconfigitem('commands', 'status.relative',
221 coreconfigitem('commands', 'status.relative',
220 default=False,
222 default=False,
221 )
223 )
222 coreconfigitem('commands', 'status.skipstates',
224 coreconfigitem('commands', 'status.skipstates',
223 default=[],
225 default=[],
224 )
226 )
225 coreconfigitem('commands', 'status.terse',
227 coreconfigitem('commands', 'status.terse',
226 default='',
228 default='',
227 )
229 )
228 coreconfigitem('commands', 'status.verbose',
230 coreconfigitem('commands', 'status.verbose',
229 default=False,
231 default=False,
230 )
232 )
231 coreconfigitem('commands', 'update.check',
233 coreconfigitem('commands', 'update.check',
232 default=None,
234 default=None,
233 )
235 )
234 coreconfigitem('commands', 'update.requiredest',
236 coreconfigitem('commands', 'update.requiredest',
235 default=False,
237 default=False,
236 )
238 )
237 coreconfigitem('committemplate', '.*',
239 coreconfigitem('committemplate', '.*',
238 default=None,
240 default=None,
239 generic=True,
241 generic=True,
240 )
242 )
241 coreconfigitem('convert', 'bzr.saverev',
243 coreconfigitem('convert', 'bzr.saverev',
242 default=True,
244 default=True,
243 )
245 )
244 coreconfigitem('convert', 'cvsps.cache',
246 coreconfigitem('convert', 'cvsps.cache',
245 default=True,
247 default=True,
246 )
248 )
247 coreconfigitem('convert', 'cvsps.fuzz',
249 coreconfigitem('convert', 'cvsps.fuzz',
248 default=60,
250 default=60,
249 )
251 )
250 coreconfigitem('convert', 'cvsps.logencoding',
252 coreconfigitem('convert', 'cvsps.logencoding',
251 default=None,
253 default=None,
252 )
254 )
253 coreconfigitem('convert', 'cvsps.mergefrom',
255 coreconfigitem('convert', 'cvsps.mergefrom',
254 default=None,
256 default=None,
255 )
257 )
256 coreconfigitem('convert', 'cvsps.mergeto',
258 coreconfigitem('convert', 'cvsps.mergeto',
257 default=None,
259 default=None,
258 )
260 )
259 coreconfigitem('convert', 'git.committeractions',
261 coreconfigitem('convert', 'git.committeractions',
260 default=lambda: ['messagedifferent'],
262 default=lambda: ['messagedifferent'],
261 )
263 )
262 coreconfigitem('convert', 'git.extrakeys',
264 coreconfigitem('convert', 'git.extrakeys',
263 default=list,
265 default=list,
264 )
266 )
265 coreconfigitem('convert', 'git.findcopiesharder',
267 coreconfigitem('convert', 'git.findcopiesharder',
266 default=False,
268 default=False,
267 )
269 )
268 coreconfigitem('convert', 'git.remoteprefix',
270 coreconfigitem('convert', 'git.remoteprefix',
269 default='remote',
271 default='remote',
270 )
272 )
271 coreconfigitem('convert', 'git.renamelimit',
273 coreconfigitem('convert', 'git.renamelimit',
272 default=400,
274 default=400,
273 )
275 )
274 coreconfigitem('convert', 'git.saverev',
276 coreconfigitem('convert', 'git.saverev',
275 default=True,
277 default=True,
276 )
278 )
277 coreconfigitem('convert', 'git.similarity',
279 coreconfigitem('convert', 'git.similarity',
278 default=50,
280 default=50,
279 )
281 )
280 coreconfigitem('convert', 'git.skipsubmodules',
282 coreconfigitem('convert', 'git.skipsubmodules',
281 default=False,
283 default=False,
282 )
284 )
283 coreconfigitem('convert', 'hg.clonebranches',
285 coreconfigitem('convert', 'hg.clonebranches',
284 default=False,
286 default=False,
285 )
287 )
286 coreconfigitem('convert', 'hg.ignoreerrors',
288 coreconfigitem('convert', 'hg.ignoreerrors',
287 default=False,
289 default=False,
288 )
290 )
289 coreconfigitem('convert', 'hg.revs',
291 coreconfigitem('convert', 'hg.revs',
290 default=None,
292 default=None,
291 )
293 )
292 coreconfigitem('convert', 'hg.saverev',
294 coreconfigitem('convert', 'hg.saverev',
293 default=False,
295 default=False,
294 )
296 )
295 coreconfigitem('convert', 'hg.sourcename',
297 coreconfigitem('convert', 'hg.sourcename',
296 default=None,
298 default=None,
297 )
299 )
298 coreconfigitem('convert', 'hg.startrev',
300 coreconfigitem('convert', 'hg.startrev',
299 default=None,
301 default=None,
300 )
302 )
301 coreconfigitem('convert', 'hg.tagsbranch',
303 coreconfigitem('convert', 'hg.tagsbranch',
302 default='default',
304 default='default',
303 )
305 )
304 coreconfigitem('convert', 'hg.usebranchnames',
306 coreconfigitem('convert', 'hg.usebranchnames',
305 default=True,
307 default=True,
306 )
308 )
307 coreconfigitem('convert', 'ignoreancestorcheck',
309 coreconfigitem('convert', 'ignoreancestorcheck',
308 default=False,
310 default=False,
309 )
311 )
310 coreconfigitem('convert', 'localtimezone',
312 coreconfigitem('convert', 'localtimezone',
311 default=False,
313 default=False,
312 )
314 )
313 coreconfigitem('convert', 'p4.encoding',
315 coreconfigitem('convert', 'p4.encoding',
314 default=dynamicdefault,
316 default=dynamicdefault,
315 )
317 )
316 coreconfigitem('convert', 'p4.startrev',
318 coreconfigitem('convert', 'p4.startrev',
317 default=0,
319 default=0,
318 )
320 )
319 coreconfigitem('convert', 'skiptags',
321 coreconfigitem('convert', 'skiptags',
320 default=False,
322 default=False,
321 )
323 )
322 coreconfigitem('convert', 'svn.debugsvnlog',
324 coreconfigitem('convert', 'svn.debugsvnlog',
323 default=True,
325 default=True,
324 )
326 )
325 coreconfigitem('convert', 'svn.trunk',
327 coreconfigitem('convert', 'svn.trunk',
326 default=None,
328 default=None,
327 )
329 )
328 coreconfigitem('convert', 'svn.tags',
330 coreconfigitem('convert', 'svn.tags',
329 default=None,
331 default=None,
330 )
332 )
331 coreconfigitem('convert', 'svn.branches',
333 coreconfigitem('convert', 'svn.branches',
332 default=None,
334 default=None,
333 )
335 )
334 coreconfigitem('convert', 'svn.startrev',
336 coreconfigitem('convert', 'svn.startrev',
335 default=0,
337 default=0,
336 )
338 )
337 coreconfigitem('debug', 'dirstate.delaywrite',
339 coreconfigitem('debug', 'dirstate.delaywrite',
338 default=0,
340 default=0,
339 )
341 )
340 coreconfigitem('defaults', '.*',
342 coreconfigitem('defaults', '.*',
341 default=None,
343 default=None,
342 generic=True,
344 generic=True,
343 )
345 )
344 coreconfigitem('devel', 'all-warnings',
346 coreconfigitem('devel', 'all-warnings',
345 default=False,
347 default=False,
346 )
348 )
347 coreconfigitem('devel', 'bundle2.debug',
349 coreconfigitem('devel', 'bundle2.debug',
348 default=False,
350 default=False,
349 )
351 )
350 coreconfigitem('devel', 'bundle.delta',
352 coreconfigitem('devel', 'bundle.delta',
351 default='',
353 default='',
352 )
354 )
353 coreconfigitem('devel', 'cache-vfs',
355 coreconfigitem('devel', 'cache-vfs',
354 default=None,
356 default=None,
355 )
357 )
356 coreconfigitem('devel', 'check-locks',
358 coreconfigitem('devel', 'check-locks',
357 default=False,
359 default=False,
358 )
360 )
359 coreconfigitem('devel', 'check-relroot',
361 coreconfigitem('devel', 'check-relroot',
360 default=False,
362 default=False,
361 )
363 )
362 coreconfigitem('devel', 'default-date',
364 coreconfigitem('devel', 'default-date',
363 default=None,
365 default=None,
364 )
366 )
365 coreconfigitem('devel', 'deprec-warn',
367 coreconfigitem('devel', 'deprec-warn',
366 default=False,
368 default=False,
367 )
369 )
368 coreconfigitem('devel', 'disableloaddefaultcerts',
370 coreconfigitem('devel', 'disableloaddefaultcerts',
369 default=False,
371 default=False,
370 )
372 )
371 coreconfigitem('devel', 'warn-empty-changegroup',
373 coreconfigitem('devel', 'warn-empty-changegroup',
372 default=False,
374 default=False,
373 )
375 )
374 coreconfigitem('devel', 'legacy.exchange',
376 coreconfigitem('devel', 'legacy.exchange',
375 default=list,
377 default=list,
376 )
378 )
377 coreconfigitem('devel', 'servercafile',
379 coreconfigitem('devel', 'servercafile',
378 default='',
380 default='',
379 )
381 )
380 coreconfigitem('devel', 'serverexactprotocol',
382 coreconfigitem('devel', 'serverexactprotocol',
381 default='',
383 default='',
382 )
384 )
383 coreconfigitem('devel', 'serverrequirecert',
385 coreconfigitem('devel', 'serverrequirecert',
384 default=False,
386 default=False,
385 )
387 )
386 coreconfigitem('devel', 'strip-obsmarkers',
388 coreconfigitem('devel', 'strip-obsmarkers',
387 default=True,
389 default=True,
388 )
390 )
389 coreconfigitem('devel', 'warn-config',
391 coreconfigitem('devel', 'warn-config',
390 default=None,
392 default=None,
391 )
393 )
392 coreconfigitem('devel', 'warn-config-default',
394 coreconfigitem('devel', 'warn-config-default',
393 default=None,
395 default=None,
394 )
396 )
395 coreconfigitem('devel', 'user.obsmarker',
397 coreconfigitem('devel', 'user.obsmarker',
396 default=None,
398 default=None,
397 )
399 )
398 coreconfigitem('devel', 'warn-config-unknown',
400 coreconfigitem('devel', 'warn-config-unknown',
399 default=None,
401 default=None,
400 )
402 )
401 coreconfigitem('devel', 'debug.copies',
403 coreconfigitem('devel', 'debug.copies',
402 default=False,
404 default=False,
403 )
405 )
404 coreconfigitem('devel', 'debug.extensions',
406 coreconfigitem('devel', 'debug.extensions',
405 default=False,
407 default=False,
406 )
408 )
407 coreconfigitem('devel', 'debug.peer-request',
409 coreconfigitem('devel', 'debug.peer-request',
408 default=False,
410 default=False,
409 )
411 )
410 _registerdiffopts(section='diff')
412 _registerdiffopts(section='diff')
411 coreconfigitem('email', 'bcc',
413 coreconfigitem('email', 'bcc',
412 default=None,
414 default=None,
413 )
415 )
414 coreconfigitem('email', 'cc',
416 coreconfigitem('email', 'cc',
415 default=None,
417 default=None,
416 )
418 )
417 coreconfigitem('email', 'charsets',
419 coreconfigitem('email', 'charsets',
418 default=list,
420 default=list,
419 )
421 )
420 coreconfigitem('email', 'from',
422 coreconfigitem('email', 'from',
421 default=None,
423 default=None,
422 )
424 )
423 coreconfigitem('email', 'method',
425 coreconfigitem('email', 'method',
424 default='smtp',
426 default='smtp',
425 )
427 )
426 coreconfigitem('email', 'reply-to',
428 coreconfigitem('email', 'reply-to',
427 default=None,
429 default=None,
428 )
430 )
429 coreconfigitem('email', 'to',
431 coreconfigitem('email', 'to',
430 default=None,
432 default=None,
431 )
433 )
432 coreconfigitem('experimental', 'archivemetatemplate',
434 coreconfigitem('experimental', 'archivemetatemplate',
433 default=dynamicdefault,
435 default=dynamicdefault,
434 )
436 )
435 coreconfigitem('experimental', 'auto-publish',
437 coreconfigitem('experimental', 'auto-publish',
436 default='publish',
438 default='publish',
437 )
439 )
438 coreconfigitem('experimental', 'bundle-phases',
440 coreconfigitem('experimental', 'bundle-phases',
439 default=False,
441 default=False,
440 )
442 )
441 coreconfigitem('experimental', 'bundle2-advertise',
443 coreconfigitem('experimental', 'bundle2-advertise',
442 default=True,
444 default=True,
443 )
445 )
444 coreconfigitem('experimental', 'bundle2-output-capture',
446 coreconfigitem('experimental', 'bundle2-output-capture',
445 default=False,
447 default=False,
446 )
448 )
447 coreconfigitem('experimental', 'bundle2.pushback',
449 coreconfigitem('experimental', 'bundle2.pushback',
448 default=False,
450 default=False,
449 )
451 )
450 coreconfigitem('experimental', 'bundle2lazylocking',
452 coreconfigitem('experimental', 'bundle2lazylocking',
451 default=False,
453 default=False,
452 )
454 )
453 coreconfigitem('experimental', 'bundlecomplevel',
455 coreconfigitem('experimental', 'bundlecomplevel',
454 default=None,
456 default=None,
455 )
457 )
456 coreconfigitem('experimental', 'bundlecomplevel.bzip2',
458 coreconfigitem('experimental', 'bundlecomplevel.bzip2',
457 default=None,
459 default=None,
458 )
460 )
459 coreconfigitem('experimental', 'bundlecomplevel.gzip',
461 coreconfigitem('experimental', 'bundlecomplevel.gzip',
460 default=None,
462 default=None,
461 )
463 )
462 coreconfigitem('experimental', 'bundlecomplevel.none',
464 coreconfigitem('experimental', 'bundlecomplevel.none',
463 default=None,
465 default=None,
464 )
466 )
465 coreconfigitem('experimental', 'bundlecomplevel.zstd',
467 coreconfigitem('experimental', 'bundlecomplevel.zstd',
466 default=None,
468 default=None,
467 )
469 )
468 coreconfigitem('experimental', 'changegroup3',
470 coreconfigitem('experimental', 'changegroup3',
469 default=False,
471 default=False,
470 )
472 )
471 coreconfigitem('experimental', 'clientcompressionengines',
473 coreconfigitem('experimental', 'clientcompressionengines',
472 default=list,
474 default=list,
473 )
475 )
474 coreconfigitem('experimental', 'copytrace',
476 coreconfigitem('experimental', 'copytrace',
475 default='on',
477 default='on',
476 )
478 )
477 coreconfigitem('experimental', 'copytrace.movecandidateslimit',
479 coreconfigitem('experimental', 'copytrace.movecandidateslimit',
478 default=100,
480 default=100,
479 )
481 )
480 coreconfigitem('experimental', 'copytrace.sourcecommitlimit',
482 coreconfigitem('experimental', 'copytrace.sourcecommitlimit',
481 default=100,
483 default=100,
482 )
484 )
483 coreconfigitem('experimental', 'crecordtest',
485 coreconfigitem('experimental', 'crecordtest',
484 default=None,
486 default=None,
485 )
487 )
486 coreconfigitem('experimental', 'directaccess',
488 coreconfigitem('experimental', 'directaccess',
487 default=False,
489 default=False,
488 )
490 )
489 coreconfigitem('experimental', 'directaccess.revnums',
491 coreconfigitem('experimental', 'directaccess.revnums',
490 default=False,
492 default=False,
491 )
493 )
492 coreconfigitem('experimental', 'editortmpinhg',
494 coreconfigitem('experimental', 'editortmpinhg',
493 default=False,
495 default=False,
494 )
496 )
495 coreconfigitem('experimental', 'evolution',
497 coreconfigitem('experimental', 'evolution',
496 default=list,
498 default=list,
497 )
499 )
498 coreconfigitem('experimental', 'evolution.allowdivergence',
500 coreconfigitem('experimental', 'evolution.allowdivergence',
499 default=False,
501 default=False,
500 alias=[('experimental', 'allowdivergence')]
502 alias=[('experimental', 'allowdivergence')]
501 )
503 )
502 coreconfigitem('experimental', 'evolution.allowunstable',
504 coreconfigitem('experimental', 'evolution.allowunstable',
503 default=None,
505 default=None,
504 )
506 )
505 coreconfigitem('experimental', 'evolution.createmarkers',
507 coreconfigitem('experimental', 'evolution.createmarkers',
506 default=None,
508 default=None,
507 )
509 )
508 coreconfigitem('experimental', 'evolution.effect-flags',
510 coreconfigitem('experimental', 'evolution.effect-flags',
509 default=True,
511 default=True,
510 alias=[('experimental', 'effect-flags')]
512 alias=[('experimental', 'effect-flags')]
511 )
513 )
512 coreconfigitem('experimental', 'evolution.exchange',
514 coreconfigitem('experimental', 'evolution.exchange',
513 default=None,
515 default=None,
514 )
516 )
515 coreconfigitem('experimental', 'evolution.bundle-obsmarker',
517 coreconfigitem('experimental', 'evolution.bundle-obsmarker',
516 default=False,
518 default=False,
517 )
519 )
518 coreconfigitem('experimental', 'evolution.report-instabilities',
520 coreconfigitem('experimental', 'evolution.report-instabilities',
519 default=True,
521 default=True,
520 )
522 )
521 coreconfigitem('experimental', 'evolution.track-operation',
523 coreconfigitem('experimental', 'evolution.track-operation',
522 default=True,
524 default=True,
523 )
525 )
524 coreconfigitem('experimental', 'maxdeltachainspan',
526 coreconfigitem('experimental', 'maxdeltachainspan',
525 default=-1,
527 default=-1,
526 )
528 )
527 coreconfigitem('experimental', 'mergetempdirprefix',
529 coreconfigitem('experimental', 'mergetempdirprefix',
528 default=None,
530 default=None,
529 )
531 )
530 coreconfigitem('experimental', 'mmapindexthreshold',
532 coreconfigitem('experimental', 'mmapindexthreshold',
531 default=None,
533 default=None,
532 )
534 )
533 coreconfigitem('experimental', 'narrow',
535 coreconfigitem('experimental', 'narrow',
534 default=False,
536 default=False,
535 )
537 )
536 coreconfigitem('experimental', 'nonnormalparanoidcheck',
538 coreconfigitem('experimental', 'nonnormalparanoidcheck',
537 default=False,
539 default=False,
538 )
540 )
539 coreconfigitem('experimental', 'exportableenviron',
541 coreconfigitem('experimental', 'exportableenviron',
540 default=list,
542 default=list,
541 )
543 )
542 coreconfigitem('experimental', 'extendedheader.index',
544 coreconfigitem('experimental', 'extendedheader.index',
543 default=None,
545 default=None,
544 )
546 )
545 coreconfigitem('experimental', 'extendedheader.similarity',
547 coreconfigitem('experimental', 'extendedheader.similarity',
546 default=False,
548 default=False,
547 )
549 )
548 coreconfigitem('experimental', 'format.compression',
550 coreconfigitem('experimental', 'format.compression',
549 default='zlib',
551 default='zlib',
550 )
552 )
551 coreconfigitem('experimental', 'graphshorten',
553 coreconfigitem('experimental', 'graphshorten',
552 default=False,
554 default=False,
553 )
555 )
554 coreconfigitem('experimental', 'graphstyle.parent',
556 coreconfigitem('experimental', 'graphstyle.parent',
555 default=dynamicdefault,
557 default=dynamicdefault,
556 )
558 )
557 coreconfigitem('experimental', 'graphstyle.missing',
559 coreconfigitem('experimental', 'graphstyle.missing',
558 default=dynamicdefault,
560 default=dynamicdefault,
559 )
561 )
560 coreconfigitem('experimental', 'graphstyle.grandparent',
562 coreconfigitem('experimental', 'graphstyle.grandparent',
561 default=dynamicdefault,
563 default=dynamicdefault,
562 )
564 )
563 coreconfigitem('experimental', 'hook-track-tags',
565 coreconfigitem('experimental', 'hook-track-tags',
564 default=False,
566 default=False,
565 )
567 )
566 coreconfigitem('experimental', 'httppeer.advertise-v2',
568 coreconfigitem('experimental', 'httppeer.advertise-v2',
567 default=False,
569 default=False,
568 )
570 )
569 coreconfigitem('experimental', 'httppeer.v2-encoder-order',
571 coreconfigitem('experimental', 'httppeer.v2-encoder-order',
570 default=None,
572 default=None,
571 )
573 )
572 coreconfigitem('experimental', 'httppostargs',
574 coreconfigitem('experimental', 'httppostargs',
573 default=False,
575 default=False,
574 )
576 )
575 coreconfigitem('experimental', 'mergedriver',
577 coreconfigitem('experimental', 'mergedriver',
576 default=None,
578 default=None,
577 )
579 )
578 coreconfigitem('experimental', 'nointerrupt', default=False)
580 coreconfigitem('experimental', 'nointerrupt', default=False)
579 coreconfigitem('experimental', 'nointerrupt-interactiveonly', default=True)
581 coreconfigitem('experimental', 'nointerrupt-interactiveonly', default=True)
580
582
581 coreconfigitem('experimental', 'obsmarkers-exchange-debug',
583 coreconfigitem('experimental', 'obsmarkers-exchange-debug',
582 default=False,
584 default=False,
583 )
585 )
584 coreconfigitem('experimental', 'remotenames',
586 coreconfigitem('experimental', 'remotenames',
585 default=False,
587 default=False,
586 )
588 )
587 coreconfigitem('experimental', 'removeemptydirs',
589 coreconfigitem('experimental', 'removeemptydirs',
588 default=True,
590 default=True,
589 )
591 )
590 coreconfigitem('experimental', 'revisions.prefixhexnode',
592 coreconfigitem('experimental', 'revisions.prefixhexnode',
591 default=False,
593 default=False,
592 )
594 )
593 coreconfigitem('experimental', 'revlogv2',
595 coreconfigitem('experimental', 'revlogv2',
594 default=None,
596 default=None,
595 )
597 )
596 coreconfigitem('experimental', 'revisions.disambiguatewithin',
598 coreconfigitem('experimental', 'revisions.disambiguatewithin',
597 default=None,
599 default=None,
598 )
600 )
599 coreconfigitem('experimental', 'server.filesdata.recommended-batch-size',
601 coreconfigitem('experimental', 'server.filesdata.recommended-batch-size',
600 default=50000,
602 default=50000,
601 )
603 )
602 coreconfigitem('experimental', 'server.manifestdata.recommended-batch-size',
604 coreconfigitem('experimental', 'server.manifestdata.recommended-batch-size',
603 default=100000,
605 default=100000,
604 )
606 )
605 coreconfigitem('experimental', 'server.stream-narrow-clones',
607 coreconfigitem('experimental', 'server.stream-narrow-clones',
606 default=False,
608 default=False,
607 )
609 )
608 coreconfigitem('experimental', 'single-head-per-branch',
610 coreconfigitem('experimental', 'single-head-per-branch',
609 default=False,
611 default=False,
610 )
612 )
611 coreconfigitem('experimental', 'sshserver.support-v2',
613 coreconfigitem('experimental', 'sshserver.support-v2',
612 default=False,
614 default=False,
613 )
615 )
614 coreconfigitem('experimental', 'sparse-read',
616 coreconfigitem('experimental', 'sparse-read',
615 default=False,
617 default=False,
616 )
618 )
617 coreconfigitem('experimental', 'sparse-read.density-threshold',
619 coreconfigitem('experimental', 'sparse-read.density-threshold',
618 default=0.50,
620 default=0.50,
619 )
621 )
620 coreconfigitem('experimental', 'sparse-read.min-gap-size',
622 coreconfigitem('experimental', 'sparse-read.min-gap-size',
621 default='65K',
623 default='65K',
622 )
624 )
623 coreconfigitem('experimental', 'treemanifest',
625 coreconfigitem('experimental', 'treemanifest',
624 default=False,
626 default=False,
625 )
627 )
626 coreconfigitem('experimental', 'update.atomic-file',
628 coreconfigitem('experimental', 'update.atomic-file',
627 default=False,
629 default=False,
628 )
630 )
629 coreconfigitem('experimental', 'sshpeer.advertise-v2',
631 coreconfigitem('experimental', 'sshpeer.advertise-v2',
630 default=False,
632 default=False,
631 )
633 )
632 coreconfigitem('experimental', 'web.apiserver',
634 coreconfigitem('experimental', 'web.apiserver',
633 default=False,
635 default=False,
634 )
636 )
635 coreconfigitem('experimental', 'web.api.http-v2',
637 coreconfigitem('experimental', 'web.api.http-v2',
636 default=False,
638 default=False,
637 )
639 )
638 coreconfigitem('experimental', 'web.api.debugreflect',
640 coreconfigitem('experimental', 'web.api.debugreflect',
639 default=False,
641 default=False,
640 )
642 )
641 coreconfigitem('experimental', 'worker.wdir-get-thread-safe',
643 coreconfigitem('experimental', 'worker.wdir-get-thread-safe',
642 default=False,
644 default=False,
643 )
645 )
644 coreconfigitem('experimental', 'xdiff',
646 coreconfigitem('experimental', 'xdiff',
645 default=False,
647 default=False,
646 )
648 )
647 coreconfigitem('extensions', '.*',
649 coreconfigitem('extensions', '.*',
648 default=None,
650 default=None,
649 generic=True,
651 generic=True,
650 )
652 )
651 coreconfigitem('extdata', '.*',
653 coreconfigitem('extdata', '.*',
652 default=None,
654 default=None,
653 generic=True,
655 generic=True,
654 )
656 )
655 coreconfigitem('format', 'chunkcachesize',
657 coreconfigitem('format', 'chunkcachesize',
656 default=None,
658 default=None,
657 )
659 )
658 coreconfigitem('format', 'dotencode',
660 coreconfigitem('format', 'dotencode',
659 default=True,
661 default=True,
660 )
662 )
661 coreconfigitem('format', 'generaldelta',
663 coreconfigitem('format', 'generaldelta',
662 default=False,
664 default=False,
663 )
665 )
664 coreconfigitem('format', 'manifestcachesize',
666 coreconfigitem('format', 'manifestcachesize',
665 default=None,
667 default=None,
666 )
668 )
667 coreconfigitem('format', 'maxchainlen',
669 coreconfigitem('format', 'maxchainlen',
668 default=dynamicdefault,
670 default=dynamicdefault,
669 )
671 )
670 coreconfigitem('format', 'obsstore-version',
672 coreconfigitem('format', 'obsstore-version',
671 default=None,
673 default=None,
672 )
674 )
673 coreconfigitem('format', 'sparse-revlog',
675 coreconfigitem('format', 'sparse-revlog',
674 default=True,
676 default=True,
675 )
677 )
676 coreconfigitem('format', 'usefncache',
678 coreconfigitem('format', 'usefncache',
677 default=True,
679 default=True,
678 )
680 )
679 coreconfigitem('format', 'usegeneraldelta',
681 coreconfigitem('format', 'usegeneraldelta',
680 default=True,
682 default=True,
681 )
683 )
682 coreconfigitem('format', 'usestore',
684 coreconfigitem('format', 'usestore',
683 default=True,
685 default=True,
684 )
686 )
685 coreconfigitem('format', 'internal-phase',
687 coreconfigitem('format', 'internal-phase',
686 default=False,
688 default=False,
687 )
689 )
688 coreconfigitem('fsmonitor', 'warn_when_unused',
690 coreconfigitem('fsmonitor', 'warn_when_unused',
689 default=True,
691 default=True,
690 )
692 )
691 coreconfigitem('fsmonitor', 'warn_update_file_count',
693 coreconfigitem('fsmonitor', 'warn_update_file_count',
692 default=50000,
694 default=50000,
693 )
695 )
694 coreconfigitem('help', br'hidden-command\..*',
696 coreconfigitem('help', br'hidden-command\..*',
695 default=False,
697 default=False,
696 generic=True,
698 generic=True,
697 )
699 )
698 coreconfigitem('help', br'hidden-topic\..*',
700 coreconfigitem('help', br'hidden-topic\..*',
699 default=False,
701 default=False,
700 generic=True,
702 generic=True,
701 )
703 )
702 coreconfigitem('hooks', '.*',
704 coreconfigitem('hooks', '.*',
703 default=dynamicdefault,
705 default=dynamicdefault,
704 generic=True,
706 generic=True,
705 )
707 )
706 coreconfigitem('hgweb-paths', '.*',
708 coreconfigitem('hgweb-paths', '.*',
707 default=list,
709 default=list,
708 generic=True,
710 generic=True,
709 )
711 )
710 coreconfigitem('hostfingerprints', '.*',
712 coreconfigitem('hostfingerprints', '.*',
711 default=list,
713 default=list,
712 generic=True,
714 generic=True,
713 )
715 )
714 coreconfigitem('hostsecurity', 'ciphers',
716 coreconfigitem('hostsecurity', 'ciphers',
715 default=None,
717 default=None,
716 )
718 )
717 coreconfigitem('hostsecurity', 'disabletls10warning',
719 coreconfigitem('hostsecurity', 'disabletls10warning',
718 default=False,
720 default=False,
719 )
721 )
720 coreconfigitem('hostsecurity', 'minimumprotocol',
722 coreconfigitem('hostsecurity', 'minimumprotocol',
721 default=dynamicdefault,
723 default=dynamicdefault,
722 )
724 )
723 coreconfigitem('hostsecurity', '.*:minimumprotocol$',
725 coreconfigitem('hostsecurity', '.*:minimumprotocol$',
724 default=dynamicdefault,
726 default=dynamicdefault,
725 generic=True,
727 generic=True,
726 )
728 )
727 coreconfigitem('hostsecurity', '.*:ciphers$',
729 coreconfigitem('hostsecurity', '.*:ciphers$',
728 default=dynamicdefault,
730 default=dynamicdefault,
729 generic=True,
731 generic=True,
730 )
732 )
731 coreconfigitem('hostsecurity', '.*:fingerprints$',
733 coreconfigitem('hostsecurity', '.*:fingerprints$',
732 default=list,
734 default=list,
733 generic=True,
735 generic=True,
734 )
736 )
735 coreconfigitem('hostsecurity', '.*:verifycertsfile$',
737 coreconfigitem('hostsecurity', '.*:verifycertsfile$',
736 default=None,
738 default=None,
737 generic=True,
739 generic=True,
738 )
740 )
739
741
740 coreconfigitem('http_proxy', 'always',
742 coreconfigitem('http_proxy', 'always',
741 default=False,
743 default=False,
742 )
744 )
743 coreconfigitem('http_proxy', 'host',
745 coreconfigitem('http_proxy', 'host',
744 default=None,
746 default=None,
745 )
747 )
746 coreconfigitem('http_proxy', 'no',
748 coreconfigitem('http_proxy', 'no',
747 default=list,
749 default=list,
748 )
750 )
749 coreconfigitem('http_proxy', 'passwd',
751 coreconfigitem('http_proxy', 'passwd',
750 default=None,
752 default=None,
751 )
753 )
752 coreconfigitem('http_proxy', 'user',
754 coreconfigitem('http_proxy', 'user',
753 default=None,
755 default=None,
754 )
756 )
755
757
756 coreconfigitem('http', 'timeout',
758 coreconfigitem('http', 'timeout',
757 default=None,
759 default=None,
758 )
760 )
759
761
760 coreconfigitem('logtoprocess', 'commandexception',
762 coreconfigitem('logtoprocess', 'commandexception',
761 default=None,
763 default=None,
762 )
764 )
763 coreconfigitem('logtoprocess', 'commandfinish',
765 coreconfigitem('logtoprocess', 'commandfinish',
764 default=None,
766 default=None,
765 )
767 )
766 coreconfigitem('logtoprocess', 'command',
768 coreconfigitem('logtoprocess', 'command',
767 default=None,
769 default=None,
768 )
770 )
769 coreconfigitem('logtoprocess', 'develwarn',
771 coreconfigitem('logtoprocess', 'develwarn',
770 default=None,
772 default=None,
771 )
773 )
772 coreconfigitem('logtoprocess', 'uiblocked',
774 coreconfigitem('logtoprocess', 'uiblocked',
773 default=None,
775 default=None,
774 )
776 )
775 coreconfigitem('merge', 'checkunknown',
777 coreconfigitem('merge', 'checkunknown',
776 default='abort',
778 default='abort',
777 )
779 )
778 coreconfigitem('merge', 'checkignored',
780 coreconfigitem('merge', 'checkignored',
779 default='abort',
781 default='abort',
780 )
782 )
781 coreconfigitem('experimental', 'merge.checkpathconflicts',
783 coreconfigitem('experimental', 'merge.checkpathconflicts',
782 default=False,
784 default=False,
783 )
785 )
784 coreconfigitem('merge', 'followcopies',
786 coreconfigitem('merge', 'followcopies',
785 default=True,
787 default=True,
786 )
788 )
787 coreconfigitem('merge', 'on-failure',
789 coreconfigitem('merge', 'on-failure',
788 default='continue',
790 default='continue',
789 )
791 )
790 coreconfigitem('merge', 'preferancestor',
792 coreconfigitem('merge', 'preferancestor',
791 default=lambda: ['*'],
793 default=lambda: ['*'],
792 )
794 )
793 coreconfigitem('merge', 'strict-capability-check',
795 coreconfigitem('merge', 'strict-capability-check',
794 default=False,
796 default=False,
795 )
797 )
796 coreconfigitem('merge-tools', '.*',
798 coreconfigitem('merge-tools', '.*',
797 default=None,
799 default=None,
798 generic=True,
800 generic=True,
799 )
801 )
800 coreconfigitem('merge-tools', br'.*\.args$',
802 coreconfigitem('merge-tools', br'.*\.args$',
801 default="$local $base $other",
803 default="$local $base $other",
802 generic=True,
804 generic=True,
803 priority=-1,
805 priority=-1,
804 )
806 )
805 coreconfigitem('merge-tools', br'.*\.binary$',
807 coreconfigitem('merge-tools', br'.*\.binary$',
806 default=False,
808 default=False,
807 generic=True,
809 generic=True,
808 priority=-1,
810 priority=-1,
809 )
811 )
810 coreconfigitem('merge-tools', br'.*\.check$',
812 coreconfigitem('merge-tools', br'.*\.check$',
811 default=list,
813 default=list,
812 generic=True,
814 generic=True,
813 priority=-1,
815 priority=-1,
814 )
816 )
815 coreconfigitem('merge-tools', br'.*\.checkchanged$',
817 coreconfigitem('merge-tools', br'.*\.checkchanged$',
816 default=False,
818 default=False,
817 generic=True,
819 generic=True,
818 priority=-1,
820 priority=-1,
819 )
821 )
820 coreconfigitem('merge-tools', br'.*\.executable$',
822 coreconfigitem('merge-tools', br'.*\.executable$',
821 default=dynamicdefault,
823 default=dynamicdefault,
822 generic=True,
824 generic=True,
823 priority=-1,
825 priority=-1,
824 )
826 )
825 coreconfigitem('merge-tools', br'.*\.fixeol$',
827 coreconfigitem('merge-tools', br'.*\.fixeol$',
826 default=False,
828 default=False,
827 generic=True,
829 generic=True,
828 priority=-1,
830 priority=-1,
829 )
831 )
830 coreconfigitem('merge-tools', br'.*\.gui$',
832 coreconfigitem('merge-tools', br'.*\.gui$',
831 default=False,
833 default=False,
832 generic=True,
834 generic=True,
833 priority=-1,
835 priority=-1,
834 )
836 )
835 coreconfigitem('merge-tools', br'.*\.mergemarkers$',
837 coreconfigitem('merge-tools', br'.*\.mergemarkers$',
836 default='basic',
838 default='basic',
837 generic=True,
839 generic=True,
838 priority=-1,
840 priority=-1,
839 )
841 )
840 coreconfigitem('merge-tools', br'.*\.mergemarkertemplate$',
842 coreconfigitem('merge-tools', br'.*\.mergemarkertemplate$',
841 default=dynamicdefault, # take from ui.mergemarkertemplate
843 default=dynamicdefault, # take from ui.mergemarkertemplate
842 generic=True,
844 generic=True,
843 priority=-1,
845 priority=-1,
844 )
846 )
845 coreconfigitem('merge-tools', br'.*\.priority$',
847 coreconfigitem('merge-tools', br'.*\.priority$',
846 default=0,
848 default=0,
847 generic=True,
849 generic=True,
848 priority=-1,
850 priority=-1,
849 )
851 )
850 coreconfigitem('merge-tools', br'.*\.premerge$',
852 coreconfigitem('merge-tools', br'.*\.premerge$',
851 default=dynamicdefault,
853 default=dynamicdefault,
852 generic=True,
854 generic=True,
853 priority=-1,
855 priority=-1,
854 )
856 )
855 coreconfigitem('merge-tools', br'.*\.symlink$',
857 coreconfigitem('merge-tools', br'.*\.symlink$',
856 default=False,
858 default=False,
857 generic=True,
859 generic=True,
858 priority=-1,
860 priority=-1,
859 )
861 )
860 coreconfigitem('pager', 'attend-.*',
862 coreconfigitem('pager', 'attend-.*',
861 default=dynamicdefault,
863 default=dynamicdefault,
862 generic=True,
864 generic=True,
863 )
865 )
864 coreconfigitem('pager', 'ignore',
866 coreconfigitem('pager', 'ignore',
865 default=list,
867 default=list,
866 )
868 )
867 coreconfigitem('pager', 'pager',
869 coreconfigitem('pager', 'pager',
868 default=dynamicdefault,
870 default=dynamicdefault,
869 )
871 )
870 coreconfigitem('patch', 'eol',
872 coreconfigitem('patch', 'eol',
871 default='strict',
873 default='strict',
872 )
874 )
873 coreconfigitem('patch', 'fuzz',
875 coreconfigitem('patch', 'fuzz',
874 default=2,
876 default=2,
875 )
877 )
876 coreconfigitem('paths', 'default',
878 coreconfigitem('paths', 'default',
877 default=None,
879 default=None,
878 )
880 )
879 coreconfigitem('paths', 'default-push',
881 coreconfigitem('paths', 'default-push',
880 default=None,
882 default=None,
881 )
883 )
882 coreconfigitem('paths', '.*',
884 coreconfigitem('paths', '.*',
883 default=None,
885 default=None,
884 generic=True,
886 generic=True,
885 )
887 )
886 coreconfigitem('phases', 'checksubrepos',
888 coreconfigitem('phases', 'checksubrepos',
887 default='follow',
889 default='follow',
888 )
890 )
889 coreconfigitem('phases', 'new-commit',
891 coreconfigitem('phases', 'new-commit',
890 default='draft',
892 default='draft',
891 )
893 )
892 coreconfigitem('phases', 'publish',
894 coreconfigitem('phases', 'publish',
893 default=True,
895 default=True,
894 )
896 )
895 coreconfigitem('profiling', 'enabled',
897 coreconfigitem('profiling', 'enabled',
896 default=False,
898 default=False,
897 )
899 )
898 coreconfigitem('profiling', 'format',
900 coreconfigitem('profiling', 'format',
899 default='text',
901 default='text',
900 )
902 )
901 coreconfigitem('profiling', 'freq',
903 coreconfigitem('profiling', 'freq',
902 default=1000,
904 default=1000,
903 )
905 )
904 coreconfigitem('profiling', 'limit',
906 coreconfigitem('profiling', 'limit',
905 default=30,
907 default=30,
906 )
908 )
907 coreconfigitem('profiling', 'nested',
909 coreconfigitem('profiling', 'nested',
908 default=0,
910 default=0,
909 )
911 )
910 coreconfigitem('profiling', 'output',
912 coreconfigitem('profiling', 'output',
911 default=None,
913 default=None,
912 )
914 )
913 coreconfigitem('profiling', 'showmax',
915 coreconfigitem('profiling', 'showmax',
914 default=0.999,
916 default=0.999,
915 )
917 )
916 coreconfigitem('profiling', 'showmin',
918 coreconfigitem('profiling', 'showmin',
917 default=dynamicdefault,
919 default=dynamicdefault,
918 )
920 )
919 coreconfigitem('profiling', 'sort',
921 coreconfigitem('profiling', 'sort',
920 default='inlinetime',
922 default='inlinetime',
921 )
923 )
922 coreconfigitem('profiling', 'statformat',
924 coreconfigitem('profiling', 'statformat',
923 default='hotpath',
925 default='hotpath',
924 )
926 )
925 coreconfigitem('profiling', 'time-track',
927 coreconfigitem('profiling', 'time-track',
926 default=dynamicdefault,
928 default=dynamicdefault,
927 )
929 )
928 coreconfigitem('profiling', 'type',
930 coreconfigitem('profiling', 'type',
929 default='stat',
931 default='stat',
930 )
932 )
931 coreconfigitem('progress', 'assume-tty',
933 coreconfigitem('progress', 'assume-tty',
932 default=False,
934 default=False,
933 )
935 )
934 coreconfigitem('progress', 'changedelay',
936 coreconfigitem('progress', 'changedelay',
935 default=1,
937 default=1,
936 )
938 )
937 coreconfigitem('progress', 'clear-complete',
939 coreconfigitem('progress', 'clear-complete',
938 default=True,
940 default=True,
939 )
941 )
940 coreconfigitem('progress', 'debug',
942 coreconfigitem('progress', 'debug',
941 default=False,
943 default=False,
942 )
944 )
943 coreconfigitem('progress', 'delay',
945 coreconfigitem('progress', 'delay',
944 default=3,
946 default=3,
945 )
947 )
946 coreconfigitem('progress', 'disable',
948 coreconfigitem('progress', 'disable',
947 default=False,
949 default=False,
948 )
950 )
949 coreconfigitem('progress', 'estimateinterval',
951 coreconfigitem('progress', 'estimateinterval',
950 default=60.0,
952 default=60.0,
951 )
953 )
952 coreconfigitem('progress', 'format',
954 coreconfigitem('progress', 'format',
953 default=lambda: ['topic', 'bar', 'number', 'estimate'],
955 default=lambda: ['topic', 'bar', 'number', 'estimate'],
954 )
956 )
955 coreconfigitem('progress', 'refresh',
957 coreconfigitem('progress', 'refresh',
956 default=0.1,
958 default=0.1,
957 )
959 )
958 coreconfigitem('progress', 'width',
960 coreconfigitem('progress', 'width',
959 default=dynamicdefault,
961 default=dynamicdefault,
960 )
962 )
961 coreconfigitem('push', 'pushvars.server',
963 coreconfigitem('push', 'pushvars.server',
962 default=False,
964 default=False,
963 )
965 )
964 coreconfigitem('rewrite', 'backup-bundle',
966 coreconfigitem('rewrite', 'backup-bundle',
965 default=True,
967 default=True,
966 alias=[('ui', 'history-editing-backup')],
968 alias=[('ui', 'history-editing-backup')],
967 )
969 )
968 coreconfigitem('rewrite', 'update-timestamp',
970 coreconfigitem('rewrite', 'update-timestamp',
969 default=False,
971 default=False,
970 )
972 )
971 coreconfigitem('storage', 'new-repo-backend',
973 coreconfigitem('storage', 'new-repo-backend',
972 default='revlogv1',
974 default='revlogv1',
973 )
975 )
974 coreconfigitem('storage', 'revlog.optimize-delta-parent-choice',
976 coreconfigitem('storage', 'revlog.optimize-delta-parent-choice',
975 default=True,
977 default=True,
976 alias=[('format', 'aggressivemergedeltas')],
978 alias=[('format', 'aggressivemergedeltas')],
977 )
979 )
978 coreconfigitem('server', 'bookmarks-pushkey-compat',
980 coreconfigitem('server', 'bookmarks-pushkey-compat',
979 default=True,
981 default=True,
980 )
982 )
981 coreconfigitem('server', 'bundle1',
983 coreconfigitem('server', 'bundle1',
982 default=True,
984 default=True,
983 )
985 )
984 coreconfigitem('server', 'bundle1gd',
986 coreconfigitem('server', 'bundle1gd',
985 default=None,
987 default=None,
986 )
988 )
987 coreconfigitem('server', 'bundle1.pull',
989 coreconfigitem('server', 'bundle1.pull',
988 default=None,
990 default=None,
989 )
991 )
990 coreconfigitem('server', 'bundle1gd.pull',
992 coreconfigitem('server', 'bundle1gd.pull',
991 default=None,
993 default=None,
992 )
994 )
993 coreconfigitem('server', 'bundle1.push',
995 coreconfigitem('server', 'bundle1.push',
994 default=None,
996 default=None,
995 )
997 )
996 coreconfigitem('server', 'bundle1gd.push',
998 coreconfigitem('server', 'bundle1gd.push',
997 default=None,
999 default=None,
998 )
1000 )
999 coreconfigitem('server', 'bundle2.stream',
1001 coreconfigitem('server', 'bundle2.stream',
1000 default=True,
1002 default=True,
1001 alias=[('experimental', 'bundle2.stream')]
1003 alias=[('experimental', 'bundle2.stream')]
1002 )
1004 )
1003 coreconfigitem('server', 'compressionengines',
1005 coreconfigitem('server', 'compressionengines',
1004 default=list,
1006 default=list,
1005 )
1007 )
1006 coreconfigitem('server', 'concurrent-push-mode',
1008 coreconfigitem('server', 'concurrent-push-mode',
1007 default='strict',
1009 default='strict',
1008 )
1010 )
1009 coreconfigitem('server', 'disablefullbundle',
1011 coreconfigitem('server', 'disablefullbundle',
1010 default=False,
1012 default=False,
1011 )
1013 )
1012 coreconfigitem('server', 'maxhttpheaderlen',
1014 coreconfigitem('server', 'maxhttpheaderlen',
1013 default=1024,
1015 default=1024,
1014 )
1016 )
1015 coreconfigitem('server', 'pullbundle',
1017 coreconfigitem('server', 'pullbundle',
1016 default=False,
1018 default=False,
1017 )
1019 )
1018 coreconfigitem('server', 'preferuncompressed',
1020 coreconfigitem('server', 'preferuncompressed',
1019 default=False,
1021 default=False,
1020 )
1022 )
1021 coreconfigitem('server', 'streamunbundle',
1023 coreconfigitem('server', 'streamunbundle',
1022 default=False,
1024 default=False,
1023 )
1025 )
1024 coreconfigitem('server', 'uncompressed',
1026 coreconfigitem('server', 'uncompressed',
1025 default=True,
1027 default=True,
1026 )
1028 )
1027 coreconfigitem('server', 'uncompressedallowsecret',
1029 coreconfigitem('server', 'uncompressedallowsecret',
1028 default=False,
1030 default=False,
1029 )
1031 )
1030 coreconfigitem('server', 'validate',
1032 coreconfigitem('server', 'validate',
1031 default=False,
1033 default=False,
1032 )
1034 )
1033 coreconfigitem('server', 'zliblevel',
1035 coreconfigitem('server', 'zliblevel',
1034 default=-1,
1036 default=-1,
1035 )
1037 )
1036 coreconfigitem('server', 'zstdlevel',
1038 coreconfigitem('server', 'zstdlevel',
1037 default=3,
1039 default=3,
1038 )
1040 )
1039 coreconfigitem('share', 'pool',
1041 coreconfigitem('share', 'pool',
1040 default=None,
1042 default=None,
1041 )
1043 )
1042 coreconfigitem('share', 'poolnaming',
1044 coreconfigitem('share', 'poolnaming',
1043 default='identity',
1045 default='identity',
1044 )
1046 )
1045 coreconfigitem('smtp', 'host',
1047 coreconfigitem('smtp', 'host',
1046 default=None,
1048 default=None,
1047 )
1049 )
1048 coreconfigitem('smtp', 'local_hostname',
1050 coreconfigitem('smtp', 'local_hostname',
1049 default=None,
1051 default=None,
1050 )
1052 )
1051 coreconfigitem('smtp', 'password',
1053 coreconfigitem('smtp', 'password',
1052 default=None,
1054 default=None,
1053 )
1055 )
1054 coreconfigitem('smtp', 'port',
1056 coreconfigitem('smtp', 'port',
1055 default=dynamicdefault,
1057 default=dynamicdefault,
1056 )
1058 )
1057 coreconfigitem('smtp', 'tls',
1059 coreconfigitem('smtp', 'tls',
1058 default='none',
1060 default='none',
1059 )
1061 )
1060 coreconfigitem('smtp', 'username',
1062 coreconfigitem('smtp', 'username',
1061 default=None,
1063 default=None,
1062 )
1064 )
1063 coreconfigitem('sparse', 'missingwarning',
1065 coreconfigitem('sparse', 'missingwarning',
1064 default=True,
1066 default=True,
1065 )
1067 )
1066 coreconfigitem('subrepos', 'allowed',
1068 coreconfigitem('subrepos', 'allowed',
1067 default=dynamicdefault, # to make backporting simpler
1069 default=dynamicdefault, # to make backporting simpler
1068 )
1070 )
1069 coreconfigitem('subrepos', 'hg:allowed',
1071 coreconfigitem('subrepos', 'hg:allowed',
1070 default=dynamicdefault,
1072 default=dynamicdefault,
1071 )
1073 )
1072 coreconfigitem('subrepos', 'git:allowed',
1074 coreconfigitem('subrepos', 'git:allowed',
1073 default=dynamicdefault,
1075 default=dynamicdefault,
1074 )
1076 )
1075 coreconfigitem('subrepos', 'svn:allowed',
1077 coreconfigitem('subrepos', 'svn:allowed',
1076 default=dynamicdefault,
1078 default=dynamicdefault,
1077 )
1079 )
1078 coreconfigitem('templates', '.*',
1080 coreconfigitem('templates', '.*',
1079 default=None,
1081 default=None,
1080 generic=True,
1082 generic=True,
1081 )
1083 )
1082 coreconfigitem('trusted', 'groups',
1084 coreconfigitem('trusted', 'groups',
1083 default=list,
1085 default=list,
1084 )
1086 )
1085 coreconfigitem('trusted', 'users',
1087 coreconfigitem('trusted', 'users',
1086 default=list,
1088 default=list,
1087 )
1089 )
1088 coreconfigitem('ui', '_usedassubrepo',
1090 coreconfigitem('ui', '_usedassubrepo',
1089 default=False,
1091 default=False,
1090 )
1092 )
1091 coreconfigitem('ui', 'allowemptycommit',
1093 coreconfigitem('ui', 'allowemptycommit',
1092 default=False,
1094 default=False,
1093 )
1095 )
1094 coreconfigitem('ui', 'archivemeta',
1096 coreconfigitem('ui', 'archivemeta',
1095 default=True,
1097 default=True,
1096 )
1098 )
1097 coreconfigitem('ui', 'askusername',
1099 coreconfigitem('ui', 'askusername',
1098 default=False,
1100 default=False,
1099 )
1101 )
1100 coreconfigitem('ui', 'clonebundlefallback',
1102 coreconfigitem('ui', 'clonebundlefallback',
1101 default=False,
1103 default=False,
1102 )
1104 )
1103 coreconfigitem('ui', 'clonebundleprefers',
1105 coreconfigitem('ui', 'clonebundleprefers',
1104 default=list,
1106 default=list,
1105 )
1107 )
1106 coreconfigitem('ui', 'clonebundles',
1108 coreconfigitem('ui', 'clonebundles',
1107 default=True,
1109 default=True,
1108 )
1110 )
1109 coreconfigitem('ui', 'color',
1111 coreconfigitem('ui', 'color',
1110 default='auto',
1112 default='auto',
1111 )
1113 )
1112 coreconfigitem('ui', 'commitsubrepos',
1114 coreconfigitem('ui', 'commitsubrepos',
1113 default=False,
1115 default=False,
1114 )
1116 )
1115 coreconfigitem('ui', 'debug',
1117 coreconfigitem('ui', 'debug',
1116 default=False,
1118 default=False,
1117 )
1119 )
1118 coreconfigitem('ui', 'debugger',
1120 coreconfigitem('ui', 'debugger',
1119 default=None,
1121 default=None,
1120 )
1122 )
1121 coreconfigitem('ui', 'editor',
1123 coreconfigitem('ui', 'editor',
1122 default=dynamicdefault,
1124 default=dynamicdefault,
1123 )
1125 )
1124 coreconfigitem('ui', 'fallbackencoding',
1126 coreconfigitem('ui', 'fallbackencoding',
1125 default=None,
1127 default=None,
1126 )
1128 )
1127 coreconfigitem('ui', 'forcecwd',
1129 coreconfigitem('ui', 'forcecwd',
1128 default=None,
1130 default=None,
1129 )
1131 )
1130 coreconfigitem('ui', 'forcemerge',
1132 coreconfigitem('ui', 'forcemerge',
1131 default=None,
1133 default=None,
1132 )
1134 )
1133 coreconfigitem('ui', 'formatdebug',
1135 coreconfigitem('ui', 'formatdebug',
1134 default=False,
1136 default=False,
1135 )
1137 )
1136 coreconfigitem('ui', 'formatjson',
1138 coreconfigitem('ui', 'formatjson',
1137 default=False,
1139 default=False,
1138 )
1140 )
1139 coreconfigitem('ui', 'formatted',
1141 coreconfigitem('ui', 'formatted',
1140 default=None,
1142 default=None,
1141 )
1143 )
1142 coreconfigitem('ui', 'graphnodetemplate',
1144 coreconfigitem('ui', 'graphnodetemplate',
1143 default=None,
1145 default=None,
1144 )
1146 )
1145 coreconfigitem('ui', 'interactive',
1147 coreconfigitem('ui', 'interactive',
1146 default=None,
1148 default=None,
1147 )
1149 )
1148 coreconfigitem('ui', 'interface',
1150 coreconfigitem('ui', 'interface',
1149 default=None,
1151 default=None,
1150 )
1152 )
1151 coreconfigitem('ui', 'interface.chunkselector',
1153 coreconfigitem('ui', 'interface.chunkselector',
1152 default=None,
1154 default=None,
1153 )
1155 )
1154 coreconfigitem('ui', 'large-file-limit',
1156 coreconfigitem('ui', 'large-file-limit',
1155 default=10000000,
1157 default=10000000,
1156 )
1158 )
1157 coreconfigitem('ui', 'logblockedtimes',
1159 coreconfigitem('ui', 'logblockedtimes',
1158 default=False,
1160 default=False,
1159 )
1161 )
1160 coreconfigitem('ui', 'logtemplate',
1162 coreconfigitem('ui', 'logtemplate',
1161 default=None,
1163 default=None,
1162 )
1164 )
1163 coreconfigitem('ui', 'merge',
1165 coreconfigitem('ui', 'merge',
1164 default=None,
1166 default=None,
1165 )
1167 )
1166 coreconfigitem('ui', 'mergemarkers',
1168 coreconfigitem('ui', 'mergemarkers',
1167 default='basic',
1169 default='basic',
1168 )
1170 )
1169 coreconfigitem('ui', 'mergemarkertemplate',
1171 coreconfigitem('ui', 'mergemarkertemplate',
1170 default=('{node|short} '
1172 default=('{node|short} '
1171 '{ifeq(tags, "tip", "", '
1173 '{ifeq(tags, "tip", "", '
1172 'ifeq(tags, "", "", "{tags} "))}'
1174 'ifeq(tags, "", "", "{tags} "))}'
1173 '{if(bookmarks, "{bookmarks} ")}'
1175 '{if(bookmarks, "{bookmarks} ")}'
1174 '{ifeq(branch, "default", "", "{branch} ")}'
1176 '{ifeq(branch, "default", "", "{branch} ")}'
1175 '- {author|user}: {desc|firstline}')
1177 '- {author|user}: {desc|firstline}')
1176 )
1178 )
1177 coreconfigitem('ui', 'message-output',
1179 coreconfigitem('ui', 'message-output',
1178 default='stdio',
1180 default='stdio',
1179 )
1181 )
1180 coreconfigitem('ui', 'nontty',
1182 coreconfigitem('ui', 'nontty',
1181 default=False,
1183 default=False,
1182 )
1184 )
1183 coreconfigitem('ui', 'origbackuppath',
1185 coreconfigitem('ui', 'origbackuppath',
1184 default=None,
1186 default=None,
1185 )
1187 )
1186 coreconfigitem('ui', 'paginate',
1188 coreconfigitem('ui', 'paginate',
1187 default=True,
1189 default=True,
1188 )
1190 )
1189 coreconfigitem('ui', 'patch',
1191 coreconfigitem('ui', 'patch',
1190 default=None,
1192 default=None,
1191 )
1193 )
1192 coreconfigitem('ui', 'pre-merge-tool-output-template',
1194 coreconfigitem('ui', 'pre-merge-tool-output-template',
1193 default=None,
1195 default=None,
1194 )
1196 )
1195 coreconfigitem('ui', 'portablefilenames',
1197 coreconfigitem('ui', 'portablefilenames',
1196 default='warn',
1198 default='warn',
1197 )
1199 )
1198 coreconfigitem('ui', 'promptecho',
1200 coreconfigitem('ui', 'promptecho',
1199 default=False,
1201 default=False,
1200 )
1202 )
1201 coreconfigitem('ui', 'quiet',
1203 coreconfigitem('ui', 'quiet',
1202 default=False,
1204 default=False,
1203 )
1205 )
1204 coreconfigitem('ui', 'quietbookmarkmove',
1206 coreconfigitem('ui', 'quietbookmarkmove',
1205 default=False,
1207 default=False,
1206 )
1208 )
1207 coreconfigitem('ui', 'relative-paths',
1209 coreconfigitem('ui', 'relative-paths',
1208 default=False,
1210 default=False,
1209 )
1211 )
1210 coreconfigitem('ui', 'remotecmd',
1212 coreconfigitem('ui', 'remotecmd',
1211 default='hg',
1213 default='hg',
1212 )
1214 )
1213 coreconfigitem('ui', 'report_untrusted',
1215 coreconfigitem('ui', 'report_untrusted',
1214 default=True,
1216 default=True,
1215 )
1217 )
1216 coreconfigitem('ui', 'rollback',
1218 coreconfigitem('ui', 'rollback',
1217 default=True,
1219 default=True,
1218 )
1220 )
1219 coreconfigitem('ui', 'signal-safe-lock',
1221 coreconfigitem('ui', 'signal-safe-lock',
1220 default=True,
1222 default=True,
1221 )
1223 )
1222 coreconfigitem('ui', 'slash',
1224 coreconfigitem('ui', 'slash',
1223 default=False,
1225 default=False,
1224 )
1226 )
1225 coreconfigitem('ui', 'ssh',
1227 coreconfigitem('ui', 'ssh',
1226 default='ssh',
1228 default='ssh',
1227 )
1229 )
1228 coreconfigitem('ui', 'ssherrorhint',
1230 coreconfigitem('ui', 'ssherrorhint',
1229 default=None,
1231 default=None,
1230 )
1232 )
1231 coreconfigitem('ui', 'statuscopies',
1233 coreconfigitem('ui', 'statuscopies',
1232 default=False,
1234 default=False,
1233 )
1235 )
1234 coreconfigitem('ui', 'strict',
1236 coreconfigitem('ui', 'strict',
1235 default=False,
1237 default=False,
1236 )
1238 )
1237 coreconfigitem('ui', 'style',
1239 coreconfigitem('ui', 'style',
1238 default='',
1240 default='',
1239 )
1241 )
1240 coreconfigitem('ui', 'supportcontact',
1242 coreconfigitem('ui', 'supportcontact',
1241 default=None,
1243 default=None,
1242 )
1244 )
1243 coreconfigitem('ui', 'textwidth',
1245 coreconfigitem('ui', 'textwidth',
1244 default=78,
1246 default=78,
1245 )
1247 )
1246 coreconfigitem('ui', 'timeout',
1248 coreconfigitem('ui', 'timeout',
1247 default='600',
1249 default='600',
1248 )
1250 )
1249 coreconfigitem('ui', 'timeout.warn',
1251 coreconfigitem('ui', 'timeout.warn',
1250 default=0,
1252 default=0,
1251 )
1253 )
1252 coreconfigitem('ui', 'traceback',
1254 coreconfigitem('ui', 'traceback',
1253 default=False,
1255 default=False,
1254 )
1256 )
1255 coreconfigitem('ui', 'tweakdefaults',
1257 coreconfigitem('ui', 'tweakdefaults',
1256 default=False,
1258 default=False,
1257 )
1259 )
1258 coreconfigitem('ui', 'username',
1260 coreconfigitem('ui', 'username',
1259 alias=[('ui', 'user')]
1261 alias=[('ui', 'user')]
1260 )
1262 )
1261 coreconfigitem('ui', 'verbose',
1263 coreconfigitem('ui', 'verbose',
1262 default=False,
1264 default=False,
1263 )
1265 )
1264 coreconfigitem('verify', 'skipflags',
1266 coreconfigitem('verify', 'skipflags',
1265 default=None,
1267 default=None,
1266 )
1268 )
1267 coreconfigitem('web', 'allowbz2',
1269 coreconfigitem('web', 'allowbz2',
1268 default=False,
1270 default=False,
1269 )
1271 )
1270 coreconfigitem('web', 'allowgz',
1272 coreconfigitem('web', 'allowgz',
1271 default=False,
1273 default=False,
1272 )
1274 )
1273 coreconfigitem('web', 'allow-pull',
1275 coreconfigitem('web', 'allow-pull',
1274 alias=[('web', 'allowpull')],
1276 alias=[('web', 'allowpull')],
1275 default=True,
1277 default=True,
1276 )
1278 )
1277 coreconfigitem('web', 'allow-push',
1279 coreconfigitem('web', 'allow-push',
1278 alias=[('web', 'allow_push')],
1280 alias=[('web', 'allow_push')],
1279 default=list,
1281 default=list,
1280 )
1282 )
1281 coreconfigitem('web', 'allowzip',
1283 coreconfigitem('web', 'allowzip',
1282 default=False,
1284 default=False,
1283 )
1285 )
1284 coreconfigitem('web', 'archivesubrepos',
1286 coreconfigitem('web', 'archivesubrepos',
1285 default=False,
1287 default=False,
1286 )
1288 )
1287 coreconfigitem('web', 'cache',
1289 coreconfigitem('web', 'cache',
1288 default=True,
1290 default=True,
1289 )
1291 )
1290 coreconfigitem('web', 'comparisoncontext',
1292 coreconfigitem('web', 'comparisoncontext',
1291 default=5,
1293 default=5,
1292 )
1294 )
1293 coreconfigitem('web', 'contact',
1295 coreconfigitem('web', 'contact',
1294 default=None,
1296 default=None,
1295 )
1297 )
1296 coreconfigitem('web', 'deny_push',
1298 coreconfigitem('web', 'deny_push',
1297 default=list,
1299 default=list,
1298 )
1300 )
1299 coreconfigitem('web', 'guessmime',
1301 coreconfigitem('web', 'guessmime',
1300 default=False,
1302 default=False,
1301 )
1303 )
1302 coreconfigitem('web', 'hidden',
1304 coreconfigitem('web', 'hidden',
1303 default=False,
1305 default=False,
1304 )
1306 )
1305 coreconfigitem('web', 'labels',
1307 coreconfigitem('web', 'labels',
1306 default=list,
1308 default=list,
1307 )
1309 )
1308 coreconfigitem('web', 'logoimg',
1310 coreconfigitem('web', 'logoimg',
1309 default='hglogo.png',
1311 default='hglogo.png',
1310 )
1312 )
1311 coreconfigitem('web', 'logourl',
1313 coreconfigitem('web', 'logourl',
1312 default='https://mercurial-scm.org/',
1314 default='https://mercurial-scm.org/',
1313 )
1315 )
1314 coreconfigitem('web', 'accesslog',
1316 coreconfigitem('web', 'accesslog',
1315 default='-',
1317 default='-',
1316 )
1318 )
1317 coreconfigitem('web', 'address',
1319 coreconfigitem('web', 'address',
1318 default='',
1320 default='',
1319 )
1321 )
1320 coreconfigitem('web', 'allow-archive',
1322 coreconfigitem('web', 'allow-archive',
1321 alias=[('web', 'allow_archive')],
1323 alias=[('web', 'allow_archive')],
1322 default=list,
1324 default=list,
1323 )
1325 )
1324 coreconfigitem('web', 'allow_read',
1326 coreconfigitem('web', 'allow_read',
1325 default=list,
1327 default=list,
1326 )
1328 )
1327 coreconfigitem('web', 'baseurl',
1329 coreconfigitem('web', 'baseurl',
1328 default=None,
1330 default=None,
1329 )
1331 )
1330 coreconfigitem('web', 'cacerts',
1332 coreconfigitem('web', 'cacerts',
1331 default=None,
1333 default=None,
1332 )
1334 )
1333 coreconfigitem('web', 'certificate',
1335 coreconfigitem('web', 'certificate',
1334 default=None,
1336 default=None,
1335 )
1337 )
1336 coreconfigitem('web', 'collapse',
1338 coreconfigitem('web', 'collapse',
1337 default=False,
1339 default=False,
1338 )
1340 )
1339 coreconfigitem('web', 'csp',
1341 coreconfigitem('web', 'csp',
1340 default=None,
1342 default=None,
1341 )
1343 )
1342 coreconfigitem('web', 'deny_read',
1344 coreconfigitem('web', 'deny_read',
1343 default=list,
1345 default=list,
1344 )
1346 )
1345 coreconfigitem('web', 'descend',
1347 coreconfigitem('web', 'descend',
1346 default=True,
1348 default=True,
1347 )
1349 )
1348 coreconfigitem('web', 'description',
1350 coreconfigitem('web', 'description',
1349 default="",
1351 default="",
1350 )
1352 )
1351 coreconfigitem('web', 'encoding',
1353 coreconfigitem('web', 'encoding',
1352 default=lambda: encoding.encoding,
1354 default=lambda: encoding.encoding,
1353 )
1355 )
1354 coreconfigitem('web', 'errorlog',
1356 coreconfigitem('web', 'errorlog',
1355 default='-',
1357 default='-',
1356 )
1358 )
1357 coreconfigitem('web', 'ipv6',
1359 coreconfigitem('web', 'ipv6',
1358 default=False,
1360 default=False,
1359 )
1361 )
1360 coreconfigitem('web', 'maxchanges',
1362 coreconfigitem('web', 'maxchanges',
1361 default=10,
1363 default=10,
1362 )
1364 )
1363 coreconfigitem('web', 'maxfiles',
1365 coreconfigitem('web', 'maxfiles',
1364 default=10,
1366 default=10,
1365 )
1367 )
1366 coreconfigitem('web', 'maxshortchanges',
1368 coreconfigitem('web', 'maxshortchanges',
1367 default=60,
1369 default=60,
1368 )
1370 )
1369 coreconfigitem('web', 'motd',
1371 coreconfigitem('web', 'motd',
1370 default='',
1372 default='',
1371 )
1373 )
1372 coreconfigitem('web', 'name',
1374 coreconfigitem('web', 'name',
1373 default=dynamicdefault,
1375 default=dynamicdefault,
1374 )
1376 )
1375 coreconfigitem('web', 'port',
1377 coreconfigitem('web', 'port',
1376 default=8000,
1378 default=8000,
1377 )
1379 )
1378 coreconfigitem('web', 'prefix',
1380 coreconfigitem('web', 'prefix',
1379 default='',
1381 default='',
1380 )
1382 )
1381 coreconfigitem('web', 'push_ssl',
1383 coreconfigitem('web', 'push_ssl',
1382 default=True,
1384 default=True,
1383 )
1385 )
1384 coreconfigitem('web', 'refreshinterval',
1386 coreconfigitem('web', 'refreshinterval',
1385 default=20,
1387 default=20,
1386 )
1388 )
1387 coreconfigitem('web', 'server-header',
1389 coreconfigitem('web', 'server-header',
1388 default=None,
1390 default=None,
1389 )
1391 )
1390 coreconfigitem('web', 'static',
1392 coreconfigitem('web', 'static',
1391 default=None,
1393 default=None,
1392 )
1394 )
1393 coreconfigitem('web', 'staticurl',
1395 coreconfigitem('web', 'staticurl',
1394 default=None,
1396 default=None,
1395 )
1397 )
1396 coreconfigitem('web', 'stripes',
1398 coreconfigitem('web', 'stripes',
1397 default=1,
1399 default=1,
1398 )
1400 )
1399 coreconfigitem('web', 'style',
1401 coreconfigitem('web', 'style',
1400 default='paper',
1402 default='paper',
1401 )
1403 )
1402 coreconfigitem('web', 'templates',
1404 coreconfigitem('web', 'templates',
1403 default=None,
1405 default=None,
1404 )
1406 )
1405 coreconfigitem('web', 'view',
1407 coreconfigitem('web', 'view',
1406 default='served',
1408 default='served',
1407 )
1409 )
1408 coreconfigitem('worker', 'backgroundclose',
1410 coreconfigitem('worker', 'backgroundclose',
1409 default=dynamicdefault,
1411 default=dynamicdefault,
1410 )
1412 )
1411 # Windows defaults to a limit of 512 open files. A buffer of 128
1413 # Windows defaults to a limit of 512 open files. A buffer of 128
1412 # should give us enough headway.
1414 # should give us enough headway.
1413 coreconfigitem('worker', 'backgroundclosemaxqueue',
1415 coreconfigitem('worker', 'backgroundclosemaxqueue',
1414 default=384,
1416 default=384,
1415 )
1417 )
1416 coreconfigitem('worker', 'backgroundcloseminfilecount',
1418 coreconfigitem('worker', 'backgroundcloseminfilecount',
1417 default=2048,
1419 default=2048,
1418 )
1420 )
1419 coreconfigitem('worker', 'backgroundclosethreadcount',
1421 coreconfigitem('worker', 'backgroundclosethreadcount',
1420 default=4,
1422 default=4,
1421 )
1423 )
1422 coreconfigitem('worker', 'enabled',
1424 coreconfigitem('worker', 'enabled',
1423 default=True,
1425 default=True,
1424 )
1426 )
1425 coreconfigitem('worker', 'numcpus',
1427 coreconfigitem('worker', 'numcpus',
1426 default=None,
1428 default=None,
1427 )
1429 )
1428
1430
1429 # Rebase related configuration moved to core because other extension are doing
1431 # Rebase related configuration moved to core because other extension are doing
1430 # strange things. For example, shelve import the extensions to reuse some bit
1432 # strange things. For example, shelve import the extensions to reuse some bit
1431 # without formally loading it.
1433 # without formally loading it.
1432 coreconfigitem('commands', 'rebase.requiredest',
1434 coreconfigitem('commands', 'rebase.requiredest',
1433 default=False,
1435 default=False,
1434 )
1436 )
1435 coreconfigitem('experimental', 'rebaseskipobsolete',
1437 coreconfigitem('experimental', 'rebaseskipobsolete',
1436 default=True,
1438 default=True,
1437 )
1439 )
1438 coreconfigitem('rebase', 'singletransaction',
1440 coreconfigitem('rebase', 'singletransaction',
1439 default=False,
1441 default=False,
1440 )
1442 )
1441 coreconfigitem('rebase', 'experimental.inmemory',
1443 coreconfigitem('rebase', 'experimental.inmemory',
1442 default=False,
1444 default=False,
1443 )
1445 )
@@ -1,1888 +1,1888 b''
1 Set up a repo
1 Set up a repo
2
2
3 $ cat <<EOF >> $HGRCPATH
3 $ cat <<EOF >> $HGRCPATH
4 > [ui]
4 > [ui]
5 > interactive = true
5 > interactive = true
6 > [extensions]
6 > [extensions]
7 > record =
7 > record =
8 > EOF
8 > EOF
9
9
10 $ hg init a
10 $ hg init a
11 $ cd a
11 $ cd a
12
12
13 Select no files
13 Select no files
14
14
15 $ touch empty-rw
15 $ touch empty-rw
16 $ hg add empty-rw
16 $ hg add empty-rw
17
17
18 $ hg record --config ui.interactive=false
18 $ hg record --config ui.interactive=false
19 abort: running non-interactively, use commit instead
19 abort: running non-interactively, use commit instead
20 [255]
20 [255]
21 $ hg commit -i --config ui.interactive=false
21 $ hg commit -i --config ui.interactive=false
22 abort: running non-interactively
22 abort: running non-interactively
23 [255]
23 [255]
24 $ hg commit -i empty-rw<<EOF
24 $ hg commit -i empty-rw<<EOF
25 > n
25 > n
26 > EOF
26 > EOF
27 diff --git a/empty-rw b/empty-rw
27 diff --git a/empty-rw b/empty-rw
28 new file mode 100644
28 new file mode 100644
29 examine changes to 'empty-rw'? [Ynesfdaq?] n
29 examine changes to 'empty-rw'? [Ynesfdaq?] n
30
30
31 no changes to record
31 no changes to record
32 [1]
32 [1]
33
33
34 $ hg tip -p
34 $ hg tip -p
35 changeset: -1:000000000000
35 changeset: -1:000000000000
36 tag: tip
36 tag: tip
37 user:
37 user:
38 date: Thu Jan 01 00:00:00 1970 +0000
38 date: Thu Jan 01 00:00:00 1970 +0000
39
39
40
40
41
41
42 Select files but no hunks
42 Select files but no hunks
43
43
44 $ hg commit -i empty-rw<<EOF
44 $ hg commit -i empty-rw<<EOF
45 > y
45 > y
46 > n
46 > n
47 > EOF
47 > EOF
48 diff --git a/empty-rw b/empty-rw
48 diff --git a/empty-rw b/empty-rw
49 new file mode 100644
49 new file mode 100644
50 examine changes to 'empty-rw'? [Ynesfdaq?] y
50 examine changes to 'empty-rw'? [Ynesfdaq?] y
51
51
52 abort: empty commit message
52 abort: empty commit message
53 [255]
53 [255]
54
54
55 $ hg tip -p
55 $ hg tip -p
56 changeset: -1:000000000000
56 changeset: -1:000000000000
57 tag: tip
57 tag: tip
58 user:
58 user:
59 date: Thu Jan 01 00:00:00 1970 +0000
59 date: Thu Jan 01 00:00:00 1970 +0000
60
60
61
61
62
62
63 Abort for untracked
63 Abort for untracked
64
64
65 $ touch untracked
65 $ touch untracked
66 $ hg commit -i -m should-fail empty-rw untracked
66 $ hg commit -i -m should-fail empty-rw untracked
67 abort: untracked: file not tracked!
67 abort: untracked: file not tracked!
68 [255]
68 [255]
69 $ rm untracked
69 $ rm untracked
70
70
71 Record empty file
71 Record empty file
72
72
73 $ hg commit -i -d '0 0' -m empty empty-rw<<EOF
73 $ hg commit -i -d '0 0' -m empty empty-rw<<EOF
74 > y
74 > y
75 > y
75 > y
76 > EOF
76 > EOF
77 diff --git a/empty-rw b/empty-rw
77 diff --git a/empty-rw b/empty-rw
78 new file mode 100644
78 new file mode 100644
79 examine changes to 'empty-rw'? [Ynesfdaq?] y
79 examine changes to 'empty-rw'? [Ynesfdaq?] y
80
80
81
81
82 $ hg tip -p
82 $ hg tip -p
83 changeset: 0:c0708cf4e46e
83 changeset: 0:c0708cf4e46e
84 tag: tip
84 tag: tip
85 user: test
85 user: test
86 date: Thu Jan 01 00:00:00 1970 +0000
86 date: Thu Jan 01 00:00:00 1970 +0000
87 summary: empty
87 summary: empty
88
88
89
89
90
90
91 Summary shows we updated to the new cset
91 Summary shows we updated to the new cset
92
92
93 $ hg summary
93 $ hg summary
94 parent: 0:c0708cf4e46e tip
94 parent: 0:c0708cf4e46e tip
95 empty
95 empty
96 branch: default
96 branch: default
97 commit: (clean)
97 commit: (clean)
98 update: (current)
98 update: (current)
99 phases: 1 draft
99 phases: 1 draft
100
100
101 Rename empty file
101 Rename empty file
102
102
103 $ hg mv empty-rw empty-rename
103 $ hg mv empty-rw empty-rename
104 $ hg commit -i -d '1 0' -m rename<<EOF
104 $ hg commit -i -d '1 0' -m rename<<EOF
105 > y
105 > y
106 > EOF
106 > EOF
107 diff --git a/empty-rw b/empty-rename
107 diff --git a/empty-rw b/empty-rename
108 rename from empty-rw
108 rename from empty-rw
109 rename to empty-rename
109 rename to empty-rename
110 examine changes to 'empty-rw' and 'empty-rename'? [Ynesfdaq?] y
110 examine changes to 'empty-rw' and 'empty-rename'? [Ynesfdaq?] y
111
111
112
112
113 $ hg tip -p
113 $ hg tip -p
114 changeset: 1:d695e8dcb197
114 changeset: 1:d695e8dcb197
115 tag: tip
115 tag: tip
116 user: test
116 user: test
117 date: Thu Jan 01 00:00:01 1970 +0000
117 date: Thu Jan 01 00:00:01 1970 +0000
118 summary: rename
118 summary: rename
119
119
120
120
121
121
122 Copy empty file
122 Copy empty file
123
123
124 $ hg cp empty-rename empty-copy
124 $ hg cp empty-rename empty-copy
125 $ hg commit -i -d '2 0' -m copy<<EOF
125 $ hg commit -i -d '2 0' -m copy<<EOF
126 > y
126 > y
127 > EOF
127 > EOF
128 diff --git a/empty-rename b/empty-copy
128 diff --git a/empty-rename b/empty-copy
129 copy from empty-rename
129 copy from empty-rename
130 copy to empty-copy
130 copy to empty-copy
131 examine changes to 'empty-rename' and 'empty-copy'? [Ynesfdaq?] y
131 examine changes to 'empty-rename' and 'empty-copy'? [Ynesfdaq?] y
132
132
133
133
134 $ hg tip -p
134 $ hg tip -p
135 changeset: 2:1d4b90bea524
135 changeset: 2:1d4b90bea524
136 tag: tip
136 tag: tip
137 user: test
137 user: test
138 date: Thu Jan 01 00:00:02 1970 +0000
138 date: Thu Jan 01 00:00:02 1970 +0000
139 summary: copy
139 summary: copy
140
140
141
141
142
142
143 Delete empty file
143 Delete empty file
144
144
145 $ hg rm empty-copy
145 $ hg rm empty-copy
146 $ hg commit -i -d '3 0' -m delete<<EOF
146 $ hg commit -i -d '3 0' -m delete<<EOF
147 > y
147 > y
148 > EOF
148 > EOF
149 diff --git a/empty-copy b/empty-copy
149 diff --git a/empty-copy b/empty-copy
150 deleted file mode 100644
150 deleted file mode 100644
151 examine changes to 'empty-copy'? [Ynesfdaq?] y
151 examine changes to 'empty-copy'? [Ynesfdaq?] y
152
152
153
153
154 $ hg tip -p
154 $ hg tip -p
155 changeset: 3:b39a238f01a1
155 changeset: 3:b39a238f01a1
156 tag: tip
156 tag: tip
157 user: test
157 user: test
158 date: Thu Jan 01 00:00:03 1970 +0000
158 date: Thu Jan 01 00:00:03 1970 +0000
159 summary: delete
159 summary: delete
160
160
161
161
162
162
163 Add binary file
163 Add binary file
164
164
165 $ hg bundle --type v1 --base -2 tip.bundle
165 $ hg bundle --type v1 --base -2 tip.bundle
166 1 changesets found
166 1 changesets found
167 $ hg add tip.bundle
167 $ hg add tip.bundle
168 $ hg commit -i -d '4 0' -m binary<<EOF
168 $ hg commit -i -d '4 0' -m binary<<EOF
169 > y
169 > y
170 > EOF
170 > EOF
171 diff --git a/tip.bundle b/tip.bundle
171 diff --git a/tip.bundle b/tip.bundle
172 new file mode 100644
172 new file mode 100644
173 this is a binary file
173 this is a binary file
174 examine changes to 'tip.bundle'? [Ynesfdaq?] y
174 examine changes to 'tip.bundle'? [Ynesfdaq?] y
175
175
176
176
177 $ hg tip -p
177 $ hg tip -p
178 changeset: 4:ad816da3711e
178 changeset: 4:ad816da3711e
179 tag: tip
179 tag: tip
180 user: test
180 user: test
181 date: Thu Jan 01 00:00:04 1970 +0000
181 date: Thu Jan 01 00:00:04 1970 +0000
182 summary: binary
182 summary: binary
183
183
184 diff -r b39a238f01a1 -r ad816da3711e tip.bundle
184 diff -r b39a238f01a1 -r ad816da3711e tip.bundle
185 Binary file tip.bundle has changed
185 Binary file tip.bundle has changed
186
186
187
187
188 Change binary file
188 Change binary file
189
189
190 $ hg bundle --base -2 --type v1 tip.bundle
190 $ hg bundle --base -2 --type v1 tip.bundle
191 1 changesets found
191 1 changesets found
192 $ hg commit -i -d '5 0' -m binary-change<<EOF
192 $ hg commit -i -d '5 0' -m binary-change<<EOF
193 > y
193 > y
194 > EOF
194 > EOF
195 diff --git a/tip.bundle b/tip.bundle
195 diff --git a/tip.bundle b/tip.bundle
196 this modifies a binary file (all or nothing)
196 this modifies a binary file (all or nothing)
197 examine changes to 'tip.bundle'? [Ynesfdaq?] y
197 examine changes to 'tip.bundle'? [Ynesfdaq?] y
198
198
199
199
200 $ hg tip -p
200 $ hg tip -p
201 changeset: 5:dccd6f3eb485
201 changeset: 5:dccd6f3eb485
202 tag: tip
202 tag: tip
203 user: test
203 user: test
204 date: Thu Jan 01 00:00:05 1970 +0000
204 date: Thu Jan 01 00:00:05 1970 +0000
205 summary: binary-change
205 summary: binary-change
206
206
207 diff -r ad816da3711e -r dccd6f3eb485 tip.bundle
207 diff -r ad816da3711e -r dccd6f3eb485 tip.bundle
208 Binary file tip.bundle has changed
208 Binary file tip.bundle has changed
209
209
210
210
211 Rename and change binary file
211 Rename and change binary file
212
212
213 $ hg mv tip.bundle top.bundle
213 $ hg mv tip.bundle top.bundle
214 $ hg bundle --base -2 --type v1 top.bundle
214 $ hg bundle --base -2 --type v1 top.bundle
215 1 changesets found
215 1 changesets found
216 $ hg commit -i -d '6 0' -m binary-change-rename<<EOF
216 $ hg commit -i -d '6 0' -m binary-change-rename<<EOF
217 > y
217 > y
218 > EOF
218 > EOF
219 diff --git a/tip.bundle b/top.bundle
219 diff --git a/tip.bundle b/top.bundle
220 rename from tip.bundle
220 rename from tip.bundle
221 rename to top.bundle
221 rename to top.bundle
222 this modifies a binary file (all or nothing)
222 this modifies a binary file (all or nothing)
223 examine changes to 'tip.bundle' and 'top.bundle'? [Ynesfdaq?] y
223 examine changes to 'tip.bundle' and 'top.bundle'? [Ynesfdaq?] y
224
224
225
225
226 $ hg tip -p
226 $ hg tip -p
227 changeset: 6:7fa44105f5b3
227 changeset: 6:7fa44105f5b3
228 tag: tip
228 tag: tip
229 user: test
229 user: test
230 date: Thu Jan 01 00:00:06 1970 +0000
230 date: Thu Jan 01 00:00:06 1970 +0000
231 summary: binary-change-rename
231 summary: binary-change-rename
232
232
233 diff -r dccd6f3eb485 -r 7fa44105f5b3 tip.bundle
233 diff -r dccd6f3eb485 -r 7fa44105f5b3 tip.bundle
234 Binary file tip.bundle has changed
234 Binary file tip.bundle has changed
235 diff -r dccd6f3eb485 -r 7fa44105f5b3 top.bundle
235 diff -r dccd6f3eb485 -r 7fa44105f5b3 top.bundle
236 Binary file top.bundle has changed
236 Binary file top.bundle has changed
237
237
238
238
239 Add plain file
239 Add plain file
240
240
241 $ for i in 1 2 3 4 5 6 7 8 9 10; do
241 $ for i in 1 2 3 4 5 6 7 8 9 10; do
242 > echo $i >> plain
242 > echo $i >> plain
243 > done
243 > done
244
244
245 $ hg add plain
245 $ hg add plain
246 $ hg commit -i -d '7 0' -m plain plain<<EOF
246 $ hg commit -i -d '7 0' -m plain plain<<EOF
247 > y
247 > y
248 > y
248 > y
249 > EOF
249 > EOF
250 diff --git a/plain b/plain
250 diff --git a/plain b/plain
251 new file mode 100644
251 new file mode 100644
252 examine changes to 'plain'? [Ynesfdaq?] y
252 examine changes to 'plain'? [Ynesfdaq?] y
253
253
254 @@ -0,0 +1,10 @@
254 @@ -0,0 +1,10 @@
255 +1
255 +1
256 +2
256 +2
257 +3
257 +3
258 +4
258 +4
259 +5
259 +5
260 +6
260 +6
261 +7
261 +7
262 +8
262 +8
263 +9
263 +9
264 +10
264 +10
265 record this change to 'plain'? [Ynesfdaq?] y
265 record this change to 'plain'? [Ynesfdaq?] y
266
266
267 $ hg tip -p
267 $ hg tip -p
268 changeset: 7:11fb457c1be4
268 changeset: 7:11fb457c1be4
269 tag: tip
269 tag: tip
270 user: test
270 user: test
271 date: Thu Jan 01 00:00:07 1970 +0000
271 date: Thu Jan 01 00:00:07 1970 +0000
272 summary: plain
272 summary: plain
273
273
274 diff -r 7fa44105f5b3 -r 11fb457c1be4 plain
274 diff -r 7fa44105f5b3 -r 11fb457c1be4 plain
275 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
275 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
276 +++ b/plain Thu Jan 01 00:00:07 1970 +0000
276 +++ b/plain Thu Jan 01 00:00:07 1970 +0000
277 @@ -0,0 +1,10 @@
277 @@ -0,0 +1,10 @@
278 +1
278 +1
279 +2
279 +2
280 +3
280 +3
281 +4
281 +4
282 +5
282 +5
283 +6
283 +6
284 +7
284 +7
285 +8
285 +8
286 +9
286 +9
287 +10
287 +10
288
288
289 Modify end of plain file with username unset
289 Modify end of plain file with username unset
290
290
291 $ echo 11 >> plain
291 $ echo 11 >> plain
292 $ unset HGUSER
292 $ unset HGUSER
293 $ hg commit -i --config ui.username= -d '8 0' -m end plain
293 $ hg commit -i --config ui.username= -d '8 0' -m end plain
294 abort: no username supplied
294 abort: no username supplied
295 (use 'hg config --edit' to set your username)
295 (use 'hg config --edit' to set your username)
296 [255]
296 [255]
297
297
298
298
299 Modify end of plain file, also test that diffopts are accounted for
299 Modify end of plain file, also test that diffopts are accounted for
300
300
301 $ HGUSER="test"
301 $ HGUSER="test"
302 $ export HGUSER
302 $ export HGUSER
303 $ hg commit -i --config diff.showfunc=true -d '8 0' -m end plain <<EOF
303 $ hg commit -i --config diff.showfunc=true -d '8 0' -m end plain <<EOF
304 > y
304 > y
305 > y
305 > y
306 > EOF
306 > EOF
307 diff --git a/plain b/plain
307 diff --git a/plain b/plain
308 1 hunks, 1 lines changed
308 1 hunks, 1 lines changed
309 examine changes to 'plain'? [Ynesfdaq?] y
309 examine changes to 'plain'? [Ynesfdaq?] y
310
310
311 @@ -8,3 +8,4 @@ 7
311 @@ -8,3 +8,4 @@ 7
312 8
312 8
313 9
313 9
314 10
314 10
315 +11
315 +11
316 record this change to 'plain'? [Ynesfdaq?] y
316 record this change to 'plain'? [Ynesfdaq?] y
317
317
318
318
319 Modify end of plain file, no EOL
319 Modify end of plain file, no EOL
320
320
321 $ hg tip --template '{node}' >> plain
321 $ hg tip --template '{node}' >> plain
322 $ hg commit -i -d '9 0' -m noeol plain <<EOF
322 $ hg commit -i -d '9 0' -m noeol plain <<EOF
323 > y
323 > y
324 > y
324 > y
325 > EOF
325 > EOF
326 diff --git a/plain b/plain
326 diff --git a/plain b/plain
327 1 hunks, 1 lines changed
327 1 hunks, 1 lines changed
328 examine changes to 'plain'? [Ynesfdaq?] y
328 examine changes to 'plain'? [Ynesfdaq?] y
329
329
330 @@ -9,3 +9,4 @@ 8
330 @@ -9,3 +9,4 @@ 8
331 9
331 9
332 10
332 10
333 11
333 11
334 +7264f99c5f5ff3261504828afa4fb4d406c3af54
334 +7264f99c5f5ff3261504828afa4fb4d406c3af54
335 \ No newline at end of file
335 \ No newline at end of file
336 record this change to 'plain'? [Ynesfdaq?] y
336 record this change to 'plain'? [Ynesfdaq?] y
337
337
338
338
339 Record showfunc should preserve function across sections
339 Record showfunc should preserve function across sections
340
340
341 $ cat > f1.py <<NO_CHECK_EOF
341 $ cat > f1.py <<NO_CHECK_EOF
342 > def annotate(ui, repo, *pats, **opts):
342 > def annotate(ui, repo, *pats, **opts):
343 > """show changeset information by line for each file
343 > """show changeset information by line for each file
344 >
344 >
345 > List changes in files, showing the revision id responsible for
345 > List changes in files, showing the revision id responsible for
346 > each line.
346 > each line.
347 >
347 >
348 > This command is useful for discovering when a change was made and
348 > This command is useful for discovering when a change was made and
349 > by whom.
349 > by whom.
350 >
350 >
351 > If you include -f/-u/-d, the revision number is suppressed unless
351 > If you include -f/-u/-d, the revision number is suppressed unless
352 > you also include -the revision number is suppressed unless
352 > you also include -the revision number is suppressed unless
353 > you also include -n.
353 > you also include -n.
354 >
354 >
355 > Without the -a/--text option, annotate will avoid processing files
355 > Without the -a/--text option, annotate will avoid processing files
356 > it detects as binary. With -a, annotate will annotate the file
356 > it detects as binary. With -a, annotate will annotate the file
357 > anyway, although the results will probably be neither useful
357 > anyway, although the results will probably be neither useful
358 > nor desirable.
358 > nor desirable.
359 >
359 >
360 > Returns 0 on success.
360 > Returns 0 on success.
361 > """
361 > """
362 > return 0
362 > return 0
363 > def archive(ui, repo, dest, **opts):
363 > def archive(ui, repo, dest, **opts):
364 > '''create an unversioned archive of a repository revision
364 > '''create an unversioned archive of a repository revision
365 >
365 >
366 > By default, the revision used is the parent of the working
366 > By default, the revision used is the parent of the working
367 > directory; use -r/--rev to specify a different revision.
367 > directory; use -r/--rev to specify a different revision.
368 >
368 >
369 > The archive type is automatically detected based on file
369 > The archive type is automatically detected based on file
370 > extension (to override, use -t/--type).
370 > extension (to override, use -t/--type).
371 >
371 >
372 > .. container:: verbose
372 > .. container:: verbose
373 >
373 >
374 > Valid types are:
374 > Valid types are:
375 > NO_CHECK_EOF
375 > NO_CHECK_EOF
376 $ hg add f1.py
376 $ hg add f1.py
377 $ hg commit -m funcs
377 $ hg commit -m funcs
378 $ cat > f1.py <<NO_CHECK_EOF
378 $ cat > f1.py <<NO_CHECK_EOF
379 > def annotate(ui, repo, *pats, **opts):
379 > def annotate(ui, repo, *pats, **opts):
380 > """show changeset information by line for each file
380 > """show changeset information by line for each file
381 >
381 >
382 > List changes in files, showing the revision id responsible for
382 > List changes in files, showing the revision id responsible for
383 > each line
383 > each line
384 >
384 >
385 > This command is useful for discovering when a change was made and
385 > This command is useful for discovering when a change was made and
386 > by whom.
386 > by whom.
387 >
387 >
388 > Without the -a/--text option, annotate will avoid processing files
388 > Without the -a/--text option, annotate will avoid processing files
389 > it detects as binary. With -a, annotate will annotate the file
389 > it detects as binary. With -a, annotate will annotate the file
390 > anyway, although the results will probably be neither useful
390 > anyway, although the results will probably be neither useful
391 > nor desirable.
391 > nor desirable.
392 >
392 >
393 > Returns 0 on success.
393 > Returns 0 on success.
394 > """
394 > """
395 > return 0
395 > return 0
396 > def archive(ui, repo, dest, **opts):
396 > def archive(ui, repo, dest, **opts):
397 > '''create an unversioned archive of a repository revision
397 > '''create an unversioned archive of a repository revision
398 >
398 >
399 > By default, the revision used is the parent of the working
399 > By default, the revision used is the parent of the working
400 > directory; use -r/--rev to specify a different revision.
400 > directory; use -r/--rev to specify a different revision.
401 >
401 >
402 > The archive type is automatically detected based on file
402 > The archive type is automatically detected based on file
403 > extension (or override using -t/--type).
403 > extension (or override using -t/--type).
404 >
404 >
405 > .. container:: verbose
405 > .. container:: verbose
406 >
406 >
407 > Valid types are:
407 > Valid types are:
408 > NO_CHECK_EOF
408 > NO_CHECK_EOF
409 $ hg commit -i -m interactive <<EOF
409 $ hg commit -i -m interactive <<EOF
410 > y
410 > y
411 > y
411 > y
412 > y
412 > y
413 > y
413 > y
414 > EOF
414 > EOF
415 diff --git a/f1.py b/f1.py
415 diff --git a/f1.py b/f1.py
416 3 hunks, 6 lines changed
416 3 hunks, 6 lines changed
417 examine changes to 'f1.py'? [Ynesfdaq?] y
417 examine changes to 'f1.py'? [Ynesfdaq?] y
418
418
419 @@ -2,8 +2,8 @@ def annotate(ui, repo, *pats, **opts):
419 @@ -2,8 +2,8 @@ def annotate(ui, repo, *pats, **opts):
420 """show changeset information by line for each file
420 """show changeset information by line for each file
421
421
422 List changes in files, showing the revision id responsible for
422 List changes in files, showing the revision id responsible for
423 - each line.
423 - each line.
424 + each line
424 + each line
425
425
426 This command is useful for discovering when a change was made and
426 This command is useful for discovering when a change was made and
427 by whom.
427 by whom.
428
428
429 record change 1/3 to 'f1.py'? [Ynesfdaq?] y
429 record change 1/3 to 'f1.py'? [Ynesfdaq?] y
430
430
431 @@ -6,11 +6,7 @@ def annotate(ui, repo, *pats, **opts):
431 @@ -6,11 +6,7 @@ def annotate(ui, repo, *pats, **opts):
432
432
433 This command is useful for discovering when a change was made and
433 This command is useful for discovering when a change was made and
434 by whom.
434 by whom.
435
435
436 - If you include -f/-u/-d, the revision number is suppressed unless
436 - If you include -f/-u/-d, the revision number is suppressed unless
437 - you also include -the revision number is suppressed unless
437 - you also include -the revision number is suppressed unless
438 - you also include -n.
438 - you also include -n.
439 -
439 -
440 Without the -a/--text option, annotate will avoid processing files
440 Without the -a/--text option, annotate will avoid processing files
441 it detects as binary. With -a, annotate will annotate the file
441 it detects as binary. With -a, annotate will annotate the file
442 anyway, although the results will probably be neither useful
442 anyway, although the results will probably be neither useful
443 record change 2/3 to 'f1.py'? [Ynesfdaq?] y
443 record change 2/3 to 'f1.py'? [Ynesfdaq?] y
444
444
445 @@ -26,7 +22,7 @@ def archive(ui, repo, dest, **opts):
445 @@ -26,7 +22,7 @@ def archive(ui, repo, dest, **opts):
446 directory; use -r/--rev to specify a different revision.
446 directory; use -r/--rev to specify a different revision.
447
447
448 The archive type is automatically detected based on file
448 The archive type is automatically detected based on file
449 - extension (to override, use -t/--type).
449 - extension (to override, use -t/--type).
450 + extension (or override using -t/--type).
450 + extension (or override using -t/--type).
451
451
452 .. container:: verbose
452 .. container:: verbose
453
453
454 record change 3/3 to 'f1.py'? [Ynesfdaq?] y
454 record change 3/3 to 'f1.py'? [Ynesfdaq?] y
455
455
456
456
457 Modify end of plain file, add EOL
457 Modify end of plain file, add EOL
458
458
459 $ echo >> plain
459 $ echo >> plain
460 $ echo 1 > plain2
460 $ echo 1 > plain2
461 $ hg add plain2
461 $ hg add plain2
462 $ hg commit -i -d '10 0' -m eol plain plain2 <<EOF
462 $ hg commit -i -d '10 0' -m eol plain plain2 <<EOF
463 > y
463 > y
464 > y
464 > y
465 > y
465 > y
466 > y
466 > y
467 > EOF
467 > EOF
468 diff --git a/plain b/plain
468 diff --git a/plain b/plain
469 1 hunks, 1 lines changed
469 1 hunks, 1 lines changed
470 examine changes to 'plain'? [Ynesfdaq?] y
470 examine changes to 'plain'? [Ynesfdaq?] y
471
471
472 @@ -9,4 +9,4 @@ 8
472 @@ -9,4 +9,4 @@ 8
473 9
473 9
474 10
474 10
475 11
475 11
476 -7264f99c5f5ff3261504828afa4fb4d406c3af54
476 -7264f99c5f5ff3261504828afa4fb4d406c3af54
477 \ No newline at end of file
477 \ No newline at end of file
478 +7264f99c5f5ff3261504828afa4fb4d406c3af54
478 +7264f99c5f5ff3261504828afa4fb4d406c3af54
479 record change 1/2 to 'plain'? [Ynesfdaq?] y
479 record change 1/2 to 'plain'? [Ynesfdaq?] y
480
480
481 diff --git a/plain2 b/plain2
481 diff --git a/plain2 b/plain2
482 new file mode 100644
482 new file mode 100644
483 examine changes to 'plain2'? [Ynesfdaq?] y
483 examine changes to 'plain2'? [Ynesfdaq?] y
484
484
485 @@ -0,0 +1,1 @@
485 @@ -0,0 +1,1 @@
486 +1
486 +1
487 record change 2/2 to 'plain2'? [Ynesfdaq?] y
487 record change 2/2 to 'plain2'? [Ynesfdaq?] y
488
488
489 Modify beginning, trim end, record both, add another file to test
489 Modify beginning, trim end, record both, add another file to test
490 changes numbering
490 changes numbering
491
491
492 $ rm plain
492 $ rm plain
493 $ for i in 2 2 3 4 5 6 7 8 9 10; do
493 $ for i in 2 2 3 4 5 6 7 8 9 10; do
494 > echo $i >> plain
494 > echo $i >> plain
495 > done
495 > done
496 $ echo 2 >> plain2
496 $ echo 2 >> plain2
497
497
498 $ hg commit -i -d '10 0' -m begin-and-end plain plain2 <<EOF
498 $ hg commit -i -d '10 0' -m begin-and-end plain plain2 <<EOF
499 > y
499 > y
500 > y
500 > y
501 > y
501 > y
502 > y
502 > y
503 > y
503 > y
504 > EOF
504 > EOF
505 diff --git a/plain b/plain
505 diff --git a/plain b/plain
506 2 hunks, 3 lines changed
506 2 hunks, 3 lines changed
507 examine changes to 'plain'? [Ynesfdaq?] y
507 examine changes to 'plain'? [Ynesfdaq?] y
508
508
509 @@ -1,4 +1,4 @@
509 @@ -1,4 +1,4 @@
510 -1
510 -1
511 +2
511 +2
512 2
512 2
513 3
513 3
514 4
514 4
515 record change 1/3 to 'plain'? [Ynesfdaq?] y
515 record change 1/3 to 'plain'? [Ynesfdaq?] y
516
516
517 @@ -8,5 +8,3 @@ 7
517 @@ -8,5 +8,3 @@ 7
518 8
518 8
519 9
519 9
520 10
520 10
521 -11
521 -11
522 -7264f99c5f5ff3261504828afa4fb4d406c3af54
522 -7264f99c5f5ff3261504828afa4fb4d406c3af54
523 record change 2/3 to 'plain'? [Ynesfdaq?] y
523 record change 2/3 to 'plain'? [Ynesfdaq?] y
524
524
525 diff --git a/plain2 b/plain2
525 diff --git a/plain2 b/plain2
526 1 hunks, 1 lines changed
526 1 hunks, 1 lines changed
527 examine changes to 'plain2'? [Ynesfdaq?] y
527 examine changes to 'plain2'? [Ynesfdaq?] y
528
528
529 @@ -1,1 +1,2 @@
529 @@ -1,1 +1,2 @@
530 1
530 1
531 +2
531 +2
532 record change 3/3 to 'plain2'? [Ynesfdaq?] y
532 record change 3/3 to 'plain2'? [Ynesfdaq?] y
533
533
534
534
535 $ hg tip -p
535 $ hg tip -p
536 changeset: 13:f941910cff62
536 changeset: 13:f941910cff62
537 tag: tip
537 tag: tip
538 user: test
538 user: test
539 date: Thu Jan 01 00:00:10 1970 +0000
539 date: Thu Jan 01 00:00:10 1970 +0000
540 summary: begin-and-end
540 summary: begin-and-end
541
541
542 diff -r 33abe24d946c -r f941910cff62 plain
542 diff -r 33abe24d946c -r f941910cff62 plain
543 --- a/plain Thu Jan 01 00:00:10 1970 +0000
543 --- a/plain Thu Jan 01 00:00:10 1970 +0000
544 +++ b/plain Thu Jan 01 00:00:10 1970 +0000
544 +++ b/plain Thu Jan 01 00:00:10 1970 +0000
545 @@ -1,4 +1,4 @@
545 @@ -1,4 +1,4 @@
546 -1
546 -1
547 +2
547 +2
548 2
548 2
549 3
549 3
550 4
550 4
551 @@ -8,5 +8,3 @@
551 @@ -8,5 +8,3 @@
552 8
552 8
553 9
553 9
554 10
554 10
555 -11
555 -11
556 -7264f99c5f5ff3261504828afa4fb4d406c3af54
556 -7264f99c5f5ff3261504828afa4fb4d406c3af54
557 diff -r 33abe24d946c -r f941910cff62 plain2
557 diff -r 33abe24d946c -r f941910cff62 plain2
558 --- a/plain2 Thu Jan 01 00:00:10 1970 +0000
558 --- a/plain2 Thu Jan 01 00:00:10 1970 +0000
559 +++ b/plain2 Thu Jan 01 00:00:10 1970 +0000
559 +++ b/plain2 Thu Jan 01 00:00:10 1970 +0000
560 @@ -1,1 +1,2 @@
560 @@ -1,1 +1,2 @@
561 1
561 1
562 +2
562 +2
563
563
564
564
565 Trim beginning, modify end
565 Trim beginning, modify end
566
566
567 $ rm plain
567 $ rm plain
568 > for i in 4 5 6 7 8 9 10.new; do
568 > for i in 4 5 6 7 8 9 10.new; do
569 > echo $i >> plain
569 > echo $i >> plain
570 > done
570 > done
571
571
572 Record end
572 Record end
573
573
574 $ hg commit -i -d '11 0' -m end-only plain <<EOF
574 $ hg commit -i -d '11 0' -m end-only plain <<EOF
575 > y
575 > y
576 > n
576 > n
577 > y
577 > y
578 > EOF
578 > EOF
579 diff --git a/plain b/plain
579 diff --git a/plain b/plain
580 2 hunks, 4 lines changed
580 2 hunks, 4 lines changed
581 examine changes to 'plain'? [Ynesfdaq?] y
581 examine changes to 'plain'? [Ynesfdaq?] y
582
582
583 @@ -1,9 +1,6 @@
583 @@ -1,9 +1,6 @@
584 -2
584 -2
585 -2
585 -2
586 -3
586 -3
587 4
587 4
588 5
588 5
589 6
589 6
590 7
590 7
591 8
591 8
592 9
592 9
593 record change 1/2 to 'plain'? [Ynesfdaq?] n
593 record change 1/2 to 'plain'? [Ynesfdaq?] n
594
594
595 @@ -4,7 +1,7 @@
595 @@ -4,7 +1,7 @@
596 4
596 4
597 5
597 5
598 6
598 6
599 7
599 7
600 8
600 8
601 9
601 9
602 -10
602 -10
603 +10.new
603 +10.new
604 record change 2/2 to 'plain'? [Ynesfdaq?] y
604 record change 2/2 to 'plain'? [Ynesfdaq?] y
605
605
606
606
607 $ hg tip -p
607 $ hg tip -p
608 changeset: 14:4915f538659b
608 changeset: 14:4915f538659b
609 tag: tip
609 tag: tip
610 user: test
610 user: test
611 date: Thu Jan 01 00:00:11 1970 +0000
611 date: Thu Jan 01 00:00:11 1970 +0000
612 summary: end-only
612 summary: end-only
613
613
614 diff -r f941910cff62 -r 4915f538659b plain
614 diff -r f941910cff62 -r 4915f538659b plain
615 --- a/plain Thu Jan 01 00:00:10 1970 +0000
615 --- a/plain Thu Jan 01 00:00:10 1970 +0000
616 +++ b/plain Thu Jan 01 00:00:11 1970 +0000
616 +++ b/plain Thu Jan 01 00:00:11 1970 +0000
617 @@ -7,4 +7,4 @@
617 @@ -7,4 +7,4 @@
618 7
618 7
619 8
619 8
620 9
620 9
621 -10
621 -10
622 +10.new
622 +10.new
623
623
624
624
625 Record beginning
625 Record beginning
626
626
627 $ hg commit -i -d '12 0' -m begin-only plain <<EOF
627 $ hg commit -i -d '12 0' -m begin-only plain <<EOF
628 > y
628 > y
629 > y
629 > y
630 > EOF
630 > EOF
631 diff --git a/plain b/plain
631 diff --git a/plain b/plain
632 1 hunks, 3 lines changed
632 1 hunks, 3 lines changed
633 examine changes to 'plain'? [Ynesfdaq?] y
633 examine changes to 'plain'? [Ynesfdaq?] y
634
634
635 @@ -1,6 +1,3 @@
635 @@ -1,6 +1,3 @@
636 -2
636 -2
637 -2
637 -2
638 -3
638 -3
639 4
639 4
640 5
640 5
641 6
641 6
642 record this change to 'plain'? [Ynesfdaq?] y
642 record this change to 'plain'? [Ynesfdaq?] y
643
643
644
644
645 $ hg tip -p
645 $ hg tip -p
646 changeset: 15:1b1f93d4b94b
646 changeset: 15:1b1f93d4b94b
647 tag: tip
647 tag: tip
648 user: test
648 user: test
649 date: Thu Jan 01 00:00:12 1970 +0000
649 date: Thu Jan 01 00:00:12 1970 +0000
650 summary: begin-only
650 summary: begin-only
651
651
652 diff -r 4915f538659b -r 1b1f93d4b94b plain
652 diff -r 4915f538659b -r 1b1f93d4b94b plain
653 --- a/plain Thu Jan 01 00:00:11 1970 +0000
653 --- a/plain Thu Jan 01 00:00:11 1970 +0000
654 +++ b/plain Thu Jan 01 00:00:12 1970 +0000
654 +++ b/plain Thu Jan 01 00:00:12 1970 +0000
655 @@ -1,6 +1,3 @@
655 @@ -1,6 +1,3 @@
656 -2
656 -2
657 -2
657 -2
658 -3
658 -3
659 4
659 4
660 5
660 5
661 6
661 6
662
662
663
663
664 Add to beginning, trim from end
664 Add to beginning, trim from end
665
665
666 $ rm plain
666 $ rm plain
667 $ for i in 1 2 3 4 5 6 7 8 9; do
667 $ for i in 1 2 3 4 5 6 7 8 9; do
668 > echo $i >> plain
668 > echo $i >> plain
669 > done
669 > done
670
670
671 Record end
671 Record end
672
672
673 $ hg commit -i --traceback -d '13 0' -m end-again plain<<EOF
673 $ hg commit -i --traceback -d '13 0' -m end-again plain<<EOF
674 > y
674 > y
675 > n
675 > n
676 > y
676 > y
677 > EOF
677 > EOF
678 diff --git a/plain b/plain
678 diff --git a/plain b/plain
679 2 hunks, 4 lines changed
679 2 hunks, 4 lines changed
680 examine changes to 'plain'? [Ynesfdaq?] y
680 examine changes to 'plain'? [Ynesfdaq?] y
681
681
682 @@ -1,6 +1,9 @@
682 @@ -1,6 +1,9 @@
683 +1
683 +1
684 +2
684 +2
685 +3
685 +3
686 4
686 4
687 5
687 5
688 6
688 6
689 7
689 7
690 8
690 8
691 9
691 9
692 record change 1/2 to 'plain'? [Ynesfdaq?] n
692 record change 1/2 to 'plain'? [Ynesfdaq?] n
693
693
694 @@ -1,7 +4,6 @@
694 @@ -1,7 +4,6 @@
695 4
695 4
696 5
696 5
697 6
697 6
698 7
698 7
699 8
699 8
700 9
700 9
701 -10.new
701 -10.new
702 record change 2/2 to 'plain'? [Ynesfdaq?] y
702 record change 2/2 to 'plain'? [Ynesfdaq?] y
703
703
704
704
705 Add to beginning, middle, end
705 Add to beginning, middle, end
706
706
707 $ rm plain
707 $ rm plain
708 $ for i in 1 2 3 4 5 5.new 5.reallynew 6 7 8 9 10 11; do
708 $ for i in 1 2 3 4 5 5.new 5.reallynew 6 7 8 9 10 11; do
709 > echo $i >> plain
709 > echo $i >> plain
710 > done
710 > done
711
711
712 Record beginning, middle, and test that format-breaking diffopts are ignored
712 Record beginning, middle, and test that format-breaking diffopts are ignored
713
713
714 $ hg commit -i --config diff.noprefix=True -d '14 0' -m middle-only plain <<EOF
714 $ hg commit -i --config diff.noprefix=True -d '14 0' -m middle-only plain <<EOF
715 > y
715 > y
716 > y
716 > y
717 > y
717 > y
718 > n
718 > n
719 > EOF
719 > EOF
720 diff --git a/plain b/plain
720 diff --git a/plain b/plain
721 3 hunks, 7 lines changed
721 3 hunks, 7 lines changed
722 examine changes to 'plain'? [Ynesfdaq?] y
722 examine changes to 'plain'? [Ynesfdaq?] y
723
723
724 @@ -1,2 +1,5 @@
724 @@ -1,2 +1,5 @@
725 +1
725 +1
726 +2
726 +2
727 +3
727 +3
728 4
728 4
729 5
729 5
730 record change 1/3 to 'plain'? [Ynesfdaq?] y
730 record change 1/3 to 'plain'? [Ynesfdaq?] y
731
731
732 @@ -1,6 +4,8 @@
732 @@ -1,6 +4,8 @@
733 4
733 4
734 5
734 5
735 +5.new
735 +5.new
736 +5.reallynew
736 +5.reallynew
737 6
737 6
738 7
738 7
739 8
739 8
740 9
740 9
741 record change 2/3 to 'plain'? [Ynesfdaq?] y
741 record change 2/3 to 'plain'? [Ynesfdaq?] y
742
742
743 @@ -3,4 +8,6 @@
743 @@ -3,4 +8,6 @@
744 6
744 6
745 7
745 7
746 8
746 8
747 9
747 9
748 +10
748 +10
749 +11
749 +11
750 record change 3/3 to 'plain'? [Ynesfdaq?] n
750 record change 3/3 to 'plain'? [Ynesfdaq?] n
751
751
752
752
753 $ hg tip -p
753 $ hg tip -p
754 changeset: 17:41cf3f5c55ae
754 changeset: 17:41cf3f5c55ae
755 tag: tip
755 tag: tip
756 user: test
756 user: test
757 date: Thu Jan 01 00:00:14 1970 +0000
757 date: Thu Jan 01 00:00:14 1970 +0000
758 summary: middle-only
758 summary: middle-only
759
759
760 diff -r a69d252246e1 -r 41cf3f5c55ae plain
760 diff -r a69d252246e1 -r 41cf3f5c55ae plain
761 --- a/plain Thu Jan 01 00:00:13 1970 +0000
761 --- a/plain Thu Jan 01 00:00:13 1970 +0000
762 +++ b/plain Thu Jan 01 00:00:14 1970 +0000
762 +++ b/plain Thu Jan 01 00:00:14 1970 +0000
763 @@ -1,5 +1,10 @@
763 @@ -1,5 +1,10 @@
764 +1
764 +1
765 +2
765 +2
766 +3
766 +3
767 4
767 4
768 5
768 5
769 +5.new
769 +5.new
770 +5.reallynew
770 +5.reallynew
771 6
771 6
772 7
772 7
773 8
773 8
774
774
775
775
776 Record end
776 Record end
777
777
778 $ hg commit -i -d '15 0' -m end-only plain <<EOF
778 $ hg commit -i -d '15 0' -m end-only plain <<EOF
779 > y
779 > y
780 > y
780 > y
781 > EOF
781 > EOF
782 diff --git a/plain b/plain
782 diff --git a/plain b/plain
783 1 hunks, 2 lines changed
783 1 hunks, 2 lines changed
784 examine changes to 'plain'? [Ynesfdaq?] y
784 examine changes to 'plain'? [Ynesfdaq?] y
785
785
786 @@ -9,3 +9,5 @@ 6
786 @@ -9,3 +9,5 @@ 6
787 7
787 7
788 8
788 8
789 9
789 9
790 +10
790 +10
791 +11
791 +11
792 record this change to 'plain'? [Ynesfdaq?] y
792 record this change to 'plain'? [Ynesfdaq?] y
793
793
794
794
795 $ hg tip -p
795 $ hg tip -p
796 changeset: 18:58a72f46bc24
796 changeset: 18:58a72f46bc24
797 tag: tip
797 tag: tip
798 user: test
798 user: test
799 date: Thu Jan 01 00:00:15 1970 +0000
799 date: Thu Jan 01 00:00:15 1970 +0000
800 summary: end-only
800 summary: end-only
801
801
802 diff -r 41cf3f5c55ae -r 58a72f46bc24 plain
802 diff -r 41cf3f5c55ae -r 58a72f46bc24 plain
803 --- a/plain Thu Jan 01 00:00:14 1970 +0000
803 --- a/plain Thu Jan 01 00:00:14 1970 +0000
804 +++ b/plain Thu Jan 01 00:00:15 1970 +0000
804 +++ b/plain Thu Jan 01 00:00:15 1970 +0000
805 @@ -9,3 +9,5 @@
805 @@ -9,3 +9,5 @@
806 7
806 7
807 8
807 8
808 9
808 9
809 +10
809 +10
810 +11
810 +11
811
811
812
812
813 $ mkdir subdir
813 $ mkdir subdir
814 $ cd subdir
814 $ cd subdir
815 $ echo a > a
815 $ echo a > a
816 $ hg ci -d '16 0' -Amsubdir
816 $ hg ci -d '16 0' -Amsubdir
817 adding subdir/a
817 adding subdir/a
818
818
819 $ echo a >> a
819 $ echo a >> a
820 $ hg commit -i -d '16 0' -m subdir-change a <<EOF
820 $ hg commit -i -d '16 0' -m subdir-change a <<EOF
821 > y
821 > y
822 > y
822 > y
823 > EOF
823 > EOF
824 diff --git a/subdir/a b/subdir/a
824 diff --git a/subdir/a b/subdir/a
825 1 hunks, 1 lines changed
825 1 hunks, 1 lines changed
826 examine changes to 'subdir/a'? [Ynesfdaq?] y
826 examine changes to 'subdir/a'? [Ynesfdaq?] y
827
827
828 @@ -1,1 +1,2 @@
828 @@ -1,1 +1,2 @@
829 a
829 a
830 +a
830 +a
831 record this change to 'subdir/a'? [Ynesfdaq?] y
831 record this change to 'subdir/a'? [Ynesfdaq?] y
832
832
833
833
834 $ hg tip -p
834 $ hg tip -p
835 changeset: 20:e0f6b99f6c49
835 changeset: 20:e0f6b99f6c49
836 tag: tip
836 tag: tip
837 user: test
837 user: test
838 date: Thu Jan 01 00:00:16 1970 +0000
838 date: Thu Jan 01 00:00:16 1970 +0000
839 summary: subdir-change
839 summary: subdir-change
840
840
841 diff -r abd26b51de37 -r e0f6b99f6c49 subdir/a
841 diff -r abd26b51de37 -r e0f6b99f6c49 subdir/a
842 --- a/subdir/a Thu Jan 01 00:00:16 1970 +0000
842 --- a/subdir/a Thu Jan 01 00:00:16 1970 +0000
843 +++ b/subdir/a Thu Jan 01 00:00:16 1970 +0000
843 +++ b/subdir/a Thu Jan 01 00:00:16 1970 +0000
844 @@ -1,1 +1,2 @@
844 @@ -1,1 +1,2 @@
845 a
845 a
846 +a
846 +a
847
847
848
848
849 $ echo a > f1
849 $ echo a > f1
850 $ echo b > f2
850 $ echo b > f2
851 $ hg add f1 f2
851 $ hg add f1 f2
852
852
853 $ hg ci -mz -d '17 0'
853 $ hg ci -mz -d '17 0'
854
854
855 $ echo a >> f1
855 $ echo a >> f1
856 $ echo b >> f2
856 $ echo b >> f2
857
857
858 Help, quit
858 Help, quit
859
859
860 $ hg commit -i <<EOF
860 $ hg commit -i <<EOF
861 > ?
861 > ?
862 > q
862 > q
863 > EOF
863 > EOF
864 diff --git a/subdir/f1 b/subdir/f1
864 diff --git a/subdir/f1 b/subdir/f1
865 1 hunks, 1 lines changed
865 1 hunks, 1 lines changed
866 examine changes to 'subdir/f1'? [Ynesfdaq?] ?
866 examine changes to 'subdir/f1'? [Ynesfdaq?] ?
867
867
868 y - yes, record this change
868 y - yes, record this change
869 n - no, skip this change
869 n - no, skip this change
870 e - edit this change manually
870 e - edit this change manually
871 s - skip remaining changes to this file
871 s - skip remaining changes to this file
872 f - record remaining changes to this file
872 f - record remaining changes to this file
873 d - done, skip remaining changes and files
873 d - done, skip remaining changes and files
874 a - record all changes to all remaining files
874 a - record all changes to all remaining files
875 q - quit, recording no changes
875 q - quit, recording no changes
876 ? - ? (display help)
876 ? - ? (display help)
877 examine changes to 'subdir/f1'? [Ynesfdaq?] q
877 examine changes to 'subdir/f1'? [Ynesfdaq?] q
878
878
879 abort: user quit
879 abort: user quit
880 [255]
880 [255]
881
881
882 #if gettext
882 #if gettext
883
883
884 Test translated help message
884 Test translated help message
885
885
886 str.lower() instead of encoding.lower(str) on translated message might
886 str.lower() instead of encoding.lower(str) on translated message might
887 make message meaningless, because some encoding uses 0x41(A) - 0x5a(Z)
887 make message meaningless, because some encoding uses 0x41(A) - 0x5a(Z)
888 as the second or later byte of multi-byte character.
888 as the second or later byte of multi-byte character.
889
889
890 For example, "\x8bL\x98^" (translation of "record" in ja_JP.cp932)
890 For example, "\x8bL\x98^" (translation of "record" in ja_JP.cp932)
891 contains 0x4c (L). str.lower() replaces 0x4c(L) by 0x6c(l) and this
891 contains 0x4c (L). str.lower() replaces 0x4c(L) by 0x6c(l) and this
892 replacement makes message meaningless.
892 replacement makes message meaningless.
893
893
894 This tests that translated help message is lower()-ed correctly.
894 This tests that translated help message is lower()-ed correctly.
895
895
896 $ LANGUAGE=ja
896 $ LANGUAGE=ja
897 $ export LANGUAGE
897 $ export LANGUAGE
898
898
899 $ cat > $TESTTMP/escape.py <<EOF
899 $ cat > $TESTTMP/escape.py <<EOF
900 > from __future__ import absolute_import
900 > from __future__ import absolute_import
901 > from mercurial import (
901 > from mercurial import (
902 > pycompat,
902 > pycompat,
903 > )
903 > )
904 > from mercurial.utils import (
904 > from mercurial.utils import (
905 > procutil,
905 > procutil,
906 > )
906 > )
907 > def escape(c):
907 > def escape(c):
908 > o = ord(c)
908 > o = ord(c)
909 > if o < 0x80:
909 > if o < 0x80:
910 > return c
910 > return c
911 > else:
911 > else:
912 > return br'\x%02x' % o # escape char setting MSB
912 > return br'\x%02x' % o # escape char setting MSB
913 > for l in procutil.stdin:
913 > for l in procutil.stdin:
914 > procutil.stdout.write(
914 > procutil.stdout.write(
915 > b''.join(escape(c) for c in pycompat.iterbytestr(l)))
915 > b''.join(escape(c) for c in pycompat.iterbytestr(l)))
916 > EOF
916 > EOF
917
917
918 $ hg commit -i --encoding cp932 2>&1 <<EOF | "$PYTHON" $TESTTMP/escape.py | grep '^y - '
918 $ hg commit -i --encoding cp932 2>&1 <<EOF | "$PYTHON" $TESTTMP/escape.py | grep '^y - '
919 > ?
919 > ?
920 > q
920 > q
921 > EOF
921 > EOF
922 y - \x82\xb1\x82\xcc\x95\xcf\x8dX\x82\xf0\x8bL\x98^(yes)
922 y - \x82\xb1\x82\xcc\x95\xcf\x8dX\x82\xf0\x8bL\x98^(yes)
923
923
924 $ LANGUAGE=
924 $ LANGUAGE=
925 #endif
925 #endif
926
926
927 Skip
927 Skip
928
928
929 $ hg commit -i <<EOF
929 $ hg commit -i <<EOF
930 > s
930 > s
931 > EOF
931 > EOF
932 diff --git a/subdir/f1 b/subdir/f1
932 diff --git a/subdir/f1 b/subdir/f1
933 1 hunks, 1 lines changed
933 1 hunks, 1 lines changed
934 examine changes to 'subdir/f1'? [Ynesfdaq?] s
934 examine changes to 'subdir/f1'? [Ynesfdaq?] s
935
935
936 diff --git a/subdir/f2 b/subdir/f2
936 diff --git a/subdir/f2 b/subdir/f2
937 1 hunks, 1 lines changed
937 1 hunks, 1 lines changed
938 examine changes to 'subdir/f2'? [Ynesfdaq?] abort: response expected
938 examine changes to 'subdir/f2'? [Ynesfdaq?] abort: response expected
939 [255]
939 [255]
940
940
941 No
941 No
942
942
943 $ hg commit -i <<EOF
943 $ hg commit -i <<EOF
944 > n
944 > n
945 > EOF
945 > EOF
946 diff --git a/subdir/f1 b/subdir/f1
946 diff --git a/subdir/f1 b/subdir/f1
947 1 hunks, 1 lines changed
947 1 hunks, 1 lines changed
948 examine changes to 'subdir/f1'? [Ynesfdaq?] n
948 examine changes to 'subdir/f1'? [Ynesfdaq?] n
949
949
950 diff --git a/subdir/f2 b/subdir/f2
950 diff --git a/subdir/f2 b/subdir/f2
951 1 hunks, 1 lines changed
951 1 hunks, 1 lines changed
952 examine changes to 'subdir/f2'? [Ynesfdaq?] abort: response expected
952 examine changes to 'subdir/f2'? [Ynesfdaq?] abort: response expected
953 [255]
953 [255]
954
954
955 f, quit
955 f, quit
956
956
957 $ hg commit -i <<EOF
957 $ hg commit -i <<EOF
958 > f
958 > f
959 > q
959 > q
960 > EOF
960 > EOF
961 diff --git a/subdir/f1 b/subdir/f1
961 diff --git a/subdir/f1 b/subdir/f1
962 1 hunks, 1 lines changed
962 1 hunks, 1 lines changed
963 examine changes to 'subdir/f1'? [Ynesfdaq?] f
963 examine changes to 'subdir/f1'? [Ynesfdaq?] f
964
964
965 diff --git a/subdir/f2 b/subdir/f2
965 diff --git a/subdir/f2 b/subdir/f2
966 1 hunks, 1 lines changed
966 1 hunks, 1 lines changed
967 examine changes to 'subdir/f2'? [Ynesfdaq?] q
967 examine changes to 'subdir/f2'? [Ynesfdaq?] q
968
968
969 abort: user quit
969 abort: user quit
970 [255]
970 [255]
971
971
972 s, all
972 s, all
973
973
974 $ hg commit -i -d '18 0' -mx <<EOF
974 $ hg commit -i -d '18 0' -mx <<EOF
975 > s
975 > s
976 > a
976 > a
977 > EOF
977 > EOF
978 diff --git a/subdir/f1 b/subdir/f1
978 diff --git a/subdir/f1 b/subdir/f1
979 1 hunks, 1 lines changed
979 1 hunks, 1 lines changed
980 examine changes to 'subdir/f1'? [Ynesfdaq?] s
980 examine changes to 'subdir/f1'? [Ynesfdaq?] s
981
981
982 diff --git a/subdir/f2 b/subdir/f2
982 diff --git a/subdir/f2 b/subdir/f2
983 1 hunks, 1 lines changed
983 1 hunks, 1 lines changed
984 examine changes to 'subdir/f2'? [Ynesfdaq?] a
984 examine changes to 'subdir/f2'? [Ynesfdaq?] a
985
985
986
986
987 $ hg tip -p
987 $ hg tip -p
988 changeset: 22:6afbbefacf35
988 changeset: 22:6afbbefacf35
989 tag: tip
989 tag: tip
990 user: test
990 user: test
991 date: Thu Jan 01 00:00:18 1970 +0000
991 date: Thu Jan 01 00:00:18 1970 +0000
992 summary: x
992 summary: x
993
993
994 diff -r b73c401c693c -r 6afbbefacf35 subdir/f2
994 diff -r b73c401c693c -r 6afbbefacf35 subdir/f2
995 --- a/subdir/f2 Thu Jan 01 00:00:17 1970 +0000
995 --- a/subdir/f2 Thu Jan 01 00:00:17 1970 +0000
996 +++ b/subdir/f2 Thu Jan 01 00:00:18 1970 +0000
996 +++ b/subdir/f2 Thu Jan 01 00:00:18 1970 +0000
997 @@ -1,1 +1,2 @@
997 @@ -1,1 +1,2 @@
998 b
998 b
999 +b
999 +b
1000
1000
1001
1001
1002 f
1002 f
1003
1003
1004 $ hg commit -i -d '19 0' -my <<EOF
1004 $ hg commit -i -d '19 0' -my <<EOF
1005 > f
1005 > f
1006 > EOF
1006 > EOF
1007 diff --git a/subdir/f1 b/subdir/f1
1007 diff --git a/subdir/f1 b/subdir/f1
1008 1 hunks, 1 lines changed
1008 1 hunks, 1 lines changed
1009 examine changes to 'subdir/f1'? [Ynesfdaq?] f
1009 examine changes to 'subdir/f1'? [Ynesfdaq?] f
1010
1010
1011
1011
1012 $ hg tip -p
1012 $ hg tip -p
1013 changeset: 23:715028a33949
1013 changeset: 23:715028a33949
1014 tag: tip
1014 tag: tip
1015 user: test
1015 user: test
1016 date: Thu Jan 01 00:00:19 1970 +0000
1016 date: Thu Jan 01 00:00:19 1970 +0000
1017 summary: y
1017 summary: y
1018
1018
1019 diff -r 6afbbefacf35 -r 715028a33949 subdir/f1
1019 diff -r 6afbbefacf35 -r 715028a33949 subdir/f1
1020 --- a/subdir/f1 Thu Jan 01 00:00:18 1970 +0000
1020 --- a/subdir/f1 Thu Jan 01 00:00:18 1970 +0000
1021 +++ b/subdir/f1 Thu Jan 01 00:00:19 1970 +0000
1021 +++ b/subdir/f1 Thu Jan 01 00:00:19 1970 +0000
1022 @@ -1,1 +1,2 @@
1022 @@ -1,1 +1,2 @@
1023 a
1023 a
1024 +a
1024 +a
1025
1025
1026
1026
1027 #if execbit
1027 #if execbit
1028
1028
1029 Preserve chmod +x
1029 Preserve chmod +x
1030
1030
1031 $ chmod +x f1
1031 $ chmod +x f1
1032 $ echo a >> f1
1032 $ echo a >> f1
1033 $ hg commit -i -d '20 0' -mz <<EOF
1033 $ hg commit -i -d '20 0' -mz <<EOF
1034 > y
1034 > y
1035 > y
1035 > y
1036 > y
1036 > y
1037 > EOF
1037 > EOF
1038 diff --git a/subdir/f1 b/subdir/f1
1038 diff --git a/subdir/f1 b/subdir/f1
1039 old mode 100644
1039 old mode 100644
1040 new mode 100755
1040 new mode 100755
1041 1 hunks, 1 lines changed
1041 1 hunks, 1 lines changed
1042 examine changes to 'subdir/f1'? [Ynesfdaq?] y
1042 examine changes to 'subdir/f1'? [Ynesfdaq?] y
1043
1043
1044 @@ -1,2 +1,3 @@
1044 @@ -1,2 +1,3 @@
1045 a
1045 a
1046 a
1046 a
1047 +a
1047 +a
1048 record this change to 'subdir/f1'? [Ynesfdaq?] y
1048 record this change to 'subdir/f1'? [Ynesfdaq?] y
1049
1049
1050
1050
1051 $ hg tip --config diff.git=True -p
1051 $ hg tip --config diff.git=True -p
1052 changeset: 24:db967c1e5884
1052 changeset: 24:db967c1e5884
1053 tag: tip
1053 tag: tip
1054 user: test
1054 user: test
1055 date: Thu Jan 01 00:00:20 1970 +0000
1055 date: Thu Jan 01 00:00:20 1970 +0000
1056 summary: z
1056 summary: z
1057
1057
1058 diff --git a/subdir/f1 b/subdir/f1
1058 diff --git a/subdir/f1 b/subdir/f1
1059 old mode 100644
1059 old mode 100644
1060 new mode 100755
1060 new mode 100755
1061 --- a/subdir/f1
1061 --- a/subdir/f1
1062 +++ b/subdir/f1
1062 +++ b/subdir/f1
1063 @@ -1,2 +1,3 @@
1063 @@ -1,2 +1,3 @@
1064 a
1064 a
1065 a
1065 a
1066 +a
1066 +a
1067
1067
1068
1068
1069 Preserve execute permission on original
1069 Preserve execute permission on original
1070
1070
1071 $ echo b >> f1
1071 $ echo b >> f1
1072 $ hg commit -i -d '21 0' -maa <<EOF
1072 $ hg commit -i -d '21 0' -maa <<EOF
1073 > y
1073 > y
1074 > y
1074 > y
1075 > y
1075 > y
1076 > EOF
1076 > EOF
1077 diff --git a/subdir/f1 b/subdir/f1
1077 diff --git a/subdir/f1 b/subdir/f1
1078 1 hunks, 1 lines changed
1078 1 hunks, 1 lines changed
1079 examine changes to 'subdir/f1'? [Ynesfdaq?] y
1079 examine changes to 'subdir/f1'? [Ynesfdaq?] y
1080
1080
1081 @@ -1,3 +1,4 @@
1081 @@ -1,3 +1,4 @@
1082 a
1082 a
1083 a
1083 a
1084 a
1084 a
1085 +b
1085 +b
1086 record this change to 'subdir/f1'? [Ynesfdaq?] y
1086 record this change to 'subdir/f1'? [Ynesfdaq?] y
1087
1087
1088
1088
1089 $ hg tip --config diff.git=True -p
1089 $ hg tip --config diff.git=True -p
1090 changeset: 25:88903aef81c3
1090 changeset: 25:88903aef81c3
1091 tag: tip
1091 tag: tip
1092 user: test
1092 user: test
1093 date: Thu Jan 01 00:00:21 1970 +0000
1093 date: Thu Jan 01 00:00:21 1970 +0000
1094 summary: aa
1094 summary: aa
1095
1095
1096 diff --git a/subdir/f1 b/subdir/f1
1096 diff --git a/subdir/f1 b/subdir/f1
1097 --- a/subdir/f1
1097 --- a/subdir/f1
1098 +++ b/subdir/f1
1098 +++ b/subdir/f1
1099 @@ -1,3 +1,4 @@
1099 @@ -1,3 +1,4 @@
1100 a
1100 a
1101 a
1101 a
1102 a
1102 a
1103 +b
1103 +b
1104
1104
1105
1105
1106 Preserve chmod -x
1106 Preserve chmod -x
1107
1107
1108 $ chmod -x f1
1108 $ chmod -x f1
1109 $ echo c >> f1
1109 $ echo c >> f1
1110 $ hg commit -i -d '22 0' -mab <<EOF
1110 $ hg commit -i -d '22 0' -mab <<EOF
1111 > y
1111 > y
1112 > y
1112 > y
1113 > y
1113 > y
1114 > EOF
1114 > EOF
1115 diff --git a/subdir/f1 b/subdir/f1
1115 diff --git a/subdir/f1 b/subdir/f1
1116 old mode 100755
1116 old mode 100755
1117 new mode 100644
1117 new mode 100644
1118 1 hunks, 1 lines changed
1118 1 hunks, 1 lines changed
1119 examine changes to 'subdir/f1'? [Ynesfdaq?] y
1119 examine changes to 'subdir/f1'? [Ynesfdaq?] y
1120
1120
1121 @@ -2,3 +2,4 @@ a
1121 @@ -2,3 +2,4 @@ a
1122 a
1122 a
1123 a
1123 a
1124 b
1124 b
1125 +c
1125 +c
1126 record this change to 'subdir/f1'? [Ynesfdaq?] y
1126 record this change to 'subdir/f1'? [Ynesfdaq?] y
1127
1127
1128
1128
1129 $ hg tip --config diff.git=True -p
1129 $ hg tip --config diff.git=True -p
1130 changeset: 26:7af84b6cf560
1130 changeset: 26:7af84b6cf560
1131 tag: tip
1131 tag: tip
1132 user: test
1132 user: test
1133 date: Thu Jan 01 00:00:22 1970 +0000
1133 date: Thu Jan 01 00:00:22 1970 +0000
1134 summary: ab
1134 summary: ab
1135
1135
1136 diff --git a/subdir/f1 b/subdir/f1
1136 diff --git a/subdir/f1 b/subdir/f1
1137 old mode 100755
1137 old mode 100755
1138 new mode 100644
1138 new mode 100644
1139 --- a/subdir/f1
1139 --- a/subdir/f1
1140 +++ b/subdir/f1
1140 +++ b/subdir/f1
1141 @@ -2,3 +2,4 @@
1141 @@ -2,3 +2,4 @@
1142 a
1142 a
1143 a
1143 a
1144 b
1144 b
1145 +c
1145 +c
1146
1146
1147
1147
1148 #else
1148 #else
1149
1149
1150 Slightly bogus tests to get almost same repo structure as when x bit is used
1150 Slightly bogus tests to get almost same repo structure as when x bit is used
1151 - but with different hashes.
1151 - but with different hashes.
1152
1152
1153 Mock "Preserve chmod +x"
1153 Mock "Preserve chmod +x"
1154
1154
1155 $ echo a >> f1
1155 $ echo a >> f1
1156 $ hg commit -i -d '20 0' -mz <<EOF
1156 $ hg commit -i -d '20 0' -mz <<EOF
1157 > y
1157 > y
1158 > y
1158 > y
1159 > y
1159 > y
1160 > EOF
1160 > EOF
1161 diff --git a/subdir/f1 b/subdir/f1
1161 diff --git a/subdir/f1 b/subdir/f1
1162 1 hunks, 1 lines changed
1162 1 hunks, 1 lines changed
1163 examine changes to 'subdir/f1'? [Ynesfdaq?] y
1163 examine changes to 'subdir/f1'? [Ynesfdaq?] y
1164
1164
1165 @@ -1,2 +1,3 @@
1165 @@ -1,2 +1,3 @@
1166 a
1166 a
1167 a
1167 a
1168 +a
1168 +a
1169 record this change to 'subdir/f1'? [Ynesfdaq?] y
1169 record this change to 'subdir/f1'? [Ynesfdaq?] y
1170
1170
1171
1171
1172 $ hg tip --config diff.git=True -p
1172 $ hg tip --config diff.git=True -p
1173 changeset: 24:c26cfe2c4eb0
1173 changeset: 24:c26cfe2c4eb0
1174 tag: tip
1174 tag: tip
1175 user: test
1175 user: test
1176 date: Thu Jan 01 00:00:20 1970 +0000
1176 date: Thu Jan 01 00:00:20 1970 +0000
1177 summary: z
1177 summary: z
1178
1178
1179 diff --git a/subdir/f1 b/subdir/f1
1179 diff --git a/subdir/f1 b/subdir/f1
1180 --- a/subdir/f1
1180 --- a/subdir/f1
1181 +++ b/subdir/f1
1181 +++ b/subdir/f1
1182 @@ -1,2 +1,3 @@
1182 @@ -1,2 +1,3 @@
1183 a
1183 a
1184 a
1184 a
1185 +a
1185 +a
1186
1186
1187
1187
1188 Mock "Preserve execute permission on original"
1188 Mock "Preserve execute permission on original"
1189
1189
1190 $ echo b >> f1
1190 $ echo b >> f1
1191 $ hg commit -i -d '21 0' -maa <<EOF
1191 $ hg commit -i -d '21 0' -maa <<EOF
1192 > y
1192 > y
1193 > y
1193 > y
1194 > y
1194 > y
1195 > EOF
1195 > EOF
1196 diff --git a/subdir/f1 b/subdir/f1
1196 diff --git a/subdir/f1 b/subdir/f1
1197 1 hunks, 1 lines changed
1197 1 hunks, 1 lines changed
1198 examine changes to 'subdir/f1'? [Ynesfdaq?] y
1198 examine changes to 'subdir/f1'? [Ynesfdaq?] y
1199
1199
1200 @@ -1,3 +1,4 @@
1200 @@ -1,3 +1,4 @@
1201 a
1201 a
1202 a
1202 a
1203 a
1203 a
1204 +b
1204 +b
1205 record this change to 'subdir/f1'? [Ynesfdaq?] y
1205 record this change to 'subdir/f1'? [Ynesfdaq?] y
1206
1206
1207
1207
1208 $ hg tip --config diff.git=True -p
1208 $ hg tip --config diff.git=True -p
1209 changeset: 25:a48d2d60adde
1209 changeset: 25:a48d2d60adde
1210 tag: tip
1210 tag: tip
1211 user: test
1211 user: test
1212 date: Thu Jan 01 00:00:21 1970 +0000
1212 date: Thu Jan 01 00:00:21 1970 +0000
1213 summary: aa
1213 summary: aa
1214
1214
1215 diff --git a/subdir/f1 b/subdir/f1
1215 diff --git a/subdir/f1 b/subdir/f1
1216 --- a/subdir/f1
1216 --- a/subdir/f1
1217 +++ b/subdir/f1
1217 +++ b/subdir/f1
1218 @@ -1,3 +1,4 @@
1218 @@ -1,3 +1,4 @@
1219 a
1219 a
1220 a
1220 a
1221 a
1221 a
1222 +b
1222 +b
1223
1223
1224
1224
1225 Mock "Preserve chmod -x"
1225 Mock "Preserve chmod -x"
1226
1226
1227 $ chmod -x f1
1227 $ chmod -x f1
1228 $ echo c >> f1
1228 $ echo c >> f1
1229 $ hg commit -i -d '22 0' -mab <<EOF
1229 $ hg commit -i -d '22 0' -mab <<EOF
1230 > y
1230 > y
1231 > y
1231 > y
1232 > y
1232 > y
1233 > EOF
1233 > EOF
1234 diff --git a/subdir/f1 b/subdir/f1
1234 diff --git a/subdir/f1 b/subdir/f1
1235 1 hunks, 1 lines changed
1235 1 hunks, 1 lines changed
1236 examine changes to 'subdir/f1'? [Ynesfdaq?] y
1236 examine changes to 'subdir/f1'? [Ynesfdaq?] y
1237
1237
1238 @@ -2,3 +2,4 @@ a
1238 @@ -2,3 +2,4 @@ a
1239 a
1239 a
1240 a
1240 a
1241 b
1241 b
1242 +c
1242 +c
1243 record this change to 'subdir/f1'? [Ynesfdaq?] y
1243 record this change to 'subdir/f1'? [Ynesfdaq?] y
1244
1244
1245
1245
1246 $ hg tip --config diff.git=True -p
1246 $ hg tip --config diff.git=True -p
1247 changeset: 26:5cc89ae210fa
1247 changeset: 26:5cc89ae210fa
1248 tag: tip
1248 tag: tip
1249 user: test
1249 user: test
1250 date: Thu Jan 01 00:00:22 1970 +0000
1250 date: Thu Jan 01 00:00:22 1970 +0000
1251 summary: ab
1251 summary: ab
1252
1252
1253 diff --git a/subdir/f1 b/subdir/f1
1253 diff --git a/subdir/f1 b/subdir/f1
1254 --- a/subdir/f1
1254 --- a/subdir/f1
1255 +++ b/subdir/f1
1255 +++ b/subdir/f1
1256 @@ -2,3 +2,4 @@
1256 @@ -2,3 +2,4 @@
1257 a
1257 a
1258 a
1258 a
1259 b
1259 b
1260 +c
1260 +c
1261
1261
1262
1262
1263 #endif
1263 #endif
1264
1264
1265 $ cd ..
1265 $ cd ..
1266
1266
1267
1267
1268 Abort early when a merge is in progress
1268 Abort early when a merge is in progress
1269
1269
1270 $ hg up 4
1270 $ hg up 4
1271 1 files updated, 0 files merged, 7 files removed, 0 files unresolved
1271 1 files updated, 0 files merged, 7 files removed, 0 files unresolved
1272
1272
1273 $ touch iwillmergethat
1273 $ touch iwillmergethat
1274 $ hg add iwillmergethat
1274 $ hg add iwillmergethat
1275
1275
1276 $ hg branch thatbranch
1276 $ hg branch thatbranch
1277 marked working directory as branch thatbranch
1277 marked working directory as branch thatbranch
1278 (branches are permanent and global, did you want a bookmark?)
1278 (branches are permanent and global, did you want a bookmark?)
1279
1279
1280 $ hg ci -m'new head'
1280 $ hg ci -m'new head'
1281
1281
1282 $ hg up default
1282 $ hg up default
1283 7 files updated, 0 files merged, 2 files removed, 0 files unresolved
1283 7 files updated, 0 files merged, 2 files removed, 0 files unresolved
1284
1284
1285 $ hg merge thatbranch
1285 $ hg merge thatbranch
1286 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1286 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1287 (branch merge, don't forget to commit)
1287 (branch merge, don't forget to commit)
1288
1288
1289 $ hg commit -i -m'will abort'
1289 $ hg commit -i -m'will abort'
1290 abort: cannot partially commit a merge (use "hg commit" instead)
1290 abort: cannot partially commit a merge (use "hg commit" instead)
1291 [255]
1291 [255]
1292
1292
1293 $ hg up -C
1293 $ hg up -C
1294 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1294 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1295
1295
1296 Editing patch (and ignoring trailing text)
1296 Editing patch (and ignoring trailing text)
1297
1297
1298 $ cat > editor.sh << '__EOF__'
1298 $ cat > editor.sh << '__EOF__'
1299 > sed -e 7d -e '5s/^-/ /' -e '/^# ---/i\
1299 > sed -e 7d -e '5s/^-/ /' -e '/^# ---/i\
1300 > trailing\nditto' "$1" > tmp
1300 > trailing\nditto' "$1" > tmp
1301 > mv tmp "$1"
1301 > mv tmp "$1"
1302 > __EOF__
1302 > __EOF__
1303 $ cat > editedfile << '__EOF__'
1303 $ cat > editedfile << '__EOF__'
1304 > This is the first line
1304 > This is the first line
1305 > This is the second line
1305 > This is the second line
1306 > This is the third line
1306 > This is the third line
1307 > __EOF__
1307 > __EOF__
1308 $ hg add editedfile
1308 $ hg add editedfile
1309 $ hg commit -medit-patch-1
1309 $ hg commit -medit-patch-1
1310 $ cat > editedfile << '__EOF__'
1310 $ cat > editedfile << '__EOF__'
1311 > This line has changed
1311 > This line has changed
1312 > This change will be committed
1312 > This change will be committed
1313 > This is the third line
1313 > This is the third line
1314 > __EOF__
1314 > __EOF__
1315 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit -i -d '23 0' -medit-patch-2 <<EOF
1315 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit -i -d '23 0' -medit-patch-2 <<EOF
1316 > y
1316 > y
1317 > e
1317 > e
1318 > EOF
1318 > EOF
1319 diff --git a/editedfile b/editedfile
1319 diff --git a/editedfile b/editedfile
1320 1 hunks, 2 lines changed
1320 1 hunks, 2 lines changed
1321 examine changes to 'editedfile'? [Ynesfdaq?] y
1321 examine changes to 'editedfile'? [Ynesfdaq?] y
1322
1322
1323 @@ -1,3 +1,3 @@
1323 @@ -1,3 +1,3 @@
1324 -This is the first line
1324 -This is the first line
1325 -This is the second line
1325 -This is the second line
1326 +This line has changed
1326 +This line has changed
1327 +This change will be committed
1327 +This change will be committed
1328 This is the third line
1328 This is the third line
1329 record this change to 'editedfile'? [Ynesfdaq?] e
1329 record this change to 'editedfile'? [Ynesfdaq?] e
1330
1330
1331 $ cat editedfile
1331 $ cat editedfile
1332 This line has changed
1332 This line has changed
1333 This change will be committed
1333 This change will be committed
1334 This is the third line
1334 This is the third line
1335 $ hg cat -r tip editedfile
1335 $ hg cat -r tip editedfile
1336 This is the first line
1336 This is the first line
1337 This change will be committed
1337 This change will be committed
1338 This is the third line
1338 This is the third line
1339 $ hg revert editedfile
1339 $ hg revert editedfile
1340
1340
1341 Trying to edit patch for whole file
1341 Trying to edit patch for whole file
1342
1342
1343 $ echo "This is the fourth line" >> editedfile
1343 $ echo "This is the fourth line" >> editedfile
1344 $ hg commit -i <<EOF
1344 $ hg commit -i <<EOF
1345 > e
1345 > e
1346 > q
1346 > q
1347 > EOF
1347 > EOF
1348 diff --git a/editedfile b/editedfile
1348 diff --git a/editedfile b/editedfile
1349 1 hunks, 1 lines changed
1349 1 hunks, 1 lines changed
1350 examine changes to 'editedfile'? [Ynesfdaq?] e
1350 examine changes to 'editedfile'? [Ynesfdaq?] e
1351
1351
1352 cannot edit patch for whole file
1352 cannot edit patch for whole file
1353 examine changes to 'editedfile'? [Ynesfdaq?] q
1353 examine changes to 'editedfile'? [Ynesfdaq?] q
1354
1354
1355 abort: user quit
1355 abort: user quit
1356 [255]
1356 [255]
1357 $ hg revert editedfile
1357 $ hg revert editedfile
1358
1358
1359 Removing changes from patch
1359 Removing changes from patch
1360
1360
1361 $ sed -e '3s/third/second/' -e '2s/will/will not/' -e 1d editedfile > tmp
1361 $ sed -e '3s/third/second/' -e '2s/will/will not/' -e 1d editedfile > tmp
1362 $ mv tmp editedfile
1362 $ mv tmp editedfile
1363 $ echo "This line has been added" >> editedfile
1363 $ echo "This line has been added" >> editedfile
1364 $ cat > editor.sh << '__EOF__'
1364 $ cat > editor.sh << '__EOF__'
1365 > sed -e 's/^[-+]/ /' "$1" > tmp
1365 > sed -e 's/^[-+]/ /' "$1" > tmp
1366 > mv tmp "$1"
1366 > mv tmp "$1"
1367 > __EOF__
1367 > __EOF__
1368 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit -i <<EOF
1368 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit -i <<EOF
1369 > y
1369 > y
1370 > e
1370 > e
1371 > EOF
1371 > EOF
1372 diff --git a/editedfile b/editedfile
1372 diff --git a/editedfile b/editedfile
1373 1 hunks, 3 lines changed
1373 1 hunks, 3 lines changed
1374 examine changes to 'editedfile'? [Ynesfdaq?] y
1374 examine changes to 'editedfile'? [Ynesfdaq?] y
1375
1375
1376 @@ -1,3 +1,3 @@
1376 @@ -1,3 +1,3 @@
1377 -This is the first line
1377 -This is the first line
1378 -This change will be committed
1378 -This change will be committed
1379 -This is the third line
1379 -This is the third line
1380 +This change will not be committed
1380 +This change will not be committed
1381 +This is the second line
1381 +This is the second line
1382 +This line has been added
1382 +This line has been added
1383 record this change to 'editedfile'? [Ynesfdaq?] e
1383 record this change to 'editedfile'? [Ynesfdaq?] e
1384
1384
1385 no changes to record
1385 no changes to record
1386 [1]
1386 [1]
1387 $ cat editedfile
1387 $ cat editedfile
1388 This change will not be committed
1388 This change will not be committed
1389 This is the second line
1389 This is the second line
1390 This line has been added
1390 This line has been added
1391 $ hg cat -r tip editedfile
1391 $ hg cat -r tip editedfile
1392 This is the first line
1392 This is the first line
1393 This change will be committed
1393 This change will be committed
1394 This is the third line
1394 This is the third line
1395 $ hg revert editedfile
1395 $ hg revert editedfile
1396
1396
1397 Invalid patch
1397 Invalid patch
1398
1398
1399 $ sed -e '3s/third/second/' -e '2s/will/will not/' -e 1d editedfile > tmp
1399 $ sed -e '3s/third/second/' -e '2s/will/will not/' -e 1d editedfile > tmp
1400 $ mv tmp editedfile
1400 $ mv tmp editedfile
1401 $ echo "This line has been added" >> editedfile
1401 $ echo "This line has been added" >> editedfile
1402 $ cat > editor.sh << '__EOF__'
1402 $ cat > editor.sh << '__EOF__'
1403 > sed s/This/That/ "$1" > tmp
1403 > sed s/This/That/ "$1" > tmp
1404 > mv tmp "$1"
1404 > mv tmp "$1"
1405 > __EOF__
1405 > __EOF__
1406 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit -i <<EOF
1406 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit -i <<EOF
1407 > y
1407 > y
1408 > e
1408 > e
1409 > EOF
1409 > EOF
1410 diff --git a/editedfile b/editedfile
1410 diff --git a/editedfile b/editedfile
1411 1 hunks, 3 lines changed
1411 1 hunks, 3 lines changed
1412 examine changes to 'editedfile'? [Ynesfdaq?] y
1412 examine changes to 'editedfile'? [Ynesfdaq?] y
1413
1413
1414 @@ -1,3 +1,3 @@
1414 @@ -1,3 +1,3 @@
1415 -This is the first line
1415 -This is the first line
1416 -This change will be committed
1416 -This change will be committed
1417 -This is the third line
1417 -This is the third line
1418 +This change will not be committed
1418 +This change will not be committed
1419 +This is the second line
1419 +This is the second line
1420 +This line has been added
1420 +This line has been added
1421 record this change to 'editedfile'? [Ynesfdaq?] e
1421 record this change to 'editedfile'? [Ynesfdaq?] e
1422
1422
1423 patching file editedfile
1423 patching file editedfile
1424 Hunk #1 FAILED at 0
1424 Hunk #1 FAILED at 0
1425 1 out of 1 hunks FAILED -- saving rejects to file editedfile.rej
1425 1 out of 1 hunks FAILED -- saving rejects to file editedfile.rej
1426 abort: patch failed to apply
1426 abort: patch failed to apply
1427 [255]
1427 [255]
1428 $ cat editedfile
1428 $ cat editedfile
1429 This change will not be committed
1429 This change will not be committed
1430 This is the second line
1430 This is the second line
1431 This line has been added
1431 This line has been added
1432 $ hg cat -r tip editedfile
1432 $ hg cat -r tip editedfile
1433 This is the first line
1433 This is the first line
1434 This change will be committed
1434 This change will be committed
1435 This is the third line
1435 This is the third line
1436 $ cat editedfile.rej
1436 $ cat editedfile.rej
1437 --- editedfile
1437 --- editedfile
1438 +++ editedfile
1438 +++ editedfile
1439 @@ -1,3 +1,3 @@
1439 @@ -1,3 +1,3 @@
1440 -That is the first line
1440 -That is the first line
1441 -That change will be committed
1441 -That change will be committed
1442 -That is the third line
1442 -That is the third line
1443 +That change will not be committed
1443 +That change will not be committed
1444 +That is the second line
1444 +That is the second line
1445 +That line has been added
1445 +That line has been added
1446
1446
1447 Malformed patch - error handling
1447 Malformed patch - error handling
1448
1448
1449 $ cat > editor.sh << '__EOF__'
1449 $ cat > editor.sh << '__EOF__'
1450 > sed -e '/^@/p' "$1" > tmp
1450 > sed -e '/^@/p' "$1" > tmp
1451 > mv tmp "$1"
1451 > mv tmp "$1"
1452 > __EOF__
1452 > __EOF__
1453 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit -i <<EOF
1453 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit -i <<EOF
1454 > y
1454 > y
1455 > e
1455 > e
1456 > EOF
1456 > EOF
1457 diff --git a/editedfile b/editedfile
1457 diff --git a/editedfile b/editedfile
1458 1 hunks, 3 lines changed
1458 1 hunks, 3 lines changed
1459 examine changes to 'editedfile'? [Ynesfdaq?] y
1459 examine changes to 'editedfile'? [Ynesfdaq?] y
1460
1460
1461 @@ -1,3 +1,3 @@
1461 @@ -1,3 +1,3 @@
1462 -This is the first line
1462 -This is the first line
1463 -This change will be committed
1463 -This change will be committed
1464 -This is the third line
1464 -This is the third line
1465 +This change will not be committed
1465 +This change will not be committed
1466 +This is the second line
1466 +This is the second line
1467 +This line has been added
1467 +This line has been added
1468 record this change to 'editedfile'? [Ynesfdaq?] e
1468 record this change to 'editedfile'? [Ynesfdaq?] e
1469
1469
1470 abort: error parsing patch: unhandled transition: range -> range
1470 abort: error parsing patch: unhandled transition: range -> range
1471 [255]
1471 [255]
1472
1472
1473 Exiting editor with status 1, ignores the edit but does not stop the recording
1473 Exiting editor with status 1, ignores the edit but does not stop the recording
1474 session
1474 session
1475
1475
1476 $ HGEDITOR=false hg commit -i <<EOF
1476 $ HGEDITOR=false hg commit -i <<EOF
1477 > y
1477 > y
1478 > e
1478 > e
1479 > n
1479 > n
1480 > EOF
1480 > EOF
1481 diff --git a/editedfile b/editedfile
1481 diff --git a/editedfile b/editedfile
1482 1 hunks, 3 lines changed
1482 1 hunks, 3 lines changed
1483 examine changes to 'editedfile'? [Ynesfdaq?] y
1483 examine changes to 'editedfile'? [Ynesfdaq?] y
1484
1484
1485 @@ -1,3 +1,3 @@
1485 @@ -1,3 +1,3 @@
1486 -This is the first line
1486 -This is the first line
1487 -This change will be committed
1487 -This change will be committed
1488 -This is the third line
1488 -This is the third line
1489 +This change will not be committed
1489 +This change will not be committed
1490 +This is the second line
1490 +This is the second line
1491 +This line has been added
1491 +This line has been added
1492 record this change to 'editedfile'? [Ynesfdaq?] e
1492 record this change to 'editedfile'? [Ynesfdaq?] e
1493
1493
1494 editor exited with exit code 1
1494 editor exited with exit code 1
1495 record this change to 'editedfile'? [Ynesfdaq?] n
1495 record this change to 'editedfile'? [Ynesfdaq?] n
1496
1496
1497 no changes to record
1497 no changes to record
1498 [1]
1498 [1]
1499
1499
1500
1500
1501 random text in random positions is still an error
1501 random text in random positions is still an error
1502
1502
1503 $ cat > editor.sh << '__EOF__'
1503 $ cat > editor.sh << '__EOF__'
1504 > sed -e '/^@/i\
1504 > sed -e '/^@/i\
1505 > other' "$1" > tmp
1505 > other' "$1" > tmp
1506 > mv tmp "$1"
1506 > mv tmp "$1"
1507 > __EOF__
1507 > __EOF__
1508 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit -i <<EOF
1508 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit -i <<EOF
1509 > y
1509 > y
1510 > e
1510 > e
1511 > EOF
1511 > EOF
1512 diff --git a/editedfile b/editedfile
1512 diff --git a/editedfile b/editedfile
1513 1 hunks, 3 lines changed
1513 1 hunks, 3 lines changed
1514 examine changes to 'editedfile'? [Ynesfdaq?] y
1514 examine changes to 'editedfile'? [Ynesfdaq?] y
1515
1515
1516 @@ -1,3 +1,3 @@
1516 @@ -1,3 +1,3 @@
1517 -This is the first line
1517 -This is the first line
1518 -This change will be committed
1518 -This change will be committed
1519 -This is the third line
1519 -This is the third line
1520 +This change will not be committed
1520 +This change will not be committed
1521 +This is the second line
1521 +This is the second line
1522 +This line has been added
1522 +This line has been added
1523 record this change to 'editedfile'? [Ynesfdaq?] e
1523 record this change to 'editedfile'? [Ynesfdaq?] e
1524
1524
1525 abort: error parsing patch: unhandled transition: file -> other
1525 abort: error parsing patch: unhandled transition: file -> other
1526 [255]
1526 [255]
1527
1527
1528 $ hg up -C
1528 $ hg up -C
1529 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1529 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1530
1530
1531 With win32text
1531 With win32text
1532
1532
1533 $ echo '[extensions]' >> .hg/hgrc
1533 $ echo '[extensions]' >> .hg/hgrc
1534 $ echo 'win32text = ' >> .hg/hgrc
1534 $ echo 'win32text = ' >> .hg/hgrc
1535 $ echo '[decode]' >> .hg/hgrc
1535 $ echo '[decode]' >> .hg/hgrc
1536 $ echo '** = cleverdecode:' >> .hg/hgrc
1536 $ echo '** = cleverdecode:' >> .hg/hgrc
1537 $ echo '[encode]' >> .hg/hgrc
1537 $ echo '[encode]' >> .hg/hgrc
1538 $ echo '** = cleverencode:' >> .hg/hgrc
1538 $ echo '** = cleverencode:' >> .hg/hgrc
1539 $ echo '[patch]' >> .hg/hgrc
1539 $ echo '[patch]' >> .hg/hgrc
1540 $ echo 'eol = crlf' >> .hg/hgrc
1540 $ echo 'eol = crlf' >> .hg/hgrc
1541
1541
1542 Ignore win32text deprecation warning for now:
1542 Ignore win32text deprecation warning for now:
1543
1543
1544 $ echo '[win32text]' >> .hg/hgrc
1544 $ echo '[win32text]' >> .hg/hgrc
1545 $ echo 'warn = no' >> .hg/hgrc
1545 $ echo 'warn = no' >> .hg/hgrc
1546
1546
1547 $ echo d >> subdir/f1
1547 $ echo d >> subdir/f1
1548 $ hg commit -i -d '24 0' -mw1 <<EOF
1548 $ hg commit -i -d '24 0' -mw1 <<EOF
1549 > y
1549 > y
1550 > y
1550 > y
1551 > EOF
1551 > EOF
1552 diff --git a/subdir/f1 b/subdir/f1
1552 diff --git a/subdir/f1 b/subdir/f1
1553 1 hunks, 1 lines changed
1553 1 hunks, 1 lines changed
1554 examine changes to 'subdir/f1'? [Ynesfdaq?] y
1554 examine changes to 'subdir/f1'? [Ynesfdaq?] y
1555
1555
1556 @@ -3,3 +3,4 @@ a
1556 @@ -3,3 +3,4 @@ a
1557 a
1557 a
1558 b
1558 b
1559 c
1559 c
1560 +d
1560 +d
1561 record this change to 'subdir/f1'? [Ynesfdaq?] y
1561 record this change to 'subdir/f1'? [Ynesfdaq?] y
1562
1562
1563
1563
1564 $ hg status -A subdir/f1
1564 $ hg status -A subdir/f1
1565 C subdir/f1
1565 C subdir/f1
1566 $ hg tip -p
1566 $ hg tip -p
1567 changeset: 30:* (glob)
1567 changeset: 30:* (glob)
1568 tag: tip
1568 tag: tip
1569 user: test
1569 user: test
1570 date: Thu Jan 01 00:00:24 1970 +0000
1570 date: Thu Jan 01 00:00:24 1970 +0000
1571 summary: w1
1571 summary: w1
1572
1572
1573 diff -r ???????????? -r ???????????? subdir/f1 (glob)
1573 diff -r ???????????? -r ???????????? subdir/f1 (glob)
1574 --- a/subdir/f1 Thu Jan 01 00:00:23 1970 +0000
1574 --- a/subdir/f1 Thu Jan 01 00:00:23 1970 +0000
1575 +++ b/subdir/f1 Thu Jan 01 00:00:24 1970 +0000
1575 +++ b/subdir/f1 Thu Jan 01 00:00:24 1970 +0000
1576 @@ -3,3 +3,4 @@
1576 @@ -3,3 +3,4 @@
1577 a
1577 a
1578 b
1578 b
1579 c
1579 c
1580 +d
1580 +d
1581
1581
1582
1582
1583
1583
1584 Test --user when ui.username not set
1584 Test --user when ui.username not set
1585 $ unset HGUSER
1585 $ unset HGUSER
1586 $ echo e >> subdir/f1
1586 $ echo e >> subdir/f1
1587 $ hg commit -i --config ui.username= -d '8 0' --user xyz -m "user flag" <<EOF
1587 $ hg commit -i --config ui.username= -d '8 0' --user xyz -m "user flag" <<EOF
1588 > y
1588 > y
1589 > y
1589 > y
1590 > EOF
1590 > EOF
1591 diff --git a/subdir/f1 b/subdir/f1
1591 diff --git a/subdir/f1 b/subdir/f1
1592 1 hunks, 1 lines changed
1592 1 hunks, 1 lines changed
1593 examine changes to 'subdir/f1'? [Ynesfdaq?] y
1593 examine changes to 'subdir/f1'? [Ynesfdaq?] y
1594
1594
1595 @@ -4,3 +4,4 @@ a
1595 @@ -4,3 +4,4 @@ a
1596 b
1596 b
1597 c
1597 c
1598 d
1598 d
1599 +e
1599 +e
1600 record this change to 'subdir/f1'? [Ynesfdaq?] y
1600 record this change to 'subdir/f1'? [Ynesfdaq?] y
1601
1601
1602 $ hg status -A subdir/f1
1602 $ hg status -A subdir/f1
1603 C subdir/f1
1603 C subdir/f1
1604 $ hg log --template '{author}\n' -l 1
1604 $ hg log --template '{author}\n' -l 1
1605 xyz
1605 xyz
1606 $ HGUSER="test"
1606 $ HGUSER="test"
1607 $ export HGUSER
1607 $ export HGUSER
1608
1608
1609
1609
1610 Moving files
1610 Moving files
1611
1611
1612 $ hg update -C .
1612 $ hg update -C .
1613 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1613 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1614 $ hg mv plain plain3
1614 $ hg mv plain plain3
1615 $ echo somechange >> plain3
1615 $ echo somechange >> plain3
1616 $ hg commit -i -d '23 0' -mmoving_files << EOF
1616 $ hg commit -i -d '23 0' -mmoving_files << EOF
1617 > y
1617 > y
1618 > y
1618 > y
1619 > EOF
1619 > EOF
1620 diff --git a/plain b/plain3
1620 diff --git a/plain b/plain3
1621 rename from plain
1621 rename from plain
1622 rename to plain3
1622 rename to plain3
1623 1 hunks, 1 lines changed
1623 1 hunks, 1 lines changed
1624 examine changes to 'plain' and 'plain3'? [Ynesfdaq?] y
1624 examine changes to 'plain' and 'plain3'? [Ynesfdaq?] y
1625
1625
1626 @@ -11,3 +11,4 @@ 8
1626 @@ -11,3 +11,4 @@ 8
1627 9
1627 9
1628 10
1628 10
1629 11
1629 11
1630 +somechange
1630 +somechange
1631 record this change to 'plain3'? [Ynesfdaq?] y
1631 record this change to 'plain3'? [Ynesfdaq?] y
1632
1632
1633 The #if execbit block above changes the hash here on some systems
1633 The #if execbit block above changes the hash here on some systems
1634 $ hg status -A plain3
1634 $ hg status -A plain3
1635 C plain3
1635 C plain3
1636 $ hg tip
1636 $ hg tip
1637 changeset: 32:* (glob)
1637 changeset: 32:* (glob)
1638 tag: tip
1638 tag: tip
1639 user: test
1639 user: test
1640 date: Thu Jan 01 00:00:23 1970 +0000
1640 date: Thu Jan 01 00:00:23 1970 +0000
1641 summary: moving_files
1641 summary: moving_files
1642
1642
1643 Editing patch of newly added file
1643 Editing patch of newly added file
1644
1644
1645 $ hg update -C .
1645 $ hg update -C .
1646 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1646 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1647 $ cat > editor.sh << '__EOF__'
1647 $ cat > editor.sh << '__EOF__'
1648 > cat "$1" | sed "s/first/very/g" > tt
1648 > cat "$1" | sed "s/first/very/g" > tt
1649 > mv tt "$1"
1649 > mv tt "$1"
1650 > __EOF__
1650 > __EOF__
1651 $ cat > newfile << '__EOF__'
1651 $ cat > newfile << '__EOF__'
1652 > This is the first line
1652 > This is the first line
1653 > This is the second line
1653 > This is the second line
1654 > This is the third line
1654 > This is the third line
1655 > __EOF__
1655 > __EOF__
1656 $ hg add newfile
1656 $ hg add newfile
1657 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit -i -d '23 0' -medit-patch-new <<EOF
1657 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit -i -d '23 0' -medit-patch-new <<EOF
1658 > y
1658 > y
1659 > e
1659 > e
1660 > EOF
1660 > EOF
1661 diff --git a/newfile b/newfile
1661 diff --git a/newfile b/newfile
1662 new file mode 100644
1662 new file mode 100644
1663 examine changes to 'newfile'? [Ynesfdaq?] y
1663 examine changes to 'newfile'? [Ynesfdaq?] y
1664
1664
1665 @@ -0,0 +1,3 @@
1665 @@ -0,0 +1,3 @@
1666 +This is the first line
1666 +This is the first line
1667 +This is the second line
1667 +This is the second line
1668 +This is the third line
1668 +This is the third line
1669 record this change to 'newfile'? [Ynesfdaq?] e
1669 record this change to 'newfile'? [Ynesfdaq?] e
1670
1670
1671 $ hg cat -r tip newfile
1671 $ hg cat -r tip newfile
1672 This is the very line
1672 This is the very line
1673 This is the second line
1673 This is the second line
1674 This is the third line
1674 This is the third line
1675
1675
1676 $ cat newfile
1676 $ cat newfile
1677 This is the first line
1677 This is the first line
1678 This is the second line
1678 This is the second line
1679 This is the third line
1679 This is the third line
1680
1680
1681 Add new file from within a subdirectory
1681 Add new file from within a subdirectory
1682 $ hg update -C .
1682 $ hg update -C .
1683 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1683 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1684 $ mkdir folder
1684 $ mkdir folder
1685 $ cd folder
1685 $ cd folder
1686 $ echo "foo" > bar
1686 $ echo "foo" > bar
1687 $ hg add bar
1687 $ hg add bar
1688 $ hg commit -i -d '23 0' -mnewfilesubdir <<EOF
1688 $ hg commit -i -d '23 0' -mnewfilesubdir <<EOF
1689 > y
1689 > y
1690 > y
1690 > y
1691 > EOF
1691 > EOF
1692 diff --git a/folder/bar b/folder/bar
1692 diff --git a/folder/bar b/folder/bar
1693 new file mode 100644
1693 new file mode 100644
1694 examine changes to 'folder/bar'? [Ynesfdaq?] y
1694 examine changes to 'folder/bar'? [Ynesfdaq?] y
1695
1695
1696 @@ -0,0 +1,1 @@
1696 @@ -0,0 +1,1 @@
1697 +foo
1697 +foo
1698 record this change to 'folder/bar'? [Ynesfdaq?] y
1698 record this change to 'folder/bar'? [Ynesfdaq?] y
1699
1699
1700 The #if execbit block above changes the hashes here on some systems
1700 The #if execbit block above changes the hashes here on some systems
1701 $ hg tip -p
1701 $ hg tip -p
1702 changeset: 34:* (glob)
1702 changeset: 34:* (glob)
1703 tag: tip
1703 tag: tip
1704 user: test
1704 user: test
1705 date: Thu Jan 01 00:00:23 1970 +0000
1705 date: Thu Jan 01 00:00:23 1970 +0000
1706 summary: newfilesubdir
1706 summary: newfilesubdir
1707
1707
1708 diff -r * -r * folder/bar (glob)
1708 diff -r * -r * folder/bar (glob)
1709 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1709 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1710 +++ b/folder/bar Thu Jan 01 00:00:23 1970 +0000
1710 +++ b/folder/bar Thu Jan 01 00:00:23 1970 +0000
1711 @@ -0,0 +1,1 @@
1711 @@ -0,0 +1,1 @@
1712 +foo
1712 +foo
1713
1713
1714 $ cd ..
1714 $ cd ..
1715
1715
1716 $ hg status -A folder/bar
1716 $ hg status -A folder/bar
1717 C folder/bar
1717 C folder/bar
1718
1718
1719 Clear win32text configuration before size/timestamp sensitive test
1719 Clear win32text configuration before size/timestamp sensitive test
1720
1720
1721 $ cat >> .hg/hgrc <<EOF
1721 $ cat >> .hg/hgrc <<EOF
1722 > [extensions]
1722 > [extensions]
1723 > win32text = !
1723 > win32text = !
1724 > [decode]
1724 > [decode]
1725 > ** = !
1725 > ** = !
1726 > [encode]
1726 > [encode]
1727 > ** = !
1727 > ** = !
1728 > [patch]
1728 > [patch]
1729 > eol = strict
1729 > eol = strict
1730 > EOF
1730 > EOF
1731 $ hg update -q -C null
1731 $ hg update -q -C null
1732 $ hg update -q -C tip
1732 $ hg update -q -C tip
1733
1733
1734 Test that partially committed file is still treated as "modified",
1734 Test that partially committed file is still treated as "modified",
1735 even if none of mode, size and timestamp is changed on the filesystem
1735 even if none of mode, size and timestamp is changed on the filesystem
1736 (see also issue4583).
1736 (see also issue4583).
1737
1737
1738 $ cat > subdir/f1 <<EOF
1738 $ cat > subdir/f1 <<EOF
1739 > A
1739 > A
1740 > a
1740 > a
1741 > a
1741 > a
1742 > b
1742 > b
1743 > c
1743 > c
1744 > d
1744 > d
1745 > E
1745 > E
1746 > EOF
1746 > EOF
1747 $ hg diff --git subdir/f1
1747 $ hg diff --git subdir/f1
1748 diff --git a/subdir/f1 b/subdir/f1
1748 diff --git a/subdir/f1 b/subdir/f1
1749 --- a/subdir/f1
1749 --- a/subdir/f1
1750 +++ b/subdir/f1
1750 +++ b/subdir/f1
1751 @@ -1,7 +1,7 @@
1751 @@ -1,7 +1,7 @@
1752 -a
1752 -a
1753 +A
1753 +A
1754 a
1754 a
1755 a
1755 a
1756 b
1756 b
1757 c
1757 c
1758 d
1758 d
1759 -e
1759 -e
1760 +E
1760 +E
1761
1761
1762 $ touch -t 200001010000 subdir/f1
1762 $ touch -t 200001010000 subdir/f1
1763
1763
1764 $ cat >> .hg/hgrc <<EOF
1764 $ cat >> .hg/hgrc <<EOF
1765 > # emulate invoking patch.internalpatch() at 2000-01-01 00:00
1765 > # emulate invoking patch.internalpatch() at 2000-01-01 00:00
1766 > [fakepatchtime]
1766 > [fakepatchtime]
1767 > fakenow = 200001010000
1767 > fakenow = 200001010000
1768 >
1768 >
1769 > [extensions]
1769 > [extensions]
1770 > fakepatchtime = $TESTDIR/fakepatchtime.py
1770 > fakepatchtime = $TESTDIR/fakepatchtime.py
1771 > EOF
1771 > EOF
1772 $ hg commit -i -m 'commit subdir/f1 partially' <<EOF
1772 $ hg commit -i -m 'commit subdir/f1 partially' <<EOF
1773 > y
1773 > y
1774 > y
1774 > y
1775 > n
1775 > n
1776 > EOF
1776 > EOF
1777 diff --git a/subdir/f1 b/subdir/f1
1777 diff --git a/subdir/f1 b/subdir/f1
1778 2 hunks, 2 lines changed
1778 2 hunks, 2 lines changed
1779 examine changes to 'subdir/f1'? [Ynesfdaq?] y
1779 examine changes to 'subdir/f1'? [Ynesfdaq?] y
1780
1780
1781 @@ -1,6 +1,6 @@
1781 @@ -1,6 +1,6 @@
1782 -a
1782 -a
1783 +A
1783 +A
1784 a
1784 a
1785 a
1785 a
1786 b
1786 b
1787 c
1787 c
1788 d
1788 d
1789 record change 1/2 to 'subdir/f1'? [Ynesfdaq?] y
1789 record change 1/2 to 'subdir/f1'? [Ynesfdaq?] y
1790
1790
1791 @@ -2,6 +2,6 @@
1791 @@ -2,6 +2,6 @@
1792 a
1792 a
1793 a
1793 a
1794 b
1794 b
1795 c
1795 c
1796 d
1796 d
1797 -e
1797 -e
1798 +E
1798 +E
1799 record change 2/2 to 'subdir/f1'? [Ynesfdaq?] n
1799 record change 2/2 to 'subdir/f1'? [Ynesfdaq?] n
1800
1800
1801 $ cat >> .hg/hgrc <<EOF
1801 $ cat >> .hg/hgrc <<EOF
1802 > [extensions]
1802 > [extensions]
1803 > fakepatchtime = !
1803 > fakepatchtime = !
1804 > EOF
1804 > EOF
1805
1805
1806 $ hg debugstate | grep ' subdir/f1$'
1806 $ hg debugstate | grep ' subdir/f1$'
1807 n 0 -1 unset subdir/f1
1807 n 0 -1 unset subdir/f1
1808 $ hg status -A subdir/f1
1808 $ hg status -A subdir/f1
1809 M subdir/f1
1809 M subdir/f1
1810
1810
1811 Test diff.unified=0
1811 Test commands.commit.interactive.unified=0
1812
1812
1813 $ hg init $TESTTMP/b
1813 $ hg init $TESTTMP/b
1814 $ cd $TESTTMP/b
1814 $ cd $TESTTMP/b
1815 $ cat > foo <<EOF
1815 $ cat > foo <<EOF
1816 > 1
1816 > 1
1817 > 2
1817 > 2
1818 > 3
1818 > 3
1819 > 4
1819 > 4
1820 > 5
1820 > 5
1821 > EOF
1821 > EOF
1822 $ hg ci -qAm initial
1822 $ hg ci -qAm initial
1823 $ cat > foo <<EOF
1823 $ cat > foo <<EOF
1824 > 1
1824 > 1
1825 > change1
1825 > change1
1826 > 2
1826 > 2
1827 > 3
1827 > 3
1828 > change2
1828 > change2
1829 > 4
1829 > 4
1830 > 5
1830 > 5
1831 > EOF
1831 > EOF
1832 $ printf 'y\ny\ny\n' | hg ci -im initial --config diff.unified=0
1832 $ printf 'y\ny\ny\n' | hg ci -im initial --config commands.commit.interactive.unified=0
1833 diff --git a/foo b/foo
1833 diff --git a/foo b/foo
1834 2 hunks, 2 lines changed
1834 2 hunks, 2 lines changed
1835 examine changes to 'foo'? [Ynesfdaq?] y
1835 examine changes to 'foo'? [Ynesfdaq?] y
1836
1836
1837 @@ -1,0 +2,1 @@ 1
1837 @@ -1,0 +2,1 @@ 1
1838 +change1
1838 +change1
1839 record change 1/2 to 'foo'? [Ynesfdaq?] y
1839 record change 1/2 to 'foo'? [Ynesfdaq?] y
1840
1840
1841 @@ -3,0 +5,1 @@ 3
1841 @@ -3,0 +5,1 @@ 3
1842 +change2
1842 +change2
1843 record change 2/2 to 'foo'? [Ynesfdaq?] y
1843 record change 2/2 to 'foo'? [Ynesfdaq?] y
1844
1844
1845 $ cd $TESTTMP
1845 $ cd $TESTTMP
1846
1846
1847 Test diff.ignoreblanklines=1
1847 Test diff.ignoreblanklines=1
1848
1848
1849 $ hg init c
1849 $ hg init c
1850 $ cd c
1850 $ cd c
1851 $ cat > foo <<EOF
1851 $ cat > foo <<EOF
1852 > 1
1852 > 1
1853 > 2
1853 > 2
1854 > 3
1854 > 3
1855 > 4
1855 > 4
1856 > 5
1856 > 5
1857 > EOF
1857 > EOF
1858 $ hg ci -qAm initial
1858 $ hg ci -qAm initial
1859 $ cat > foo <<EOF
1859 $ cat > foo <<EOF
1860 > 1
1860 > 1
1861 >
1861 >
1862 > 2
1862 > 2
1863 > 3
1863 > 3
1864 > change2
1864 > change2
1865 > 4
1865 > 4
1866 > 5
1866 > 5
1867 > EOF
1867 > EOF
1868 $ printf 'y\ny\ny\n' | hg ci -im initial --config diff.ignoreblanklines=1
1868 $ printf 'y\ny\ny\n' | hg ci -im initial --config diff.ignoreblanklines=1
1869 diff --git a/foo b/foo
1869 diff --git a/foo b/foo
1870 2 hunks, 2 lines changed
1870 2 hunks, 2 lines changed
1871 examine changes to 'foo'? [Ynesfdaq?] y
1871 examine changes to 'foo'? [Ynesfdaq?] y
1872
1872
1873 @@ -1,3 +1,4 @@
1873 @@ -1,3 +1,4 @@
1874 1
1874 1
1875 +
1875 +
1876 2
1876 2
1877 3
1877 3
1878 record change 1/2 to 'foo'? [Ynesfdaq?] y
1878 record change 1/2 to 'foo'? [Ynesfdaq?] y
1879
1879
1880 @@ -2,4 +3,5 @@
1880 @@ -2,4 +3,5 @@
1881 2
1881 2
1882 3
1882 3
1883 +change2
1883 +change2
1884 4
1884 4
1885 5
1885 5
1886 record change 2/2 to 'foo'? [Ynesfdaq?] y
1886 record change 2/2 to 'foo'? [Ynesfdaq?] y
1887
1887
1888
1888
@@ -1,709 +1,711 b''
1 #testcases obsstore-on obsstore-off
1 #testcases obsstore-on obsstore-off
2
2
3 $ cat > $TESTTMP/editor.py <<EOF
3 $ cat > $TESTTMP/editor.py <<EOF
4 > #!"$PYTHON"
4 > #!"$PYTHON"
5 > import os
5 > import os
6 > import sys
6 > import sys
7 > path = os.path.join(os.environ['TESTTMP'], 'messages')
7 > path = os.path.join(os.environ['TESTTMP'], 'messages')
8 > messages = open(path).read().split('--\n')
8 > messages = open(path).read().split('--\n')
9 > prompt = open(sys.argv[1]).read()
9 > prompt = open(sys.argv[1]).read()
10 > sys.stdout.write(''.join('EDITOR: %s' % l for l in prompt.splitlines(True)))
10 > sys.stdout.write(''.join('EDITOR: %s' % l for l in prompt.splitlines(True)))
11 > sys.stdout.flush()
11 > sys.stdout.flush()
12 > with open(sys.argv[1], 'w') as f:
12 > with open(sys.argv[1], 'w') as f:
13 > f.write(messages[0])
13 > f.write(messages[0])
14 > with open(path, 'w') as f:
14 > with open(path, 'w') as f:
15 > f.write('--\n'.join(messages[1:]))
15 > f.write('--\n'.join(messages[1:]))
16 > EOF
16 > EOF
17
17
18 $ cat >> $HGRCPATH <<EOF
18 $ cat >> $HGRCPATH <<EOF
19 > [extensions]
19 > [extensions]
20 > drawdag=$TESTDIR/drawdag.py
20 > drawdag=$TESTDIR/drawdag.py
21 > split=
21 > split=
22 > [ui]
22 > [ui]
23 > interactive=1
23 > interactive=1
24 > color=no
24 > color=no
25 > paginate=never
25 > paginate=never
26 > [diff]
26 > [diff]
27 > git=1
27 > git=1
28 > unified=0
28 > unified=0
29 > [commands]
30 > commit.interactive.unified=0
29 > [alias]
31 > [alias]
30 > glog=log -G -T '{rev}:{node|short} {desc} {bookmarks}\n'
32 > glog=log -G -T '{rev}:{node|short} {desc} {bookmarks}\n'
31 > EOF
33 > EOF
32
34
33 #if obsstore-on
35 #if obsstore-on
34 $ cat >> $HGRCPATH <<EOF
36 $ cat >> $HGRCPATH <<EOF
35 > [experimental]
37 > [experimental]
36 > evolution=all
38 > evolution=all
37 > EOF
39 > EOF
38 #endif
40 #endif
39
41
40 $ hg init a
42 $ hg init a
41 $ cd a
43 $ cd a
42
44
43 Nothing to split
45 Nothing to split
44
46
45 $ hg split
47 $ hg split
46 nothing to split
48 nothing to split
47 [1]
49 [1]
48
50
49 $ hg commit -m empty --config ui.allowemptycommit=1
51 $ hg commit -m empty --config ui.allowemptycommit=1
50 $ hg split
52 $ hg split
51 abort: cannot split an empty revision
53 abort: cannot split an empty revision
52 [255]
54 [255]
53
55
54 $ rm -rf .hg
56 $ rm -rf .hg
55 $ hg init
57 $ hg init
56
58
57 Cannot split working directory
59 Cannot split working directory
58
60
59 $ hg split -r 'wdir()'
61 $ hg split -r 'wdir()'
60 abort: cannot split working directory
62 abort: cannot split working directory
61 [255]
63 [255]
62
64
63 Generate some content. The sed filter drop CR on Windows, which is dropped in
65 Generate some content. The sed filter drop CR on Windows, which is dropped in
64 the a > b line.
66 the a > b line.
65
67
66 $ $TESTDIR/seq.py 1 5 | sed 's/\r$//' >> a
68 $ $TESTDIR/seq.py 1 5 | sed 's/\r$//' >> a
67 $ hg ci -m a1 -A a -q
69 $ hg ci -m a1 -A a -q
68 $ hg bookmark -i r1
70 $ hg bookmark -i r1
69 $ sed 's/1/11/;s/3/33/;s/5/55/' a > b
71 $ sed 's/1/11/;s/3/33/;s/5/55/' a > b
70 $ mv b a
72 $ mv b a
71 $ hg ci -m a2 -q
73 $ hg ci -m a2 -q
72 $ hg bookmark -i r2
74 $ hg bookmark -i r2
73
75
74 Cannot split a public changeset
76 Cannot split a public changeset
75
77
76 $ hg phase --public -r 'all()'
78 $ hg phase --public -r 'all()'
77 $ hg split .
79 $ hg split .
78 abort: cannot split public changeset
80 abort: cannot split public changeset
79 (see 'hg help phases' for details)
81 (see 'hg help phases' for details)
80 [255]
82 [255]
81
83
82 $ hg phase --draft -f -r 'all()'
84 $ hg phase --draft -f -r 'all()'
83
85
84 Cannot split while working directory is dirty
86 Cannot split while working directory is dirty
85
87
86 $ touch dirty
88 $ touch dirty
87 $ hg add dirty
89 $ hg add dirty
88 $ hg split .
90 $ hg split .
89 abort: uncommitted changes
91 abort: uncommitted changes
90 [255]
92 [255]
91 $ hg forget dirty
93 $ hg forget dirty
92 $ rm dirty
94 $ rm dirty
93
95
94 Make a clean directory for future tests to build off of
96 Make a clean directory for future tests to build off of
95
97
96 $ cp -R . ../clean
98 $ cp -R . ../clean
97
99
98 Split a head
100 Split a head
99
101
100 $ hg bookmark r3
102 $ hg bookmark r3
101
103
102 $ hg split 'all()'
104 $ hg split 'all()'
103 abort: cannot split multiple revisions
105 abort: cannot split multiple revisions
104 [255]
106 [255]
105
107
106 This function splits a bit strangely primarily to avoid changing the behavior of
108 This function splits a bit strangely primarily to avoid changing the behavior of
107 the test after a bug was fixed with how split/commit --interactive handled
109 the test after a bug was fixed with how split/commit --interactive handled
108 `diff.unified=0`: when there were no context lines, it kept only the last diff
110 `commands.commit.interactive.unified=0`: when there were no context lines,
109 hunk. When running split, this meant that runsplit was always recording three commits,
111 it kept only the last diff hunk. When running split, this meant that runsplit
110 one for each diff hunk, in reverse order (the base commit was the last diff hunk
112 was always recording three commits, one for each diff hunk, in reverse order
111 in the file).
113 (the base commit was the last diff hunk in the file).
112 $ runsplit() {
114 $ runsplit() {
113 > cat > $TESTTMP/messages <<EOF
115 > cat > $TESTTMP/messages <<EOF
114 > split 1
116 > split 1
115 > --
117 > --
116 > split 2
118 > split 2
117 > --
119 > --
118 > split 3
120 > split 3
119 > EOF
121 > EOF
120 > cat <<EOF | hg split "$@"
122 > cat <<EOF | hg split "$@"
121 > y
123 > y
122 > n
124 > n
123 > n
125 > n
124 > y
126 > y
125 > y
127 > y
126 > n
128 > n
127 > y
129 > y
128 > y
130 > y
129 > y
131 > y
130 > EOF
132 > EOF
131 > }
133 > }
132
134
133 $ HGEDITOR=false runsplit
135 $ HGEDITOR=false runsplit
134 diff --git a/a b/a
136 diff --git a/a b/a
135 3 hunks, 3 lines changed
137 3 hunks, 3 lines changed
136 examine changes to 'a'? [Ynesfdaq?] y
138 examine changes to 'a'? [Ynesfdaq?] y
137
139
138 @@ -1,1 +1,1 @@
140 @@ -1,1 +1,1 @@
139 -1
141 -1
140 +11
142 +11
141 record change 1/3 to 'a'? [Ynesfdaq?] n
143 record change 1/3 to 'a'? [Ynesfdaq?] n
142
144
143 @@ -3,1 +3,1 @@ 2
145 @@ -3,1 +3,1 @@ 2
144 -3
146 -3
145 +33
147 +33
146 record change 2/3 to 'a'? [Ynesfdaq?] n
148 record change 2/3 to 'a'? [Ynesfdaq?] n
147
149
148 @@ -5,1 +5,1 @@ 4
150 @@ -5,1 +5,1 @@ 4
149 -5
151 -5
150 +55
152 +55
151 record change 3/3 to 'a'? [Ynesfdaq?] y
153 record change 3/3 to 'a'? [Ynesfdaq?] y
152
154
153 transaction abort!
155 transaction abort!
154 rollback completed
156 rollback completed
155 abort: edit failed: false exited with status 1
157 abort: edit failed: false exited with status 1
156 [255]
158 [255]
157 $ hg status
159 $ hg status
158
160
159 $ HGEDITOR="\"$PYTHON\" $TESTTMP/editor.py"
161 $ HGEDITOR="\"$PYTHON\" $TESTTMP/editor.py"
160 $ runsplit
162 $ runsplit
161 diff --git a/a b/a
163 diff --git a/a b/a
162 3 hunks, 3 lines changed
164 3 hunks, 3 lines changed
163 examine changes to 'a'? [Ynesfdaq?] y
165 examine changes to 'a'? [Ynesfdaq?] y
164
166
165 @@ -1,1 +1,1 @@
167 @@ -1,1 +1,1 @@
166 -1
168 -1
167 +11
169 +11
168 record change 1/3 to 'a'? [Ynesfdaq?] n
170 record change 1/3 to 'a'? [Ynesfdaq?] n
169
171
170 @@ -3,1 +3,1 @@ 2
172 @@ -3,1 +3,1 @@ 2
171 -3
173 -3
172 +33
174 +33
173 record change 2/3 to 'a'? [Ynesfdaq?] n
175 record change 2/3 to 'a'? [Ynesfdaq?] n
174
176
175 @@ -5,1 +5,1 @@ 4
177 @@ -5,1 +5,1 @@ 4
176 -5
178 -5
177 +55
179 +55
178 record change 3/3 to 'a'? [Ynesfdaq?] y
180 record change 3/3 to 'a'? [Ynesfdaq?] y
179
181
180 EDITOR: HG: Splitting 1df0d5c5a3ab. Write commit message for the first split changeset.
182 EDITOR: HG: Splitting 1df0d5c5a3ab. Write commit message for the first split changeset.
181 EDITOR: a2
183 EDITOR: a2
182 EDITOR:
184 EDITOR:
183 EDITOR:
185 EDITOR:
184 EDITOR: HG: Enter commit message. Lines beginning with 'HG:' are removed.
186 EDITOR: HG: Enter commit message. Lines beginning with 'HG:' are removed.
185 EDITOR: HG: Leave message empty to abort commit.
187 EDITOR: HG: Leave message empty to abort commit.
186 EDITOR: HG: --
188 EDITOR: HG: --
187 EDITOR: HG: user: test
189 EDITOR: HG: user: test
188 EDITOR: HG: branch 'default'
190 EDITOR: HG: branch 'default'
189 EDITOR: HG: changed a
191 EDITOR: HG: changed a
190 created new head
192 created new head
191 diff --git a/a b/a
193 diff --git a/a b/a
192 2 hunks, 2 lines changed
194 2 hunks, 2 lines changed
193 examine changes to 'a'? [Ynesfdaq?] y
195 examine changes to 'a'? [Ynesfdaq?] y
194
196
195 @@ -1,1 +1,1 @@
197 @@ -1,1 +1,1 @@
196 -1
198 -1
197 +11
199 +11
198 record change 1/2 to 'a'? [Ynesfdaq?] n
200 record change 1/2 to 'a'? [Ynesfdaq?] n
199
201
200 @@ -3,1 +3,1 @@ 2
202 @@ -3,1 +3,1 @@ 2
201 -3
203 -3
202 +33
204 +33
203 record change 2/2 to 'a'? [Ynesfdaq?] y
205 record change 2/2 to 'a'? [Ynesfdaq?] y
204
206
205 EDITOR: HG: Splitting 1df0d5c5a3ab. So far it has been split into:
207 EDITOR: HG: Splitting 1df0d5c5a3ab. So far it has been split into:
206 EDITOR: HG: - e704349bd21b: split 1
208 EDITOR: HG: - e704349bd21b: split 1
207 EDITOR: HG: Write commit message for the next split changeset.
209 EDITOR: HG: Write commit message for the next split changeset.
208 EDITOR: a2
210 EDITOR: a2
209 EDITOR:
211 EDITOR:
210 EDITOR:
212 EDITOR:
211 EDITOR: HG: Enter commit message. Lines beginning with 'HG:' are removed.
213 EDITOR: HG: Enter commit message. Lines beginning with 'HG:' are removed.
212 EDITOR: HG: Leave message empty to abort commit.
214 EDITOR: HG: Leave message empty to abort commit.
213 EDITOR: HG: --
215 EDITOR: HG: --
214 EDITOR: HG: user: test
216 EDITOR: HG: user: test
215 EDITOR: HG: branch 'default'
217 EDITOR: HG: branch 'default'
216 EDITOR: HG: changed a
218 EDITOR: HG: changed a
217 diff --git a/a b/a
219 diff --git a/a b/a
218 1 hunks, 1 lines changed
220 1 hunks, 1 lines changed
219 examine changes to 'a'? [Ynesfdaq?] y
221 examine changes to 'a'? [Ynesfdaq?] y
220
222
221 @@ -1,1 +1,1 @@
223 @@ -1,1 +1,1 @@
222 -1
224 -1
223 +11
225 +11
224 record this change to 'a'? [Ynesfdaq?] y
226 record this change to 'a'? [Ynesfdaq?] y
225
227
226 EDITOR: HG: Splitting 1df0d5c5a3ab. So far it has been split into:
228 EDITOR: HG: Splitting 1df0d5c5a3ab. So far it has been split into:
227 EDITOR: HG: - e704349bd21b: split 1
229 EDITOR: HG: - e704349bd21b: split 1
228 EDITOR: HG: - a09ad58faae3: split 2
230 EDITOR: HG: - a09ad58faae3: split 2
229 EDITOR: HG: Write commit message for the next split changeset.
231 EDITOR: HG: Write commit message for the next split changeset.
230 EDITOR: a2
232 EDITOR: a2
231 EDITOR:
233 EDITOR:
232 EDITOR:
234 EDITOR:
233 EDITOR: HG: Enter commit message. Lines beginning with 'HG:' are removed.
235 EDITOR: HG: Enter commit message. Lines beginning with 'HG:' are removed.
234 EDITOR: HG: Leave message empty to abort commit.
236 EDITOR: HG: Leave message empty to abort commit.
235 EDITOR: HG: --
237 EDITOR: HG: --
236 EDITOR: HG: user: test
238 EDITOR: HG: user: test
237 EDITOR: HG: branch 'default'
239 EDITOR: HG: branch 'default'
238 EDITOR: HG: changed a
240 EDITOR: HG: changed a
239 saved backup bundle to $TESTTMP/a/.hg/strip-backup/1df0d5c5a3ab-8341b760-split.hg (obsstore-off !)
241 saved backup bundle to $TESTTMP/a/.hg/strip-backup/1df0d5c5a3ab-8341b760-split.hg (obsstore-off !)
240
242
241 #if obsstore-off
243 #if obsstore-off
242 $ hg bookmark
244 $ hg bookmark
243 r1 0:a61bcde8c529
245 r1 0:a61bcde8c529
244 r2 3:00eebaf8d2e2
246 r2 3:00eebaf8d2e2
245 * r3 3:00eebaf8d2e2
247 * r3 3:00eebaf8d2e2
246 $ hg glog -p
248 $ hg glog -p
247 @ 3:00eebaf8d2e2 split 3 r2 r3
249 @ 3:00eebaf8d2e2 split 3 r2 r3
248 | diff --git a/a b/a
250 | diff --git a/a b/a
249 | --- a/a
251 | --- a/a
250 | +++ b/a
252 | +++ b/a
251 | @@ -1,1 +1,1 @@
253 | @@ -1,1 +1,1 @@
252 | -1
254 | -1
253 | +11
255 | +11
254 |
256 |
255 o 2:a09ad58faae3 split 2
257 o 2:a09ad58faae3 split 2
256 | diff --git a/a b/a
258 | diff --git a/a b/a
257 | --- a/a
259 | --- a/a
258 | +++ b/a
260 | +++ b/a
259 | @@ -3,1 +3,1 @@
261 | @@ -3,1 +3,1 @@
260 | -3
262 | -3
261 | +33
263 | +33
262 |
264 |
263 o 1:e704349bd21b split 1
265 o 1:e704349bd21b split 1
264 | diff --git a/a b/a
266 | diff --git a/a b/a
265 | --- a/a
267 | --- a/a
266 | +++ b/a
268 | +++ b/a
267 | @@ -5,1 +5,1 @@
269 | @@ -5,1 +5,1 @@
268 | -5
270 | -5
269 | +55
271 | +55
270 |
272 |
271 o 0:a61bcde8c529 a1 r1
273 o 0:a61bcde8c529 a1 r1
272 diff --git a/a b/a
274 diff --git a/a b/a
273 new file mode 100644
275 new file mode 100644
274 --- /dev/null
276 --- /dev/null
275 +++ b/a
277 +++ b/a
276 @@ -0,0 +1,5 @@
278 @@ -0,0 +1,5 @@
277 +1
279 +1
278 +2
280 +2
279 +3
281 +3
280 +4
282 +4
281 +5
283 +5
282
284
283 #else
285 #else
284 $ hg bookmark
286 $ hg bookmark
285 r1 0:a61bcde8c529
287 r1 0:a61bcde8c529
286 r2 4:00eebaf8d2e2
288 r2 4:00eebaf8d2e2
287 * r3 4:00eebaf8d2e2
289 * r3 4:00eebaf8d2e2
288 $ hg glog
290 $ hg glog
289 @ 4:00eebaf8d2e2 split 3 r2 r3
291 @ 4:00eebaf8d2e2 split 3 r2 r3
290 |
292 |
291 o 3:a09ad58faae3 split 2
293 o 3:a09ad58faae3 split 2
292 |
294 |
293 o 2:e704349bd21b split 1
295 o 2:e704349bd21b split 1
294 |
296 |
295 o 0:a61bcde8c529 a1 r1
297 o 0:a61bcde8c529 a1 r1
296
298
297 #endif
299 #endif
298
300
299 Split a head while working parent is not that head
301 Split a head while working parent is not that head
300
302
301 $ cp -R $TESTTMP/clean $TESTTMP/b
303 $ cp -R $TESTTMP/clean $TESTTMP/b
302 $ cd $TESTTMP/b
304 $ cd $TESTTMP/b
303
305
304 $ hg up 0 -q
306 $ hg up 0 -q
305 $ hg bookmark r3
307 $ hg bookmark r3
306
308
307 $ runsplit tip >/dev/null
309 $ runsplit tip >/dev/null
308
310
309 #if obsstore-off
311 #if obsstore-off
310 $ hg bookmark
312 $ hg bookmark
311 r1 0:a61bcde8c529
313 r1 0:a61bcde8c529
312 r2 3:00eebaf8d2e2
314 r2 3:00eebaf8d2e2
313 * r3 0:a61bcde8c529
315 * r3 0:a61bcde8c529
314 $ hg glog
316 $ hg glog
315 o 3:00eebaf8d2e2 split 3 r2
317 o 3:00eebaf8d2e2 split 3 r2
316 |
318 |
317 o 2:a09ad58faae3 split 2
319 o 2:a09ad58faae3 split 2
318 |
320 |
319 o 1:e704349bd21b split 1
321 o 1:e704349bd21b split 1
320 |
322 |
321 @ 0:a61bcde8c529 a1 r1 r3
323 @ 0:a61bcde8c529 a1 r1 r3
322
324
323 #else
325 #else
324 $ hg bookmark
326 $ hg bookmark
325 r1 0:a61bcde8c529
327 r1 0:a61bcde8c529
326 r2 4:00eebaf8d2e2
328 r2 4:00eebaf8d2e2
327 * r3 0:a61bcde8c529
329 * r3 0:a61bcde8c529
328 $ hg glog
330 $ hg glog
329 o 4:00eebaf8d2e2 split 3 r2
331 o 4:00eebaf8d2e2 split 3 r2
330 |
332 |
331 o 3:a09ad58faae3 split 2
333 o 3:a09ad58faae3 split 2
332 |
334 |
333 o 2:e704349bd21b split 1
335 o 2:e704349bd21b split 1
334 |
336 |
335 @ 0:a61bcde8c529 a1 r1 r3
337 @ 0:a61bcde8c529 a1 r1 r3
336
338
337 #endif
339 #endif
338
340
339 Split a non-head
341 Split a non-head
340
342
341 $ cp -R $TESTTMP/clean $TESTTMP/c
343 $ cp -R $TESTTMP/clean $TESTTMP/c
342 $ cd $TESTTMP/c
344 $ cd $TESTTMP/c
343 $ echo d > d
345 $ echo d > d
344 $ hg ci -m d1 -A d
346 $ hg ci -m d1 -A d
345 $ hg bookmark -i d1
347 $ hg bookmark -i d1
346 $ echo 2 >> d
348 $ echo 2 >> d
347 $ hg ci -m d2
349 $ hg ci -m d2
348 $ echo 3 >> d
350 $ echo 3 >> d
349 $ hg ci -m d3
351 $ hg ci -m d3
350 $ hg bookmark -i d3
352 $ hg bookmark -i d3
351 $ hg up '.^' -q
353 $ hg up '.^' -q
352 $ hg bookmark d2
354 $ hg bookmark d2
353 $ cp -R . ../d
355 $ cp -R . ../d
354
356
355 $ runsplit -r 1 | grep rebasing
357 $ runsplit -r 1 | grep rebasing
356 rebasing 2:b5c5ea414030 "d1" (d1)
358 rebasing 2:b5c5ea414030 "d1" (d1)
357 rebasing 3:f4a0a8d004cc "d2" (d2)
359 rebasing 3:f4a0a8d004cc "d2" (d2)
358 rebasing 4:777940761eba "d3" (d3)
360 rebasing 4:777940761eba "d3" (d3)
359 #if obsstore-off
361 #if obsstore-off
360 $ hg bookmark
362 $ hg bookmark
361 d1 4:c4b449ef030e
363 d1 4:c4b449ef030e
362 * d2 5:c9dd00ab36a3
364 * d2 5:c9dd00ab36a3
363 d3 6:19f476bc865c
365 d3 6:19f476bc865c
364 r1 0:a61bcde8c529
366 r1 0:a61bcde8c529
365 r2 3:00eebaf8d2e2
367 r2 3:00eebaf8d2e2
366 $ hg glog -p
368 $ hg glog -p
367 o 6:19f476bc865c d3 d3
369 o 6:19f476bc865c d3 d3
368 | diff --git a/d b/d
370 | diff --git a/d b/d
369 | --- a/d
371 | --- a/d
370 | +++ b/d
372 | +++ b/d
371 | @@ -2,0 +3,1 @@
373 | @@ -2,0 +3,1 @@
372 | +3
374 | +3
373 |
375 |
374 @ 5:c9dd00ab36a3 d2 d2
376 @ 5:c9dd00ab36a3 d2 d2
375 | diff --git a/d b/d
377 | diff --git a/d b/d
376 | --- a/d
378 | --- a/d
377 | +++ b/d
379 | +++ b/d
378 | @@ -1,0 +2,1 @@
380 | @@ -1,0 +2,1 @@
379 | +2
381 | +2
380 |
382 |
381 o 4:c4b449ef030e d1 d1
383 o 4:c4b449ef030e d1 d1
382 | diff --git a/d b/d
384 | diff --git a/d b/d
383 | new file mode 100644
385 | new file mode 100644
384 | --- /dev/null
386 | --- /dev/null
385 | +++ b/d
387 | +++ b/d
386 | @@ -0,0 +1,1 @@
388 | @@ -0,0 +1,1 @@
387 | +d
389 | +d
388 |
390 |
389 o 3:00eebaf8d2e2 split 3 r2
391 o 3:00eebaf8d2e2 split 3 r2
390 | diff --git a/a b/a
392 | diff --git a/a b/a
391 | --- a/a
393 | --- a/a
392 | +++ b/a
394 | +++ b/a
393 | @@ -1,1 +1,1 @@
395 | @@ -1,1 +1,1 @@
394 | -1
396 | -1
395 | +11
397 | +11
396 |
398 |
397 o 2:a09ad58faae3 split 2
399 o 2:a09ad58faae3 split 2
398 | diff --git a/a b/a
400 | diff --git a/a b/a
399 | --- a/a
401 | --- a/a
400 | +++ b/a
402 | +++ b/a
401 | @@ -3,1 +3,1 @@
403 | @@ -3,1 +3,1 @@
402 | -3
404 | -3
403 | +33
405 | +33
404 |
406 |
405 o 1:e704349bd21b split 1
407 o 1:e704349bd21b split 1
406 | diff --git a/a b/a
408 | diff --git a/a b/a
407 | --- a/a
409 | --- a/a
408 | +++ b/a
410 | +++ b/a
409 | @@ -5,1 +5,1 @@
411 | @@ -5,1 +5,1 @@
410 | -5
412 | -5
411 | +55
413 | +55
412 |
414 |
413 o 0:a61bcde8c529 a1 r1
415 o 0:a61bcde8c529 a1 r1
414 diff --git a/a b/a
416 diff --git a/a b/a
415 new file mode 100644
417 new file mode 100644
416 --- /dev/null
418 --- /dev/null
417 +++ b/a
419 +++ b/a
418 @@ -0,0 +1,5 @@
420 @@ -0,0 +1,5 @@
419 +1
421 +1
420 +2
422 +2
421 +3
423 +3
422 +4
424 +4
423 +5
425 +5
424
426
425 #else
427 #else
426 $ hg bookmark
428 $ hg bookmark
427 d1 8:c4b449ef030e
429 d1 8:c4b449ef030e
428 * d2 9:c9dd00ab36a3
430 * d2 9:c9dd00ab36a3
429 d3 10:19f476bc865c
431 d3 10:19f476bc865c
430 r1 0:a61bcde8c529
432 r1 0:a61bcde8c529
431 r2 7:00eebaf8d2e2
433 r2 7:00eebaf8d2e2
432 $ hg glog
434 $ hg glog
433 o 10:19f476bc865c d3 d3
435 o 10:19f476bc865c d3 d3
434 |
436 |
435 @ 9:c9dd00ab36a3 d2 d2
437 @ 9:c9dd00ab36a3 d2 d2
436 |
438 |
437 o 8:c4b449ef030e d1 d1
439 o 8:c4b449ef030e d1 d1
438 |
440 |
439 o 7:00eebaf8d2e2 split 3 r2
441 o 7:00eebaf8d2e2 split 3 r2
440 |
442 |
441 o 6:a09ad58faae3 split 2
443 o 6:a09ad58faae3 split 2
442 |
444 |
443 o 5:e704349bd21b split 1
445 o 5:e704349bd21b split 1
444 |
446 |
445 o 0:a61bcde8c529 a1 r1
447 o 0:a61bcde8c529 a1 r1
446
448
447 #endif
449 #endif
448
450
449 Split a non-head without rebase
451 Split a non-head without rebase
450
452
451 $ cd $TESTTMP/d
453 $ cd $TESTTMP/d
452 #if obsstore-off
454 #if obsstore-off
453 $ runsplit -r 1 --no-rebase
455 $ runsplit -r 1 --no-rebase
454 abort: cannot split changeset with children without rebase
456 abort: cannot split changeset with children without rebase
455 [255]
457 [255]
456 #else
458 #else
457 $ runsplit -r 1 --no-rebase >/dev/null
459 $ runsplit -r 1 --no-rebase >/dev/null
458 3 new orphan changesets
460 3 new orphan changesets
459 $ hg bookmark
461 $ hg bookmark
460 d1 2:b5c5ea414030
462 d1 2:b5c5ea414030
461 * d2 3:f4a0a8d004cc
463 * d2 3:f4a0a8d004cc
462 d3 4:777940761eba
464 d3 4:777940761eba
463 r1 0:a61bcde8c529
465 r1 0:a61bcde8c529
464 r2 7:00eebaf8d2e2
466 r2 7:00eebaf8d2e2
465
467
466 $ hg glog
468 $ hg glog
467 o 7:00eebaf8d2e2 split 3 r2
469 o 7:00eebaf8d2e2 split 3 r2
468 |
470 |
469 o 6:a09ad58faae3 split 2
471 o 6:a09ad58faae3 split 2
470 |
472 |
471 o 5:e704349bd21b split 1
473 o 5:e704349bd21b split 1
472 |
474 |
473 | * 4:777940761eba d3 d3
475 | * 4:777940761eba d3 d3
474 | |
476 | |
475 | @ 3:f4a0a8d004cc d2 d2
477 | @ 3:f4a0a8d004cc d2 d2
476 | |
478 | |
477 | * 2:b5c5ea414030 d1 d1
479 | * 2:b5c5ea414030 d1 d1
478 | |
480 | |
479 | x 1:1df0d5c5a3ab a2
481 | x 1:1df0d5c5a3ab a2
480 |/
482 |/
481 o 0:a61bcde8c529 a1 r1
483 o 0:a61bcde8c529 a1 r1
482
484
483 #endif
485 #endif
484
486
485 Split a non-head with obsoleted descendants
487 Split a non-head with obsoleted descendants
486
488
487 #if obsstore-on
489 #if obsstore-on
488 $ hg init $TESTTMP/e
490 $ hg init $TESTTMP/e
489 $ cd $TESTTMP/e
491 $ cd $TESTTMP/e
490 $ hg debugdrawdag <<'EOS'
492 $ hg debugdrawdag <<'EOS'
491 > H I J
493 > H I J
492 > | | |
494 > | | |
493 > F G1 G2 # amend: G1 -> G2
495 > F G1 G2 # amend: G1 -> G2
494 > | | / # prune: F
496 > | | / # prune: F
495 > C D E
497 > C D E
496 > \|/
498 > \|/
497 > B
499 > B
498 > |
500 > |
499 > A
501 > A
500 > EOS
502 > EOS
501 2 new orphan changesets
503 2 new orphan changesets
502 $ eval `hg tags -T '{tag}={node}\n'`
504 $ eval `hg tags -T '{tag}={node}\n'`
503 $ rm .hg/localtags
505 $ rm .hg/localtags
504 $ hg split $B --config experimental.evolution=createmarkers
506 $ hg split $B --config experimental.evolution=createmarkers
505 abort: split would leave orphaned changesets behind
507 abort: split would leave orphaned changesets behind
506 [255]
508 [255]
507 $ cat > $TESTTMP/messages <<EOF
509 $ cat > $TESTTMP/messages <<EOF
508 > Split B
510 > Split B
509 > EOF
511 > EOF
510 $ cat <<EOF | hg split $B
512 $ cat <<EOF | hg split $B
511 > y
513 > y
512 > y
514 > y
513 > EOF
515 > EOF
514 diff --git a/B b/B
516 diff --git a/B b/B
515 new file mode 100644
517 new file mode 100644
516 examine changes to 'B'? [Ynesfdaq?] y
518 examine changes to 'B'? [Ynesfdaq?] y
517
519
518 @@ -0,0 +1,1 @@
520 @@ -0,0 +1,1 @@
519 +B
521 +B
520 \ No newline at end of file
522 \ No newline at end of file
521 record this change to 'B'? [Ynesfdaq?] y
523 record this change to 'B'? [Ynesfdaq?] y
522
524
523 EDITOR: HG: Splitting 112478962961. Write commit message for the first split changeset.
525 EDITOR: HG: Splitting 112478962961. Write commit message for the first split changeset.
524 EDITOR: B
526 EDITOR: B
525 EDITOR:
527 EDITOR:
526 EDITOR:
528 EDITOR:
527 EDITOR: HG: Enter commit message. Lines beginning with 'HG:' are removed.
529 EDITOR: HG: Enter commit message. Lines beginning with 'HG:' are removed.
528 EDITOR: HG: Leave message empty to abort commit.
530 EDITOR: HG: Leave message empty to abort commit.
529 EDITOR: HG: --
531 EDITOR: HG: --
530 EDITOR: HG: user: test
532 EDITOR: HG: user: test
531 EDITOR: HG: branch 'default'
533 EDITOR: HG: branch 'default'
532 EDITOR: HG: added B
534 EDITOR: HG: added B
533 created new head
535 created new head
534 rebasing 2:26805aba1e60 "C"
536 rebasing 2:26805aba1e60 "C"
535 rebasing 3:be0ef73c17ad "D"
537 rebasing 3:be0ef73c17ad "D"
536 rebasing 4:49cb92066bfd "E"
538 rebasing 4:49cb92066bfd "E"
537 rebasing 7:97a6268cc7ef "G2"
539 rebasing 7:97a6268cc7ef "G2"
538 rebasing 10:e2f1e425c0db "J"
540 rebasing 10:e2f1e425c0db "J"
539 $ hg glog -r 'sort(all(), topo)'
541 $ hg glog -r 'sort(all(), topo)'
540 o 16:556c085f8b52 J
542 o 16:556c085f8b52 J
541 |
543 |
542 o 15:8761f6c9123f G2
544 o 15:8761f6c9123f G2
543 |
545 |
544 o 14:a7aeffe59b65 E
546 o 14:a7aeffe59b65 E
545 |
547 |
546 | o 13:e1e914ede9ab D
548 | o 13:e1e914ede9ab D
547 |/
549 |/
548 | o 12:01947e9b98aa C
550 | o 12:01947e9b98aa C
549 |/
551 |/
550 o 11:0947baa74d47 Split B
552 o 11:0947baa74d47 Split B
551 |
553 |
552 | * 9:88ede1d5ee13 I
554 | * 9:88ede1d5ee13 I
553 | |
555 | |
554 | x 6:af8cbf225b7b G1
556 | x 6:af8cbf225b7b G1
555 | |
557 | |
556 | x 3:be0ef73c17ad D
558 | x 3:be0ef73c17ad D
557 | |
559 | |
558 | | * 8:74863e5b5074 H
560 | | * 8:74863e5b5074 H
559 | | |
561 | | |
560 | | x 5:ee481a2a1e69 F
562 | | x 5:ee481a2a1e69 F
561 | | |
563 | | |
562 | | x 2:26805aba1e60 C
564 | | x 2:26805aba1e60 C
563 | |/
565 | |/
564 | x 1:112478962961 B
566 | x 1:112478962961 B
565 |/
567 |/
566 o 0:426bada5c675 A
568 o 0:426bada5c675 A
567
569
568 #endif
570 #endif
569
571
570 Preserve secret phase in split
572 Preserve secret phase in split
571
573
572 $ cp -R $TESTTMP/clean $TESTTMP/phases1
574 $ cp -R $TESTTMP/clean $TESTTMP/phases1
573 $ cd $TESTTMP/phases1
575 $ cd $TESTTMP/phases1
574 $ hg phase --secret -fr tip
576 $ hg phase --secret -fr tip
575 $ hg log -T '{short(node)} {phase}\n'
577 $ hg log -T '{short(node)} {phase}\n'
576 1df0d5c5a3ab secret
578 1df0d5c5a3ab secret
577 a61bcde8c529 draft
579 a61bcde8c529 draft
578 $ runsplit tip >/dev/null
580 $ runsplit tip >/dev/null
579 $ hg log -T '{short(node)} {phase}\n'
581 $ hg log -T '{short(node)} {phase}\n'
580 00eebaf8d2e2 secret
582 00eebaf8d2e2 secret
581 a09ad58faae3 secret
583 a09ad58faae3 secret
582 e704349bd21b secret
584 e704349bd21b secret
583 a61bcde8c529 draft
585 a61bcde8c529 draft
584
586
585 Do not move things to secret even if phases.new-commit=secret
587 Do not move things to secret even if phases.new-commit=secret
586
588
587 $ cp -R $TESTTMP/clean $TESTTMP/phases2
589 $ cp -R $TESTTMP/clean $TESTTMP/phases2
588 $ cd $TESTTMP/phases2
590 $ cd $TESTTMP/phases2
589 $ cat >> .hg/hgrc <<EOF
591 $ cat >> .hg/hgrc <<EOF
590 > [phases]
592 > [phases]
591 > new-commit=secret
593 > new-commit=secret
592 > EOF
594 > EOF
593 $ hg log -T '{short(node)} {phase}\n'
595 $ hg log -T '{short(node)} {phase}\n'
594 1df0d5c5a3ab draft
596 1df0d5c5a3ab draft
595 a61bcde8c529 draft
597 a61bcde8c529 draft
596 $ runsplit tip >/dev/null
598 $ runsplit tip >/dev/null
597 $ hg log -T '{short(node)} {phase}\n'
599 $ hg log -T '{short(node)} {phase}\n'
598 00eebaf8d2e2 draft
600 00eebaf8d2e2 draft
599 a09ad58faae3 draft
601 a09ad58faae3 draft
600 e704349bd21b draft
602 e704349bd21b draft
601 a61bcde8c529 draft
603 a61bcde8c529 draft
602
604
603 `hg split` with ignoreblanklines=1 does not infinite loop
605 `hg split` with ignoreblanklines=1 does not infinite loop
604
606
605 $ mkdir $TESTTMP/f
607 $ mkdir $TESTTMP/f
606 $ hg init $TESTTMP/f/a
608 $ hg init $TESTTMP/f/a
607 $ cd $TESTTMP/f/a
609 $ cd $TESTTMP/f/a
608 $ printf '1\n2\n3\n4\n5\n' > foo
610 $ printf '1\n2\n3\n4\n5\n' > foo
609 $ cp foo bar
611 $ cp foo bar
610 $ hg ci -qAm initial
612 $ hg ci -qAm initial
611 $ printf '1\n\n2\n3\ntest\n4\n5\n' > bar
613 $ printf '1\n\n2\n3\ntest\n4\n5\n' > bar
612 $ printf '1\n2\n3\ntest\n4\n5\n' > foo
614 $ printf '1\n2\n3\ntest\n4\n5\n' > foo
613 $ hg ci -qm splitme
615 $ hg ci -qm splitme
614 $ cat > $TESTTMP/messages <<EOF
616 $ cat > $TESTTMP/messages <<EOF
615 > split 1
617 > split 1
616 > --
618 > --
617 > split 2
619 > split 2
618 > EOF
620 > EOF
619 $ printf 'f\nn\nf\n' | hg --config extensions.split= --config diff.ignoreblanklines=1 split
621 $ printf 'f\nn\nf\n' | hg --config extensions.split= --config diff.ignoreblanklines=1 split
620 diff --git a/bar b/bar
622 diff --git a/bar b/bar
621 2 hunks, 2 lines changed
623 2 hunks, 2 lines changed
622 examine changes to 'bar'? [Ynesfdaq?] f
624 examine changes to 'bar'? [Ynesfdaq?] f
623
625
624 diff --git a/foo b/foo
626 diff --git a/foo b/foo
625 1 hunks, 1 lines changed
627 1 hunks, 1 lines changed
626 examine changes to 'foo'? [Ynesfdaq?] n
628 examine changes to 'foo'? [Ynesfdaq?] n
627
629
628 EDITOR: HG: Splitting dd3c45017cbf. Write commit message for the first split changeset.
630 EDITOR: HG: Splitting dd3c45017cbf. Write commit message for the first split changeset.
629 EDITOR: splitme
631 EDITOR: splitme
630 EDITOR:
632 EDITOR:
631 EDITOR:
633 EDITOR:
632 EDITOR: HG: Enter commit message. Lines beginning with 'HG:' are removed.
634 EDITOR: HG: Enter commit message. Lines beginning with 'HG:' are removed.
633 EDITOR: HG: Leave message empty to abort commit.
635 EDITOR: HG: Leave message empty to abort commit.
634 EDITOR: HG: --
636 EDITOR: HG: --
635 EDITOR: HG: user: test
637 EDITOR: HG: user: test
636 EDITOR: HG: branch 'default'
638 EDITOR: HG: branch 'default'
637 EDITOR: HG: changed bar
639 EDITOR: HG: changed bar
638 created new head
640 created new head
639 diff --git a/foo b/foo
641 diff --git a/foo b/foo
640 1 hunks, 1 lines changed
642 1 hunks, 1 lines changed
641 examine changes to 'foo'? [Ynesfdaq?] f
643 examine changes to 'foo'? [Ynesfdaq?] f
642
644
643 EDITOR: HG: Splitting dd3c45017cbf. So far it has been split into:
645 EDITOR: HG: Splitting dd3c45017cbf. So far it has been split into:
644 EDITOR: HG: - f205aea1c624: split 1
646 EDITOR: HG: - f205aea1c624: split 1
645 EDITOR: HG: Write commit message for the next split changeset.
647 EDITOR: HG: Write commit message for the next split changeset.
646 EDITOR: splitme
648 EDITOR: splitme
647 EDITOR:
649 EDITOR:
648 EDITOR:
650 EDITOR:
649 EDITOR: HG: Enter commit message. Lines beginning with 'HG:' are removed.
651 EDITOR: HG: Enter commit message. Lines beginning with 'HG:' are removed.
650 EDITOR: HG: Leave message empty to abort commit.
652 EDITOR: HG: Leave message empty to abort commit.
651 EDITOR: HG: --
653 EDITOR: HG: --
652 EDITOR: HG: user: test
654 EDITOR: HG: user: test
653 EDITOR: HG: branch 'default'
655 EDITOR: HG: branch 'default'
654 EDITOR: HG: changed foo
656 EDITOR: HG: changed foo
655 saved backup bundle to $TESTTMP/f/a/.hg/strip-backup/dd3c45017cbf-463441b5-split.hg (obsstore-off !)
657 saved backup bundle to $TESTTMP/f/a/.hg/strip-backup/dd3c45017cbf-463441b5-split.hg (obsstore-off !)
656
658
657 Let's try that again, with a slightly different set of patches, to ensure that
659 Let's try that again, with a slightly different set of patches, to ensure that
658 the ignoreblanklines thing isn't somehow position dependent.
660 the ignoreblanklines thing isn't somehow position dependent.
659
661
660 $ hg init $TESTTMP/f/b
662 $ hg init $TESTTMP/f/b
661 $ cd $TESTTMP/f/b
663 $ cd $TESTTMP/f/b
662 $ printf '1\n2\n3\n4\n5\n' > foo
664 $ printf '1\n2\n3\n4\n5\n' > foo
663 $ cp foo bar
665 $ cp foo bar
664 $ hg ci -qAm initial
666 $ hg ci -qAm initial
665 $ printf '1\n2\n3\ntest\n4\n5\n' > bar
667 $ printf '1\n2\n3\ntest\n4\n5\n' > bar
666 $ printf '1\n2\n3\ntest\n4\n\n5\n' > foo
668 $ printf '1\n2\n3\ntest\n4\n\n5\n' > foo
667 $ hg ci -qm splitme
669 $ hg ci -qm splitme
668 $ cat > $TESTTMP/messages <<EOF
670 $ cat > $TESTTMP/messages <<EOF
669 > split 1
671 > split 1
670 > --
672 > --
671 > split 2
673 > split 2
672 > EOF
674 > EOF
673 $ printf 'f\nn\nf\n' | hg --config extensions.split= --config diff.ignoreblanklines=1 split
675 $ printf 'f\nn\nf\n' | hg --config extensions.split= --config diff.ignoreblanklines=1 split
674 diff --git a/bar b/bar
676 diff --git a/bar b/bar
675 1 hunks, 1 lines changed
677 1 hunks, 1 lines changed
676 examine changes to 'bar'? [Ynesfdaq?] f
678 examine changes to 'bar'? [Ynesfdaq?] f
677
679
678 diff --git a/foo b/foo
680 diff --git a/foo b/foo
679 2 hunks, 2 lines changed
681 2 hunks, 2 lines changed
680 examine changes to 'foo'? [Ynesfdaq?] n
682 examine changes to 'foo'? [Ynesfdaq?] n
681
683
682 EDITOR: HG: Splitting 904c80b40a4a. Write commit message for the first split changeset.
684 EDITOR: HG: Splitting 904c80b40a4a. Write commit message for the first split changeset.
683 EDITOR: splitme
685 EDITOR: splitme
684 EDITOR:
686 EDITOR:
685 EDITOR:
687 EDITOR:
686 EDITOR: HG: Enter commit message. Lines beginning with 'HG:' are removed.
688 EDITOR: HG: Enter commit message. Lines beginning with 'HG:' are removed.
687 EDITOR: HG: Leave message empty to abort commit.
689 EDITOR: HG: Leave message empty to abort commit.
688 EDITOR: HG: --
690 EDITOR: HG: --
689 EDITOR: HG: user: test
691 EDITOR: HG: user: test
690 EDITOR: HG: branch 'default'
692 EDITOR: HG: branch 'default'
691 EDITOR: HG: changed bar
693 EDITOR: HG: changed bar
692 created new head
694 created new head
693 diff --git a/foo b/foo
695 diff --git a/foo b/foo
694 2 hunks, 2 lines changed
696 2 hunks, 2 lines changed
695 examine changes to 'foo'? [Ynesfdaq?] f
697 examine changes to 'foo'? [Ynesfdaq?] f
696
698
697 EDITOR: HG: Splitting 904c80b40a4a. So far it has been split into:
699 EDITOR: HG: Splitting 904c80b40a4a. So far it has been split into:
698 EDITOR: HG: - ffecf40fa954: split 1
700 EDITOR: HG: - ffecf40fa954: split 1
699 EDITOR: HG: Write commit message for the next split changeset.
701 EDITOR: HG: Write commit message for the next split changeset.
700 EDITOR: splitme
702 EDITOR: splitme
701 EDITOR:
703 EDITOR:
702 EDITOR:
704 EDITOR:
703 EDITOR: HG: Enter commit message. Lines beginning with 'HG:' are removed.
705 EDITOR: HG: Enter commit message. Lines beginning with 'HG:' are removed.
704 EDITOR: HG: Leave message empty to abort commit.
706 EDITOR: HG: Leave message empty to abort commit.
705 EDITOR: HG: --
707 EDITOR: HG: --
706 EDITOR: HG: user: test
708 EDITOR: HG: user: test
707 EDITOR: HG: branch 'default'
709 EDITOR: HG: branch 'default'
708 EDITOR: HG: changed foo
710 EDITOR: HG: changed foo
709 saved backup bundle to $TESTTMP/f/b/.hg/strip-backup/904c80b40a4a-47fb907f-split.hg (obsstore-off !)
711 saved backup bundle to $TESTTMP/f/b/.hg/strip-backup/904c80b40a4a-47fb907f-split.hg (obsstore-off !)
General Comments 0
You need to be logged in to leave comments. Login now