##// END OF EJS Templates
record: change wording of initial per-file prompt
Bryan O'Sullivan -
r5285:3ef19023 default
parent child Browse files
Show More
@@ -1,415 +1,415 b''
1 # record.py
1 # record.py
2 #
2 #
3 # Copyright 2007 Bryan O'Sullivan <bos@serpentine.com>
3 # Copyright 2007 Bryan O'Sullivan <bos@serpentine.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of
5 # This software may be used and distributed according to the terms of
6 # the GNU General Public License, incorporated herein by reference.
6 # the GNU General Public License, incorporated herein by reference.
7
7
8 '''interactive change selection during commit'''
8 '''interactive change selection during commit'''
9
9
10 from mercurial.i18n import _
10 from mercurial.i18n import _
11 from mercurial import cmdutil, commands, cmdutil, hg, mdiff, patch, revlog
11 from mercurial import cmdutil, commands, cmdutil, hg, mdiff, patch, revlog
12 from mercurial import util
12 from mercurial import util
13 import copy, cStringIO, errno, operator, os, re, shutil, tempfile
13 import copy, cStringIO, errno, operator, os, re, shutil, tempfile
14
14
15 lines_re = re.compile(r'@@ -(\d+),(\d+) \+(\d+),(\d+) @@\s*(.*)')
15 lines_re = re.compile(r'@@ -(\d+),(\d+) \+(\d+),(\d+) @@\s*(.*)')
16
16
17 def scanpatch(fp):
17 def scanpatch(fp):
18 lr = patch.linereader(fp)
18 lr = patch.linereader(fp)
19
19
20 def scanwhile(first, p):
20 def scanwhile(first, p):
21 lines = [first]
21 lines = [first]
22 while True:
22 while True:
23 line = lr.readline()
23 line = lr.readline()
24 if not line:
24 if not line:
25 break
25 break
26 if p(line):
26 if p(line):
27 lines.append(line)
27 lines.append(line)
28 else:
28 else:
29 lr.push(line)
29 lr.push(line)
30 break
30 break
31 return lines
31 return lines
32
32
33 while True:
33 while True:
34 line = lr.readline()
34 line = lr.readline()
35 if not line:
35 if not line:
36 break
36 break
37 if line.startswith('diff --git a/'):
37 if line.startswith('diff --git a/'):
38 def notheader(line):
38 def notheader(line):
39 s = line.split(None, 1)
39 s = line.split(None, 1)
40 return not s or s[0] not in ('---', 'diff')
40 return not s or s[0] not in ('---', 'diff')
41 header = scanwhile(line, notheader)
41 header = scanwhile(line, notheader)
42 fromfile = lr.readline()
42 fromfile = lr.readline()
43 if fromfile.startswith('---'):
43 if fromfile.startswith('---'):
44 tofile = lr.readline()
44 tofile = lr.readline()
45 header += [fromfile, tofile]
45 header += [fromfile, tofile]
46 else:
46 else:
47 lr.push(fromfile)
47 lr.push(fromfile)
48 yield 'file', header
48 yield 'file', header
49 elif line[0] == ' ':
49 elif line[0] == ' ':
50 yield 'context', scanwhile(line, lambda l: l[0] in ' \\')
50 yield 'context', scanwhile(line, lambda l: l[0] in ' \\')
51 elif line[0] in '-+':
51 elif line[0] in '-+':
52 yield 'hunk', scanwhile(line, lambda l: l[0] in '-+\\')
52 yield 'hunk', scanwhile(line, lambda l: l[0] in '-+\\')
53 else:
53 else:
54 m = lines_re.match(line)
54 m = lines_re.match(line)
55 if m:
55 if m:
56 yield 'range', m.groups()
56 yield 'range', m.groups()
57 else:
57 else:
58 raise patch.PatchError('unknown patch content: %r' % line)
58 raise patch.PatchError('unknown patch content: %r' % line)
59
59
60 class header(object):
60 class header(object):
61 diff_re = re.compile('diff --git a/(.*) b/(.*)$')
61 diff_re = re.compile('diff --git a/(.*) b/(.*)$')
62 allhunks_re = re.compile('(?:index|new file|deleted file) ')
62 allhunks_re = re.compile('(?:index|new file|deleted file) ')
63 pretty_re = re.compile('(?:new file|deleted file) ')
63 pretty_re = re.compile('(?:new file|deleted file) ')
64 special_re = re.compile('(?:index|new|deleted|copy|rename) ')
64 special_re = re.compile('(?:index|new|deleted|copy|rename) ')
65
65
66 def __init__(self, header):
66 def __init__(self, header):
67 self.header = header
67 self.header = header
68 self.hunks = []
68 self.hunks = []
69
69
70 def binary(self):
70 def binary(self):
71 for h in self.header:
71 for h in self.header:
72 if h.startswith('index '):
72 if h.startswith('index '):
73 return True
73 return True
74
74
75 def pretty(self, fp):
75 def pretty(self, fp):
76 for h in self.header:
76 for h in self.header:
77 if h.startswith('index '):
77 if h.startswith('index '):
78 fp.write(_('this modifies a binary file (all or nothing)\n'))
78 fp.write(_('this modifies a binary file (all or nothing)\n'))
79 break
79 break
80 if self.pretty_re.match(h):
80 if self.pretty_re.match(h):
81 fp.write(h)
81 fp.write(h)
82 if self.binary():
82 if self.binary():
83 fp.write(_('this is a binary file\n'))
83 fp.write(_('this is a binary file\n'))
84 break
84 break
85 if h.startswith('---'):
85 if h.startswith('---'):
86 fp.write(_('%d hunks, %d lines changed\n') %
86 fp.write(_('%d hunks, %d lines changed\n') %
87 (len(self.hunks),
87 (len(self.hunks),
88 sum([h.added + h.removed for h in self.hunks])))
88 sum([h.added + h.removed for h in self.hunks])))
89 break
89 break
90 fp.write(h)
90 fp.write(h)
91
91
92 def write(self, fp):
92 def write(self, fp):
93 fp.write(''.join(self.header))
93 fp.write(''.join(self.header))
94
94
95 def allhunks(self):
95 def allhunks(self):
96 for h in self.header:
96 for h in self.header:
97 if self.allhunks_re.match(h):
97 if self.allhunks_re.match(h):
98 return True
98 return True
99
99
100 def files(self):
100 def files(self):
101 fromfile, tofile = self.diff_re.match(self.header[0]).groups()
101 fromfile, tofile = self.diff_re.match(self.header[0]).groups()
102 if fromfile == tofile:
102 if fromfile == tofile:
103 return [fromfile]
103 return [fromfile]
104 return [fromfile, tofile]
104 return [fromfile, tofile]
105
105
106 def filename(self):
106 def filename(self):
107 return self.files()[-1]
107 return self.files()[-1]
108
108
109 def __repr__(self):
109 def __repr__(self):
110 return '<header %s>' % (' '.join(map(repr, self.files())))
110 return '<header %s>' % (' '.join(map(repr, self.files())))
111
111
112 def special(self):
112 def special(self):
113 for h in self.header:
113 for h in self.header:
114 if self.special_re.match(h):
114 if self.special_re.match(h):
115 return True
115 return True
116
116
117 def countchanges(hunk):
117 def countchanges(hunk):
118 add = len([h for h in hunk if h[0] == '+'])
118 add = len([h for h in hunk if h[0] == '+'])
119 rem = len([h for h in hunk if h[0] == '-'])
119 rem = len([h for h in hunk if h[0] == '-'])
120 return add, rem
120 return add, rem
121
121
122 class hunk(object):
122 class hunk(object):
123 maxcontext = 3
123 maxcontext = 3
124
124
125 def __init__(self, header, fromline, toline, proc, before, hunk, after):
125 def __init__(self, header, fromline, toline, proc, before, hunk, after):
126 def trimcontext(number, lines):
126 def trimcontext(number, lines):
127 delta = len(lines) - self.maxcontext
127 delta = len(lines) - self.maxcontext
128 if False and delta > 0:
128 if False and delta > 0:
129 return number + delta, lines[:self.maxcontext]
129 return number + delta, lines[:self.maxcontext]
130 return number, lines
130 return number, lines
131
131
132 self.header = header
132 self.header = header
133 self.fromline, self.before = trimcontext(fromline, before)
133 self.fromline, self.before = trimcontext(fromline, before)
134 self.toline, self.after = trimcontext(toline, after)
134 self.toline, self.after = trimcontext(toline, after)
135 self.proc = proc
135 self.proc = proc
136 self.hunk = hunk
136 self.hunk = hunk
137 self.added, self.removed = countchanges(self.hunk)
137 self.added, self.removed = countchanges(self.hunk)
138
138
139 def write(self, fp):
139 def write(self, fp):
140 delta = len(self.before) + len(self.after)
140 delta = len(self.before) + len(self.after)
141 fromlen = delta + self.removed
141 fromlen = delta + self.removed
142 tolen = delta + self.added
142 tolen = delta + self.added
143 fp.write('@@ -%d,%d +%d,%d @@%s\n' %
143 fp.write('@@ -%d,%d +%d,%d @@%s\n' %
144 (self.fromline, fromlen, self.toline, tolen,
144 (self.fromline, fromlen, self.toline, tolen,
145 self.proc and (' ' + self.proc)))
145 self.proc and (' ' + self.proc)))
146 fp.write(''.join(self.before + self.hunk + self.after))
146 fp.write(''.join(self.before + self.hunk + self.after))
147
147
148 pretty = write
148 pretty = write
149
149
150 def filename(self):
150 def filename(self):
151 return self.header.filename()
151 return self.header.filename()
152
152
153 def __repr__(self):
153 def __repr__(self):
154 return '<hunk %r@%d>' % (self.filename(), self.fromline)
154 return '<hunk %r@%d>' % (self.filename(), self.fromline)
155
155
156 def parsepatch(fp):
156 def parsepatch(fp):
157 class parser(object):
157 class parser(object):
158 def __init__(self):
158 def __init__(self):
159 self.fromline = 0
159 self.fromline = 0
160 self.toline = 0
160 self.toline = 0
161 self.proc = ''
161 self.proc = ''
162 self.header = None
162 self.header = None
163 self.context = []
163 self.context = []
164 self.before = []
164 self.before = []
165 self.hunk = []
165 self.hunk = []
166 self.stream = []
166 self.stream = []
167
167
168 def addrange(self, (fromstart, fromend, tostart, toend, proc)):
168 def addrange(self, (fromstart, fromend, tostart, toend, proc)):
169 self.fromline = int(fromstart)
169 self.fromline = int(fromstart)
170 self.toline = int(tostart)
170 self.toline = int(tostart)
171 self.proc = proc
171 self.proc = proc
172
172
173 def addcontext(self, context):
173 def addcontext(self, context):
174 if self.hunk:
174 if self.hunk:
175 h = hunk(self.header, self.fromline, self.toline, self.proc,
175 h = hunk(self.header, self.fromline, self.toline, self.proc,
176 self.before, self.hunk, context)
176 self.before, self.hunk, context)
177 self.header.hunks.append(h)
177 self.header.hunks.append(h)
178 self.stream.append(h)
178 self.stream.append(h)
179 self.fromline += len(self.before) + h.removed
179 self.fromline += len(self.before) + h.removed
180 self.toline += len(self.before) + h.added
180 self.toline += len(self.before) + h.added
181 self.before = []
181 self.before = []
182 self.hunk = []
182 self.hunk = []
183 self.proc = ''
183 self.proc = ''
184 self.context = context
184 self.context = context
185
185
186 def addhunk(self, hunk):
186 def addhunk(self, hunk):
187 if self.context:
187 if self.context:
188 self.before = self.context
188 self.before = self.context
189 self.context = []
189 self.context = []
190 self.hunk = data
190 self.hunk = data
191
191
192 def newfile(self, hdr):
192 def newfile(self, hdr):
193 self.addcontext([])
193 self.addcontext([])
194 h = header(hdr)
194 h = header(hdr)
195 self.stream.append(h)
195 self.stream.append(h)
196 self.header = h
196 self.header = h
197
197
198 def finished(self):
198 def finished(self):
199 self.addcontext([])
199 self.addcontext([])
200 return self.stream
200 return self.stream
201
201
202 transitions = {
202 transitions = {
203 'file': {'context': addcontext,
203 'file': {'context': addcontext,
204 'file': newfile,
204 'file': newfile,
205 'hunk': addhunk,
205 'hunk': addhunk,
206 'range': addrange},
206 'range': addrange},
207 'context': {'file': newfile,
207 'context': {'file': newfile,
208 'hunk': addhunk,
208 'hunk': addhunk,
209 'range': addrange},
209 'range': addrange},
210 'hunk': {'context': addcontext,
210 'hunk': {'context': addcontext,
211 'file': newfile,
211 'file': newfile,
212 'range': addrange},
212 'range': addrange},
213 'range': {'context': addcontext,
213 'range': {'context': addcontext,
214 'hunk': addhunk},
214 'hunk': addhunk},
215 }
215 }
216
216
217 p = parser()
217 p = parser()
218
218
219 state = 'context'
219 state = 'context'
220 for newstate, data in scanpatch(fp):
220 for newstate, data in scanpatch(fp):
221 try:
221 try:
222 p.transitions[state][newstate](p, data)
222 p.transitions[state][newstate](p, data)
223 except KeyError:
223 except KeyError:
224 raise patch.PatchError('unhandled transition: %s -> %s' %
224 raise patch.PatchError('unhandled transition: %s -> %s' %
225 (state, newstate))
225 (state, newstate))
226 state = newstate
226 state = newstate
227 return p.finished()
227 return p.finished()
228
228
229 def filterpatch(ui, chunks):
229 def filterpatch(ui, chunks):
230 chunks = list(chunks)
230 chunks = list(chunks)
231 chunks.reverse()
231 chunks.reverse()
232 seen = {}
232 seen = {}
233 def consumefile():
233 def consumefile():
234 consumed = []
234 consumed = []
235 while chunks:
235 while chunks:
236 if isinstance(chunks[-1], header):
236 if isinstance(chunks[-1], header):
237 break
237 break
238 else:
238 else:
239 consumed.append(chunks.pop())
239 consumed.append(chunks.pop())
240 return consumed
240 return consumed
241 resp_all = [None]
241 resp_all = [None]
242 resp_file = [None]
242 resp_file = [None]
243 applied = {}
243 applied = {}
244 def prompt(query):
244 def prompt(query):
245 if resp_all[0] is not None:
245 if resp_all[0] is not None:
246 return resp_all[0]
246 return resp_all[0]
247 if resp_file[0] is not None:
247 if resp_file[0] is not None:
248 return resp_file[0]
248 return resp_file[0]
249 while True:
249 while True:
250 r = (ui.prompt(query + _(' [Ynsfdaq?] '), '[Ynsfdaq?]?$',
250 r = (ui.prompt(query + _(' [Ynsfdaq?] '), '[Ynsfdaq?]?$',
251 matchflags=re.I) or 'y').lower()
251 matchflags=re.I) or 'y').lower()
252 if r == '?':
252 if r == '?':
253 c = record.__doc__.find('y - record this change')
253 c = record.__doc__.find('y - record this change')
254 for l in record.__doc__[c:].splitlines():
254 for l in record.__doc__[c:].splitlines():
255 if l: ui.write(_(l.strip()), '\n')
255 if l: ui.write(_(l.strip()), '\n')
256 continue
256 continue
257 elif r == 's':
257 elif r == 's':
258 r = resp_file[0] = 'n'
258 r = resp_file[0] = 'n'
259 elif r == 'f':
259 elif r == 'f':
260 r = resp_file[0] = 'y'
260 r = resp_file[0] = 'y'
261 elif r == 'd':
261 elif r == 'd':
262 r = resp_all[0] = 'n'
262 r = resp_all[0] = 'n'
263 elif r == 'a':
263 elif r == 'a':
264 r = resp_all[0] = 'y'
264 r = resp_all[0] = 'y'
265 elif r == 'q':
265 elif r == 'q':
266 raise util.Abort(_('user quit'))
266 raise util.Abort(_('user quit'))
267 return r
267 return r
268 while chunks:
268 while chunks:
269 chunk = chunks.pop()
269 chunk = chunks.pop()
270 if isinstance(chunk, header):
270 if isinstance(chunk, header):
271 resp_file = [None]
271 resp_file = [None]
272 fixoffset = 0
272 fixoffset = 0
273 hdr = ''.join(chunk.header)
273 hdr = ''.join(chunk.header)
274 if hdr in seen:
274 if hdr in seen:
275 consumefile()
275 consumefile()
276 continue
276 continue
277 seen[hdr] = True
277 seen[hdr] = True
278 if resp_all[0] is None:
278 if resp_all[0] is None:
279 chunk.pretty(ui)
279 chunk.pretty(ui)
280 r = prompt(_('record changes to %s?') %
280 r = prompt(_('examine changes to %s?') %
281 _(' and ').join(map(repr, chunk.files())))
281 _(' and ').join(map(repr, chunk.files())))
282 if r == 'y':
282 if r == 'y':
283 applied[chunk.filename()] = [chunk]
283 applied[chunk.filename()] = [chunk]
284 if chunk.allhunks():
284 if chunk.allhunks():
285 applied[chunk.filename()] += consumefile()
285 applied[chunk.filename()] += consumefile()
286 else:
286 else:
287 consumefile()
287 consumefile()
288 else:
288 else:
289 if resp_file[0] is None and resp_all[0] is None:
289 if resp_file[0] is None and resp_all[0] is None:
290 chunk.pretty(ui)
290 chunk.pretty(ui)
291 r = prompt(_('record this change to %r?') %
291 r = prompt(_('record this change to %r?') %
292 chunk.filename())
292 chunk.filename())
293 if r == 'y':
293 if r == 'y':
294 if fixoffset:
294 if fixoffset:
295 chunk = copy.copy(chunk)
295 chunk = copy.copy(chunk)
296 chunk.toline += fixoffset
296 chunk.toline += fixoffset
297 applied[chunk.filename()].append(chunk)
297 applied[chunk.filename()].append(chunk)
298 else:
298 else:
299 fixoffset += chunk.removed - chunk.added
299 fixoffset += chunk.removed - chunk.added
300 return reduce(operator.add, [h for h in applied.itervalues()
300 return reduce(operator.add, [h for h in applied.itervalues()
301 if h[0].special() or len(h) > 1], [])
301 if h[0].special() or len(h) > 1], [])
302
302
303 def record(ui, repo, *pats, **opts):
303 def record(ui, repo, *pats, **opts):
304 '''interactively select changes to commit
304 '''interactively select changes to commit
305
305
306 If a list of files is omitted, all changes reported by "hg status"
306 If a list of files is omitted, all changes reported by "hg status"
307 will be candidates for recording.
307 will be candidates for recording.
308
308
309 You will be prompted for whether to record changes to each
309 You will be prompted for whether to record changes to each
310 modified file, and for files with multiple changes, for each
310 modified file, and for files with multiple changes, for each
311 change to use. For each query, the following responses are
311 change to use. For each query, the following responses are
312 possible:
312 possible:
313
313
314 y - record this change
314 y - record this change
315 n - skip this change
315 n - skip this change
316
316
317 s - skip remaining changes to this file
317 s - skip remaining changes to this file
318 f - record remaining changes to this file
318 f - record remaining changes to this file
319
319
320 d - done, skip remaining changes and files
320 d - done, skip remaining changes and files
321 a - record all changes to all remaining files
321 a - record all changes to all remaining files
322 q - quit, recording no changes
322 q - quit, recording no changes
323
323
324 ? - display help'''
324 ? - display help'''
325
325
326 if not ui.interactive:
326 if not ui.interactive:
327 raise util.Abort(_('running non-interactively, use commit instead'))
327 raise util.Abort(_('running non-interactively, use commit instead'))
328
328
329 def recordfunc(ui, repo, files, message, match, opts):
329 def recordfunc(ui, repo, files, message, match, opts):
330 if files:
330 if files:
331 changes = None
331 changes = None
332 else:
332 else:
333 changes = repo.status(files=files, match=match)[:5]
333 changes = repo.status(files=files, match=match)[:5]
334 modified, added, removed = changes[:3]
334 modified, added, removed = changes[:3]
335 files = modified + added + removed
335 files = modified + added + removed
336 diffopts = mdiff.diffopts(git=True, nodates=True)
336 diffopts = mdiff.diffopts(git=True, nodates=True)
337 fp = cStringIO.StringIO()
337 fp = cStringIO.StringIO()
338 patch.diff(repo, repo.dirstate.parents()[0], files=files,
338 patch.diff(repo, repo.dirstate.parents()[0], files=files,
339 match=match, changes=changes, opts=diffopts, fp=fp)
339 match=match, changes=changes, opts=diffopts, fp=fp)
340 fp.seek(0)
340 fp.seek(0)
341
341
342 chunks = filterpatch(ui, parsepatch(fp))
342 chunks = filterpatch(ui, parsepatch(fp))
343 del fp
343 del fp
344
344
345 contenders = {}
345 contenders = {}
346 for h in chunks:
346 for h in chunks:
347 try: contenders.update(dict.fromkeys(h.files()))
347 try: contenders.update(dict.fromkeys(h.files()))
348 except AttributeError: pass
348 except AttributeError: pass
349
349
350 newfiles = [f for f in files if f in contenders]
350 newfiles = [f for f in files if f in contenders]
351
351
352 if not newfiles:
352 if not newfiles:
353 ui.status(_('no changes to record\n'))
353 ui.status(_('no changes to record\n'))
354 return 0
354 return 0
355
355
356 if changes is None:
356 if changes is None:
357 changes = repo.status(files=newfiles, match=match)[:5]
357 changes = repo.status(files=newfiles, match=match)[:5]
358 modified = dict.fromkeys(changes[0])
358 modified = dict.fromkeys(changes[0])
359
359
360 backups = {}
360 backups = {}
361 backupdir = repo.join('record-backups')
361 backupdir = repo.join('record-backups')
362 try:
362 try:
363 os.mkdir(backupdir)
363 os.mkdir(backupdir)
364 except OSError, err:
364 except OSError, err:
365 if err.errno != errno.EEXIST:
365 if err.errno != errno.EEXIST:
366 raise
366 raise
367 try:
367 try:
368 for f in newfiles:
368 for f in newfiles:
369 if f not in modified:
369 if f not in modified:
370 continue
370 continue
371 fd, tmpname = tempfile.mkstemp(prefix=f.replace('/', '_')+'.',
371 fd, tmpname = tempfile.mkstemp(prefix=f.replace('/', '_')+'.',
372 dir=backupdir)
372 dir=backupdir)
373 os.close(fd)
373 os.close(fd)
374 ui.debug('backup %r as %r\n' % (f, tmpname))
374 ui.debug('backup %r as %r\n' % (f, tmpname))
375 util.copyfile(repo.wjoin(f), tmpname)
375 util.copyfile(repo.wjoin(f), tmpname)
376 backups[f] = tmpname
376 backups[f] = tmpname
377
377
378 fp = cStringIO.StringIO()
378 fp = cStringIO.StringIO()
379 for c in chunks:
379 for c in chunks:
380 if c.filename() in backups:
380 if c.filename() in backups:
381 c.write(fp)
381 c.write(fp)
382 dopatch = fp.tell()
382 dopatch = fp.tell()
383 fp.seek(0)
383 fp.seek(0)
384
384
385 if backups:
385 if backups:
386 hg.revert(repo, repo.dirstate.parents()[0], backups.has_key)
386 hg.revert(repo, repo.dirstate.parents()[0], backups.has_key)
387
387
388 if dopatch:
388 if dopatch:
389 ui.debug('applying patch\n')
389 ui.debug('applying patch\n')
390 ui.debug(fp.getvalue())
390 ui.debug(fp.getvalue())
391 patch.internalpatch(fp, ui, 1, repo.root)
391 patch.internalpatch(fp, ui, 1, repo.root)
392 del fp
392 del fp
393
393
394 repo.commit(newfiles, message, opts['user'], opts['date'], match,
394 repo.commit(newfiles, message, opts['user'], opts['date'], match,
395 force_editor=opts.get('force_editor'))
395 force_editor=opts.get('force_editor'))
396 return 0
396 return 0
397 finally:
397 finally:
398 try:
398 try:
399 for realname, tmpname in backups.iteritems():
399 for realname, tmpname in backups.iteritems():
400 ui.debug('restoring %r to %r\n' % (tmpname, realname))
400 ui.debug('restoring %r to %r\n' % (tmpname, realname))
401 util.copyfile(tmpname, repo.wjoin(realname))
401 util.copyfile(tmpname, repo.wjoin(realname))
402 os.unlink(tmpname)
402 os.unlink(tmpname)
403 os.rmdir(backupdir)
403 os.rmdir(backupdir)
404 except OSError:
404 except OSError:
405 pass
405 pass
406 return cmdutil.commit(ui, repo, recordfunc, pats, opts)
406 return cmdutil.commit(ui, repo, recordfunc, pats, opts)
407
407
408 cmdtable = {
408 cmdtable = {
409 "record":
409 "record":
410 (record,
410 (record,
411 [('A', 'addremove', None,
411 [('A', 'addremove', None,
412 _('mark new/missing files as added/removed before committing')),
412 _('mark new/missing files as added/removed before committing')),
413 ] + commands.walkopts + commands.commitopts + commands.commitopts2,
413 ] + commands.walkopts + commands.commitopts + commands.commitopts2,
414 _('hg record [OPTION]... [FILE]...')),
414 _('hg record [OPTION]... [FILE]...')),
415 }
415 }
General Comments 0
You need to be logged in to leave comments. Login now