##// END OF EJS Templates
commands: document the layering violation in `manifest --all`...
Gregory Szorc -
r37455:814e080a default
parent child Browse files
Show More
@@ -1,5638 +1,5640 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for 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 difflib
10 import difflib
11 import errno
11 import errno
12 import os
12 import os
13 import re
13 import re
14 import sys
14 import sys
15
15
16 from .i18n import _
16 from .i18n import _
17 from .node import (
17 from .node import (
18 hex,
18 hex,
19 nullid,
19 nullid,
20 nullrev,
20 nullrev,
21 short,
21 short,
22 )
22 )
23 from . import (
23 from . import (
24 archival,
24 archival,
25 bookmarks,
25 bookmarks,
26 bundle2,
26 bundle2,
27 changegroup,
27 changegroup,
28 cmdutil,
28 cmdutil,
29 copies,
29 copies,
30 debugcommands as debugcommandsmod,
30 debugcommands as debugcommandsmod,
31 destutil,
31 destutil,
32 dirstateguard,
32 dirstateguard,
33 discovery,
33 discovery,
34 encoding,
34 encoding,
35 error,
35 error,
36 exchange,
36 exchange,
37 extensions,
37 extensions,
38 formatter,
38 formatter,
39 graphmod,
39 graphmod,
40 hbisect,
40 hbisect,
41 help,
41 help,
42 hg,
42 hg,
43 lock as lockmod,
43 lock as lockmod,
44 logcmdutil,
44 logcmdutil,
45 merge as mergemod,
45 merge as mergemod,
46 obsolete,
46 obsolete,
47 obsutil,
47 obsutil,
48 patch,
48 patch,
49 phases,
49 phases,
50 pycompat,
50 pycompat,
51 rcutil,
51 rcutil,
52 registrar,
52 registrar,
53 revsetlang,
53 revsetlang,
54 rewriteutil,
54 rewriteutil,
55 scmutil,
55 scmutil,
56 server,
56 server,
57 streamclone,
57 streamclone,
58 tags as tagsmod,
58 tags as tagsmod,
59 templatekw,
59 templatekw,
60 ui as uimod,
60 ui as uimod,
61 util,
61 util,
62 wireprotoserver,
62 wireprotoserver,
63 )
63 )
64 from .utils import (
64 from .utils import (
65 dateutil,
65 dateutil,
66 procutil,
66 procutil,
67 stringutil,
67 stringutil,
68 )
68 )
69
69
70 release = lockmod.release
70 release = lockmod.release
71
71
72 table = {}
72 table = {}
73 table.update(debugcommandsmod.command._table)
73 table.update(debugcommandsmod.command._table)
74
74
75 command = registrar.command(table)
75 command = registrar.command(table)
76 readonly = registrar.command.readonly
76 readonly = registrar.command.readonly
77
77
78 # common command options
78 # common command options
79
79
80 globalopts = [
80 globalopts = [
81 ('R', 'repository', '',
81 ('R', 'repository', '',
82 _('repository root directory or name of overlay bundle file'),
82 _('repository root directory or name of overlay bundle file'),
83 _('REPO')),
83 _('REPO')),
84 ('', 'cwd', '',
84 ('', 'cwd', '',
85 _('change working directory'), _('DIR')),
85 _('change working directory'), _('DIR')),
86 ('y', 'noninteractive', None,
86 ('y', 'noninteractive', None,
87 _('do not prompt, automatically pick the first choice for all prompts')),
87 _('do not prompt, automatically pick the first choice for all prompts')),
88 ('q', 'quiet', None, _('suppress output')),
88 ('q', 'quiet', None, _('suppress output')),
89 ('v', 'verbose', None, _('enable additional output')),
89 ('v', 'verbose', None, _('enable additional output')),
90 ('', 'color', '',
90 ('', 'color', '',
91 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
91 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
92 # and should not be translated
92 # and should not be translated
93 _("when to colorize (boolean, always, auto, never, or debug)"),
93 _("when to colorize (boolean, always, auto, never, or debug)"),
94 _('TYPE')),
94 _('TYPE')),
95 ('', 'config', [],
95 ('', 'config', [],
96 _('set/override config option (use \'section.name=value\')'),
96 _('set/override config option (use \'section.name=value\')'),
97 _('CONFIG')),
97 _('CONFIG')),
98 ('', 'debug', None, _('enable debugging output')),
98 ('', 'debug', None, _('enable debugging output')),
99 ('', 'debugger', None, _('start debugger')),
99 ('', 'debugger', None, _('start debugger')),
100 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
100 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
101 _('ENCODE')),
101 _('ENCODE')),
102 ('', 'encodingmode', encoding.encodingmode,
102 ('', 'encodingmode', encoding.encodingmode,
103 _('set the charset encoding mode'), _('MODE')),
103 _('set the charset encoding mode'), _('MODE')),
104 ('', 'traceback', None, _('always print a traceback on exception')),
104 ('', 'traceback', None, _('always print a traceback on exception')),
105 ('', 'time', None, _('time how long the command takes')),
105 ('', 'time', None, _('time how long the command takes')),
106 ('', 'profile', None, _('print command execution profile')),
106 ('', 'profile', None, _('print command execution profile')),
107 ('', 'version', None, _('output version information and exit')),
107 ('', 'version', None, _('output version information and exit')),
108 ('h', 'help', None, _('display help and exit')),
108 ('h', 'help', None, _('display help and exit')),
109 ('', 'hidden', False, _('consider hidden changesets')),
109 ('', 'hidden', False, _('consider hidden changesets')),
110 ('', 'pager', 'auto',
110 ('', 'pager', 'auto',
111 _("when to paginate (boolean, always, auto, or never)"), _('TYPE')),
111 _("when to paginate (boolean, always, auto, or never)"), _('TYPE')),
112 ]
112 ]
113
113
114 dryrunopts = cmdutil.dryrunopts
114 dryrunopts = cmdutil.dryrunopts
115 remoteopts = cmdutil.remoteopts
115 remoteopts = cmdutil.remoteopts
116 walkopts = cmdutil.walkopts
116 walkopts = cmdutil.walkopts
117 commitopts = cmdutil.commitopts
117 commitopts = cmdutil.commitopts
118 commitopts2 = cmdutil.commitopts2
118 commitopts2 = cmdutil.commitopts2
119 formatteropts = cmdutil.formatteropts
119 formatteropts = cmdutil.formatteropts
120 templateopts = cmdutil.templateopts
120 templateopts = cmdutil.templateopts
121 logopts = cmdutil.logopts
121 logopts = cmdutil.logopts
122 diffopts = cmdutil.diffopts
122 diffopts = cmdutil.diffopts
123 diffwsopts = cmdutil.diffwsopts
123 diffwsopts = cmdutil.diffwsopts
124 diffopts2 = cmdutil.diffopts2
124 diffopts2 = cmdutil.diffopts2
125 mergetoolopts = cmdutil.mergetoolopts
125 mergetoolopts = cmdutil.mergetoolopts
126 similarityopts = cmdutil.similarityopts
126 similarityopts = cmdutil.similarityopts
127 subrepoopts = cmdutil.subrepoopts
127 subrepoopts = cmdutil.subrepoopts
128 debugrevlogopts = cmdutil.debugrevlogopts
128 debugrevlogopts = cmdutil.debugrevlogopts
129
129
130 # Commands start here, listed alphabetically
130 # Commands start here, listed alphabetically
131
131
132 @command('^add',
132 @command('^add',
133 walkopts + subrepoopts + dryrunopts,
133 walkopts + subrepoopts + dryrunopts,
134 _('[OPTION]... [FILE]...'),
134 _('[OPTION]... [FILE]...'),
135 inferrepo=True)
135 inferrepo=True)
136 def add(ui, repo, *pats, **opts):
136 def add(ui, repo, *pats, **opts):
137 """add the specified files on the next commit
137 """add the specified files on the next commit
138
138
139 Schedule files to be version controlled and added to the
139 Schedule files to be version controlled and added to the
140 repository.
140 repository.
141
141
142 The files will be added to the repository at the next commit. To
142 The files will be added to the repository at the next commit. To
143 undo an add before that, see :hg:`forget`.
143 undo an add before that, see :hg:`forget`.
144
144
145 If no names are given, add all files to the repository (except
145 If no names are given, add all files to the repository (except
146 files matching ``.hgignore``).
146 files matching ``.hgignore``).
147
147
148 .. container:: verbose
148 .. container:: verbose
149
149
150 Examples:
150 Examples:
151
151
152 - New (unknown) files are added
152 - New (unknown) files are added
153 automatically by :hg:`add`::
153 automatically by :hg:`add`::
154
154
155 $ ls
155 $ ls
156 foo.c
156 foo.c
157 $ hg status
157 $ hg status
158 ? foo.c
158 ? foo.c
159 $ hg add
159 $ hg add
160 adding foo.c
160 adding foo.c
161 $ hg status
161 $ hg status
162 A foo.c
162 A foo.c
163
163
164 - Specific files to be added can be specified::
164 - Specific files to be added can be specified::
165
165
166 $ ls
166 $ ls
167 bar.c foo.c
167 bar.c foo.c
168 $ hg status
168 $ hg status
169 ? bar.c
169 ? bar.c
170 ? foo.c
170 ? foo.c
171 $ hg add bar.c
171 $ hg add bar.c
172 $ hg status
172 $ hg status
173 A bar.c
173 A bar.c
174 ? foo.c
174 ? foo.c
175
175
176 Returns 0 if all files are successfully added.
176 Returns 0 if all files are successfully added.
177 """
177 """
178
178
179 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
179 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
180 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
180 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
181 return rejected and 1 or 0
181 return rejected and 1 or 0
182
182
183 @command('addremove',
183 @command('addremove',
184 similarityopts + subrepoopts + walkopts + dryrunopts,
184 similarityopts + subrepoopts + walkopts + dryrunopts,
185 _('[OPTION]... [FILE]...'),
185 _('[OPTION]... [FILE]...'),
186 inferrepo=True)
186 inferrepo=True)
187 def addremove(ui, repo, *pats, **opts):
187 def addremove(ui, repo, *pats, **opts):
188 """add all new files, delete all missing files
188 """add all new files, delete all missing files
189
189
190 Add all new files and remove all missing files from the
190 Add all new files and remove all missing files from the
191 repository.
191 repository.
192
192
193 Unless names are given, new files are ignored if they match any of
193 Unless names are given, new files are ignored if they match any of
194 the patterns in ``.hgignore``. As with add, these changes take
194 the patterns in ``.hgignore``. As with add, these changes take
195 effect at the next commit.
195 effect at the next commit.
196
196
197 Use the -s/--similarity option to detect renamed files. This
197 Use the -s/--similarity option to detect renamed files. This
198 option takes a percentage between 0 (disabled) and 100 (files must
198 option takes a percentage between 0 (disabled) and 100 (files must
199 be identical) as its parameter. With a parameter greater than 0,
199 be identical) as its parameter. With a parameter greater than 0,
200 this compares every removed file with every added file and records
200 this compares every removed file with every added file and records
201 those similar enough as renames. Detecting renamed files this way
201 those similar enough as renames. Detecting renamed files this way
202 can be expensive. After using this option, :hg:`status -C` can be
202 can be expensive. After using this option, :hg:`status -C` can be
203 used to check which files were identified as moved or renamed. If
203 used to check which files were identified as moved or renamed. If
204 not specified, -s/--similarity defaults to 100 and only renames of
204 not specified, -s/--similarity defaults to 100 and only renames of
205 identical files are detected.
205 identical files are detected.
206
206
207 .. container:: verbose
207 .. container:: verbose
208
208
209 Examples:
209 Examples:
210
210
211 - A number of files (bar.c and foo.c) are new,
211 - A number of files (bar.c and foo.c) are new,
212 while foobar.c has been removed (without using :hg:`remove`)
212 while foobar.c has been removed (without using :hg:`remove`)
213 from the repository::
213 from the repository::
214
214
215 $ ls
215 $ ls
216 bar.c foo.c
216 bar.c foo.c
217 $ hg status
217 $ hg status
218 ! foobar.c
218 ! foobar.c
219 ? bar.c
219 ? bar.c
220 ? foo.c
220 ? foo.c
221 $ hg addremove
221 $ hg addremove
222 adding bar.c
222 adding bar.c
223 adding foo.c
223 adding foo.c
224 removing foobar.c
224 removing foobar.c
225 $ hg status
225 $ hg status
226 A bar.c
226 A bar.c
227 A foo.c
227 A foo.c
228 R foobar.c
228 R foobar.c
229
229
230 - A file foobar.c was moved to foo.c without using :hg:`rename`.
230 - A file foobar.c was moved to foo.c without using :hg:`rename`.
231 Afterwards, it was edited slightly::
231 Afterwards, it was edited slightly::
232
232
233 $ ls
233 $ ls
234 foo.c
234 foo.c
235 $ hg status
235 $ hg status
236 ! foobar.c
236 ! foobar.c
237 ? foo.c
237 ? foo.c
238 $ hg addremove --similarity 90
238 $ hg addremove --similarity 90
239 removing foobar.c
239 removing foobar.c
240 adding foo.c
240 adding foo.c
241 recording removal of foobar.c as rename to foo.c (94% similar)
241 recording removal of foobar.c as rename to foo.c (94% similar)
242 $ hg status -C
242 $ hg status -C
243 A foo.c
243 A foo.c
244 foobar.c
244 foobar.c
245 R foobar.c
245 R foobar.c
246
246
247 Returns 0 if all files are successfully added.
247 Returns 0 if all files are successfully added.
248 """
248 """
249 opts = pycompat.byteskwargs(opts)
249 opts = pycompat.byteskwargs(opts)
250 if not opts.get('similarity'):
250 if not opts.get('similarity'):
251 opts['similarity'] = '100'
251 opts['similarity'] = '100'
252 matcher = scmutil.match(repo[None], pats, opts)
252 matcher = scmutil.match(repo[None], pats, opts)
253 return scmutil.addremove(repo, matcher, "", opts)
253 return scmutil.addremove(repo, matcher, "", opts)
254
254
255 @command('^annotate|blame',
255 @command('^annotate|blame',
256 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
256 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
257 ('', 'follow', None,
257 ('', 'follow', None,
258 _('follow copies/renames and list the filename (DEPRECATED)')),
258 _('follow copies/renames and list the filename (DEPRECATED)')),
259 ('', 'no-follow', None, _("don't follow copies and renames")),
259 ('', 'no-follow', None, _("don't follow copies and renames")),
260 ('a', 'text', None, _('treat all files as text')),
260 ('a', 'text', None, _('treat all files as text')),
261 ('u', 'user', None, _('list the author (long with -v)')),
261 ('u', 'user', None, _('list the author (long with -v)')),
262 ('f', 'file', None, _('list the filename')),
262 ('f', 'file', None, _('list the filename')),
263 ('d', 'date', None, _('list the date (short with -q)')),
263 ('d', 'date', None, _('list the date (short with -q)')),
264 ('n', 'number', None, _('list the revision number (default)')),
264 ('n', 'number', None, _('list the revision number (default)')),
265 ('c', 'changeset', None, _('list the changeset')),
265 ('c', 'changeset', None, _('list the changeset')),
266 ('l', 'line-number', None, _('show line number at the first appearance')),
266 ('l', 'line-number', None, _('show line number at the first appearance')),
267 ('', 'skip', [], _('revision to not display (EXPERIMENTAL)'), _('REV')),
267 ('', 'skip', [], _('revision to not display (EXPERIMENTAL)'), _('REV')),
268 ] + diffwsopts + walkopts + formatteropts,
268 ] + diffwsopts + walkopts + formatteropts,
269 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
269 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
270 inferrepo=True)
270 inferrepo=True)
271 def annotate(ui, repo, *pats, **opts):
271 def annotate(ui, repo, *pats, **opts):
272 """show changeset information by line for each file
272 """show changeset information by line for each file
273
273
274 List changes in files, showing the revision id responsible for
274 List changes in files, showing the revision id responsible for
275 each line.
275 each line.
276
276
277 This command is useful for discovering when a change was made and
277 This command is useful for discovering when a change was made and
278 by whom.
278 by whom.
279
279
280 If you include --file, --user, or --date, the revision number is
280 If you include --file, --user, or --date, the revision number is
281 suppressed unless you also include --number.
281 suppressed unless you also include --number.
282
282
283 Without the -a/--text option, annotate will avoid processing files
283 Without the -a/--text option, annotate will avoid processing files
284 it detects as binary. With -a, annotate will annotate the file
284 it detects as binary. With -a, annotate will annotate the file
285 anyway, although the results will probably be neither useful
285 anyway, although the results will probably be neither useful
286 nor desirable.
286 nor desirable.
287
287
288 Returns 0 on success.
288 Returns 0 on success.
289 """
289 """
290 opts = pycompat.byteskwargs(opts)
290 opts = pycompat.byteskwargs(opts)
291 if not pats:
291 if not pats:
292 raise error.Abort(_('at least one filename or pattern is required'))
292 raise error.Abort(_('at least one filename or pattern is required'))
293
293
294 if opts.get('follow'):
294 if opts.get('follow'):
295 # --follow is deprecated and now just an alias for -f/--file
295 # --follow is deprecated and now just an alias for -f/--file
296 # to mimic the behavior of Mercurial before version 1.5
296 # to mimic the behavior of Mercurial before version 1.5
297 opts['file'] = True
297 opts['file'] = True
298
298
299 rev = opts.get('rev')
299 rev = opts.get('rev')
300 if rev:
300 if rev:
301 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
301 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
302 ctx = scmutil.revsingle(repo, rev)
302 ctx = scmutil.revsingle(repo, rev)
303
303
304 rootfm = ui.formatter('annotate', opts)
304 rootfm = ui.formatter('annotate', opts)
305 if ui.quiet:
305 if ui.quiet:
306 datefunc = dateutil.shortdate
306 datefunc = dateutil.shortdate
307 else:
307 else:
308 datefunc = dateutil.datestr
308 datefunc = dateutil.datestr
309 if ctx.rev() is None:
309 if ctx.rev() is None:
310 def hexfn(node):
310 def hexfn(node):
311 if node is None:
311 if node is None:
312 return None
312 return None
313 else:
313 else:
314 return rootfm.hexfunc(node)
314 return rootfm.hexfunc(node)
315 if opts.get('changeset'):
315 if opts.get('changeset'):
316 # omit "+" suffix which is appended to node hex
316 # omit "+" suffix which is appended to node hex
317 def formatrev(rev):
317 def formatrev(rev):
318 if rev is None:
318 if rev is None:
319 return '%d' % ctx.p1().rev()
319 return '%d' % ctx.p1().rev()
320 else:
320 else:
321 return '%d' % rev
321 return '%d' % rev
322 else:
322 else:
323 def formatrev(rev):
323 def formatrev(rev):
324 if rev is None:
324 if rev is None:
325 return '%d+' % ctx.p1().rev()
325 return '%d+' % ctx.p1().rev()
326 else:
326 else:
327 return '%d ' % rev
327 return '%d ' % rev
328 def formathex(hex):
328 def formathex(hex):
329 if hex is None:
329 if hex is None:
330 return '%s+' % rootfm.hexfunc(ctx.p1().node())
330 return '%s+' % rootfm.hexfunc(ctx.p1().node())
331 else:
331 else:
332 return '%s ' % hex
332 return '%s ' % hex
333 else:
333 else:
334 hexfn = rootfm.hexfunc
334 hexfn = rootfm.hexfunc
335 formatrev = formathex = pycompat.bytestr
335 formatrev = formathex = pycompat.bytestr
336
336
337 opmap = [('user', ' ', lambda x: x.fctx.user(), ui.shortuser),
337 opmap = [('user', ' ', lambda x: x.fctx.user(), ui.shortuser),
338 ('number', ' ', lambda x: x.fctx.rev(), formatrev),
338 ('number', ' ', lambda x: x.fctx.rev(), formatrev),
339 ('changeset', ' ', lambda x: hexfn(x.fctx.node()), formathex),
339 ('changeset', ' ', lambda x: hexfn(x.fctx.node()), formathex),
340 ('date', ' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
340 ('date', ' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
341 ('file', ' ', lambda x: x.fctx.path(), pycompat.bytestr),
341 ('file', ' ', lambda x: x.fctx.path(), pycompat.bytestr),
342 ('line_number', ':', lambda x: x.lineno, pycompat.bytestr),
342 ('line_number', ':', lambda x: x.lineno, pycompat.bytestr),
343 ]
343 ]
344 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
344 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
345
345
346 if (not opts.get('user') and not opts.get('changeset')
346 if (not opts.get('user') and not opts.get('changeset')
347 and not opts.get('date') and not opts.get('file')):
347 and not opts.get('date') and not opts.get('file')):
348 opts['number'] = True
348 opts['number'] = True
349
349
350 linenumber = opts.get('line_number') is not None
350 linenumber = opts.get('line_number') is not None
351 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
351 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
352 raise error.Abort(_('at least one of -n/-c is required for -l'))
352 raise error.Abort(_('at least one of -n/-c is required for -l'))
353
353
354 ui.pager('annotate')
354 ui.pager('annotate')
355
355
356 if rootfm.isplain():
356 if rootfm.isplain():
357 def makefunc(get, fmt):
357 def makefunc(get, fmt):
358 return lambda x: fmt(get(x))
358 return lambda x: fmt(get(x))
359 else:
359 else:
360 def makefunc(get, fmt):
360 def makefunc(get, fmt):
361 return get
361 return get
362 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
362 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
363 if opts.get(op)]
363 if opts.get(op)]
364 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
364 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
365 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
365 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
366 if opts.get(op))
366 if opts.get(op))
367
367
368 def bad(x, y):
368 def bad(x, y):
369 raise error.Abort("%s: %s" % (x, y))
369 raise error.Abort("%s: %s" % (x, y))
370
370
371 m = scmutil.match(ctx, pats, opts, badfn=bad)
371 m = scmutil.match(ctx, pats, opts, badfn=bad)
372
372
373 follow = not opts.get('no_follow')
373 follow = not opts.get('no_follow')
374 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
374 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
375 whitespace=True)
375 whitespace=True)
376 skiprevs = opts.get('skip')
376 skiprevs = opts.get('skip')
377 if skiprevs:
377 if skiprevs:
378 skiprevs = scmutil.revrange(repo, skiprevs)
378 skiprevs = scmutil.revrange(repo, skiprevs)
379
379
380 for abs in ctx.walk(m):
380 for abs in ctx.walk(m):
381 fctx = ctx[abs]
381 fctx = ctx[abs]
382 rootfm.startitem()
382 rootfm.startitem()
383 rootfm.data(abspath=abs, path=m.rel(abs))
383 rootfm.data(abspath=abs, path=m.rel(abs))
384 if not opts.get('text') and fctx.isbinary():
384 if not opts.get('text') and fctx.isbinary():
385 rootfm.plain(_("%s: binary file\n")
385 rootfm.plain(_("%s: binary file\n")
386 % ((pats and m.rel(abs)) or abs))
386 % ((pats and m.rel(abs)) or abs))
387 continue
387 continue
388
388
389 fm = rootfm.nested('lines')
389 fm = rootfm.nested('lines')
390 lines = fctx.annotate(follow=follow, skiprevs=skiprevs,
390 lines = fctx.annotate(follow=follow, skiprevs=skiprevs,
391 diffopts=diffopts)
391 diffopts=diffopts)
392 if not lines:
392 if not lines:
393 fm.end()
393 fm.end()
394 continue
394 continue
395 formats = []
395 formats = []
396 pieces = []
396 pieces = []
397
397
398 for f, sep in funcmap:
398 for f, sep in funcmap:
399 l = [f(n) for n in lines]
399 l = [f(n) for n in lines]
400 if fm.isplain():
400 if fm.isplain():
401 sizes = [encoding.colwidth(x) for x in l]
401 sizes = [encoding.colwidth(x) for x in l]
402 ml = max(sizes)
402 ml = max(sizes)
403 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
403 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
404 else:
404 else:
405 formats.append(['%s' for x in l])
405 formats.append(['%s' for x in l])
406 pieces.append(l)
406 pieces.append(l)
407
407
408 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
408 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
409 fm.startitem()
409 fm.startitem()
410 fm.context(fctx=n.fctx)
410 fm.context(fctx=n.fctx)
411 fm.write(fields, "".join(f), *p)
411 fm.write(fields, "".join(f), *p)
412 if n.skip:
412 if n.skip:
413 fmt = "* %s"
413 fmt = "* %s"
414 else:
414 else:
415 fmt = ": %s"
415 fmt = ": %s"
416 fm.write('line', fmt, n.text)
416 fm.write('line', fmt, n.text)
417
417
418 if not lines[-1].text.endswith('\n'):
418 if not lines[-1].text.endswith('\n'):
419 fm.plain('\n')
419 fm.plain('\n')
420 fm.end()
420 fm.end()
421
421
422 rootfm.end()
422 rootfm.end()
423
423
424 @command('archive',
424 @command('archive',
425 [('', 'no-decode', None, _('do not pass files through decoders')),
425 [('', 'no-decode', None, _('do not pass files through decoders')),
426 ('p', 'prefix', '', _('directory prefix for files in archive'),
426 ('p', 'prefix', '', _('directory prefix for files in archive'),
427 _('PREFIX')),
427 _('PREFIX')),
428 ('r', 'rev', '', _('revision to distribute'), _('REV')),
428 ('r', 'rev', '', _('revision to distribute'), _('REV')),
429 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
429 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
430 ] + subrepoopts + walkopts,
430 ] + subrepoopts + walkopts,
431 _('[OPTION]... DEST'))
431 _('[OPTION]... DEST'))
432 def archive(ui, repo, dest, **opts):
432 def archive(ui, repo, dest, **opts):
433 '''create an unversioned archive of a repository revision
433 '''create an unversioned archive of a repository revision
434
434
435 By default, the revision used is the parent of the working
435 By default, the revision used is the parent of the working
436 directory; use -r/--rev to specify a different revision.
436 directory; use -r/--rev to specify a different revision.
437
437
438 The archive type is automatically detected based on file
438 The archive type is automatically detected based on file
439 extension (to override, use -t/--type).
439 extension (to override, use -t/--type).
440
440
441 .. container:: verbose
441 .. container:: verbose
442
442
443 Examples:
443 Examples:
444
444
445 - create a zip file containing the 1.0 release::
445 - create a zip file containing the 1.0 release::
446
446
447 hg archive -r 1.0 project-1.0.zip
447 hg archive -r 1.0 project-1.0.zip
448
448
449 - create a tarball excluding .hg files::
449 - create a tarball excluding .hg files::
450
450
451 hg archive project.tar.gz -X ".hg*"
451 hg archive project.tar.gz -X ".hg*"
452
452
453 Valid types are:
453 Valid types are:
454
454
455 :``files``: a directory full of files (default)
455 :``files``: a directory full of files (default)
456 :``tar``: tar archive, uncompressed
456 :``tar``: tar archive, uncompressed
457 :``tbz2``: tar archive, compressed using bzip2
457 :``tbz2``: tar archive, compressed using bzip2
458 :``tgz``: tar archive, compressed using gzip
458 :``tgz``: tar archive, compressed using gzip
459 :``uzip``: zip archive, uncompressed
459 :``uzip``: zip archive, uncompressed
460 :``zip``: zip archive, compressed using deflate
460 :``zip``: zip archive, compressed using deflate
461
461
462 The exact name of the destination archive or directory is given
462 The exact name of the destination archive or directory is given
463 using a format string; see :hg:`help export` for details.
463 using a format string; see :hg:`help export` for details.
464
464
465 Each member added to an archive file has a directory prefix
465 Each member added to an archive file has a directory prefix
466 prepended. Use -p/--prefix to specify a format string for the
466 prepended. Use -p/--prefix to specify a format string for the
467 prefix. The default is the basename of the archive, with suffixes
467 prefix. The default is the basename of the archive, with suffixes
468 removed.
468 removed.
469
469
470 Returns 0 on success.
470 Returns 0 on success.
471 '''
471 '''
472
472
473 opts = pycompat.byteskwargs(opts)
473 opts = pycompat.byteskwargs(opts)
474 rev = opts.get('rev')
474 rev = opts.get('rev')
475 if rev:
475 if rev:
476 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
476 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
477 ctx = scmutil.revsingle(repo, rev)
477 ctx = scmutil.revsingle(repo, rev)
478 if not ctx:
478 if not ctx:
479 raise error.Abort(_('no working directory: please specify a revision'))
479 raise error.Abort(_('no working directory: please specify a revision'))
480 node = ctx.node()
480 node = ctx.node()
481 dest = cmdutil.makefilename(ctx, dest)
481 dest = cmdutil.makefilename(ctx, dest)
482 if os.path.realpath(dest) == repo.root:
482 if os.path.realpath(dest) == repo.root:
483 raise error.Abort(_('repository root cannot be destination'))
483 raise error.Abort(_('repository root cannot be destination'))
484
484
485 kind = opts.get('type') or archival.guesskind(dest) or 'files'
485 kind = opts.get('type') or archival.guesskind(dest) or 'files'
486 prefix = opts.get('prefix')
486 prefix = opts.get('prefix')
487
487
488 if dest == '-':
488 if dest == '-':
489 if kind == 'files':
489 if kind == 'files':
490 raise error.Abort(_('cannot archive plain files to stdout'))
490 raise error.Abort(_('cannot archive plain files to stdout'))
491 dest = cmdutil.makefileobj(ctx, dest)
491 dest = cmdutil.makefileobj(ctx, dest)
492 if not prefix:
492 if not prefix:
493 prefix = os.path.basename(repo.root) + '-%h'
493 prefix = os.path.basename(repo.root) + '-%h'
494
494
495 prefix = cmdutil.makefilename(ctx, prefix)
495 prefix = cmdutil.makefilename(ctx, prefix)
496 match = scmutil.match(ctx, [], opts)
496 match = scmutil.match(ctx, [], opts)
497 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
497 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
498 match, prefix, subrepos=opts.get('subrepos'))
498 match, prefix, subrepos=opts.get('subrepos'))
499
499
500 @command('backout',
500 @command('backout',
501 [('', 'merge', None, _('merge with old dirstate parent after backout')),
501 [('', 'merge', None, _('merge with old dirstate parent after backout')),
502 ('', 'commit', None,
502 ('', 'commit', None,
503 _('commit if no conflicts were encountered (DEPRECATED)')),
503 _('commit if no conflicts were encountered (DEPRECATED)')),
504 ('', 'no-commit', None, _('do not commit')),
504 ('', 'no-commit', None, _('do not commit')),
505 ('', 'parent', '',
505 ('', 'parent', '',
506 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
506 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
507 ('r', 'rev', '', _('revision to backout'), _('REV')),
507 ('r', 'rev', '', _('revision to backout'), _('REV')),
508 ('e', 'edit', False, _('invoke editor on commit messages')),
508 ('e', 'edit', False, _('invoke editor on commit messages')),
509 ] + mergetoolopts + walkopts + commitopts + commitopts2,
509 ] + mergetoolopts + walkopts + commitopts + commitopts2,
510 _('[OPTION]... [-r] REV'))
510 _('[OPTION]... [-r] REV'))
511 def backout(ui, repo, node=None, rev=None, **opts):
511 def backout(ui, repo, node=None, rev=None, **opts):
512 '''reverse effect of earlier changeset
512 '''reverse effect of earlier changeset
513
513
514 Prepare a new changeset with the effect of REV undone in the
514 Prepare a new changeset with the effect of REV undone in the
515 current working directory. If no conflicts were encountered,
515 current working directory. If no conflicts were encountered,
516 it will be committed immediately.
516 it will be committed immediately.
517
517
518 If REV is the parent of the working directory, then this new changeset
518 If REV is the parent of the working directory, then this new changeset
519 is committed automatically (unless --no-commit is specified).
519 is committed automatically (unless --no-commit is specified).
520
520
521 .. note::
521 .. note::
522
522
523 :hg:`backout` cannot be used to fix either an unwanted or
523 :hg:`backout` cannot be used to fix either an unwanted or
524 incorrect merge.
524 incorrect merge.
525
525
526 .. container:: verbose
526 .. container:: verbose
527
527
528 Examples:
528 Examples:
529
529
530 - Reverse the effect of the parent of the working directory.
530 - Reverse the effect of the parent of the working directory.
531 This backout will be committed immediately::
531 This backout will be committed immediately::
532
532
533 hg backout -r .
533 hg backout -r .
534
534
535 - Reverse the effect of previous bad revision 23::
535 - Reverse the effect of previous bad revision 23::
536
536
537 hg backout -r 23
537 hg backout -r 23
538
538
539 - Reverse the effect of previous bad revision 23 and
539 - Reverse the effect of previous bad revision 23 and
540 leave changes uncommitted::
540 leave changes uncommitted::
541
541
542 hg backout -r 23 --no-commit
542 hg backout -r 23 --no-commit
543 hg commit -m "Backout revision 23"
543 hg commit -m "Backout revision 23"
544
544
545 By default, the pending changeset will have one parent,
545 By default, the pending changeset will have one parent,
546 maintaining a linear history. With --merge, the pending
546 maintaining a linear history. With --merge, the pending
547 changeset will instead have two parents: the old parent of the
547 changeset will instead have two parents: the old parent of the
548 working directory and a new child of REV that simply undoes REV.
548 working directory and a new child of REV that simply undoes REV.
549
549
550 Before version 1.7, the behavior without --merge was equivalent
550 Before version 1.7, the behavior without --merge was equivalent
551 to specifying --merge followed by :hg:`update --clean .` to
551 to specifying --merge followed by :hg:`update --clean .` to
552 cancel the merge and leave the child of REV as a head to be
552 cancel the merge and leave the child of REV as a head to be
553 merged separately.
553 merged separately.
554
554
555 See :hg:`help dates` for a list of formats valid for -d/--date.
555 See :hg:`help dates` for a list of formats valid for -d/--date.
556
556
557 See :hg:`help revert` for a way to restore files to the state
557 See :hg:`help revert` for a way to restore files to the state
558 of another revision.
558 of another revision.
559
559
560 Returns 0 on success, 1 if nothing to backout or there are unresolved
560 Returns 0 on success, 1 if nothing to backout or there are unresolved
561 files.
561 files.
562 '''
562 '''
563 wlock = lock = None
563 wlock = lock = None
564 try:
564 try:
565 wlock = repo.wlock()
565 wlock = repo.wlock()
566 lock = repo.lock()
566 lock = repo.lock()
567 return _dobackout(ui, repo, node, rev, **opts)
567 return _dobackout(ui, repo, node, rev, **opts)
568 finally:
568 finally:
569 release(lock, wlock)
569 release(lock, wlock)
570
570
571 def _dobackout(ui, repo, node=None, rev=None, **opts):
571 def _dobackout(ui, repo, node=None, rev=None, **opts):
572 opts = pycompat.byteskwargs(opts)
572 opts = pycompat.byteskwargs(opts)
573 if opts.get('commit') and opts.get('no_commit'):
573 if opts.get('commit') and opts.get('no_commit'):
574 raise error.Abort(_("cannot use --commit with --no-commit"))
574 raise error.Abort(_("cannot use --commit with --no-commit"))
575 if opts.get('merge') and opts.get('no_commit'):
575 if opts.get('merge') and opts.get('no_commit'):
576 raise error.Abort(_("cannot use --merge with --no-commit"))
576 raise error.Abort(_("cannot use --merge with --no-commit"))
577
577
578 if rev and node:
578 if rev and node:
579 raise error.Abort(_("please specify just one revision"))
579 raise error.Abort(_("please specify just one revision"))
580
580
581 if not rev:
581 if not rev:
582 rev = node
582 rev = node
583
583
584 if not rev:
584 if not rev:
585 raise error.Abort(_("please specify a revision to backout"))
585 raise error.Abort(_("please specify a revision to backout"))
586
586
587 date = opts.get('date')
587 date = opts.get('date')
588 if date:
588 if date:
589 opts['date'] = dateutil.parsedate(date)
589 opts['date'] = dateutil.parsedate(date)
590
590
591 cmdutil.checkunfinished(repo)
591 cmdutil.checkunfinished(repo)
592 cmdutil.bailifchanged(repo)
592 cmdutil.bailifchanged(repo)
593 node = scmutil.revsingle(repo, rev).node()
593 node = scmutil.revsingle(repo, rev).node()
594
594
595 op1, op2 = repo.dirstate.parents()
595 op1, op2 = repo.dirstate.parents()
596 if not repo.changelog.isancestor(node, op1):
596 if not repo.changelog.isancestor(node, op1):
597 raise error.Abort(_('cannot backout change that is not an ancestor'))
597 raise error.Abort(_('cannot backout change that is not an ancestor'))
598
598
599 p1, p2 = repo.changelog.parents(node)
599 p1, p2 = repo.changelog.parents(node)
600 if p1 == nullid:
600 if p1 == nullid:
601 raise error.Abort(_('cannot backout a change with no parents'))
601 raise error.Abort(_('cannot backout a change with no parents'))
602 if p2 != nullid:
602 if p2 != nullid:
603 if not opts.get('parent'):
603 if not opts.get('parent'):
604 raise error.Abort(_('cannot backout a merge changeset'))
604 raise error.Abort(_('cannot backout a merge changeset'))
605 p = repo.lookup(opts['parent'])
605 p = repo.lookup(opts['parent'])
606 if p not in (p1, p2):
606 if p not in (p1, p2):
607 raise error.Abort(_('%s is not a parent of %s') %
607 raise error.Abort(_('%s is not a parent of %s') %
608 (short(p), short(node)))
608 (short(p), short(node)))
609 parent = p
609 parent = p
610 else:
610 else:
611 if opts.get('parent'):
611 if opts.get('parent'):
612 raise error.Abort(_('cannot use --parent on non-merge changeset'))
612 raise error.Abort(_('cannot use --parent on non-merge changeset'))
613 parent = p1
613 parent = p1
614
614
615 # the backout should appear on the same branch
615 # the backout should appear on the same branch
616 branch = repo.dirstate.branch()
616 branch = repo.dirstate.branch()
617 bheads = repo.branchheads(branch)
617 bheads = repo.branchheads(branch)
618 rctx = scmutil.revsingle(repo, hex(parent))
618 rctx = scmutil.revsingle(repo, hex(parent))
619 if not opts.get('merge') and op1 != node:
619 if not opts.get('merge') and op1 != node:
620 dsguard = dirstateguard.dirstateguard(repo, 'backout')
620 dsguard = dirstateguard.dirstateguard(repo, 'backout')
621 try:
621 try:
622 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
622 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
623 'backout')
623 'backout')
624 stats = mergemod.update(repo, parent, True, True, node, False)
624 stats = mergemod.update(repo, parent, True, True, node, False)
625 repo.setparents(op1, op2)
625 repo.setparents(op1, op2)
626 dsguard.close()
626 dsguard.close()
627 hg._showstats(repo, stats)
627 hg._showstats(repo, stats)
628 if stats.unresolvedcount:
628 if stats.unresolvedcount:
629 repo.ui.status(_("use 'hg resolve' to retry unresolved "
629 repo.ui.status(_("use 'hg resolve' to retry unresolved "
630 "file merges\n"))
630 "file merges\n"))
631 return 1
631 return 1
632 finally:
632 finally:
633 ui.setconfig('ui', 'forcemerge', '', '')
633 ui.setconfig('ui', 'forcemerge', '', '')
634 lockmod.release(dsguard)
634 lockmod.release(dsguard)
635 else:
635 else:
636 hg.clean(repo, node, show_stats=False)
636 hg.clean(repo, node, show_stats=False)
637 repo.dirstate.setbranch(branch)
637 repo.dirstate.setbranch(branch)
638 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
638 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
639
639
640 if opts.get('no_commit'):
640 if opts.get('no_commit'):
641 msg = _("changeset %s backed out, "
641 msg = _("changeset %s backed out, "
642 "don't forget to commit.\n")
642 "don't forget to commit.\n")
643 ui.status(msg % short(node))
643 ui.status(msg % short(node))
644 return 0
644 return 0
645
645
646 def commitfunc(ui, repo, message, match, opts):
646 def commitfunc(ui, repo, message, match, opts):
647 editform = 'backout'
647 editform = 'backout'
648 e = cmdutil.getcommiteditor(editform=editform,
648 e = cmdutil.getcommiteditor(editform=editform,
649 **pycompat.strkwargs(opts))
649 **pycompat.strkwargs(opts))
650 if not message:
650 if not message:
651 # we don't translate commit messages
651 # we don't translate commit messages
652 message = "Backed out changeset %s" % short(node)
652 message = "Backed out changeset %s" % short(node)
653 e = cmdutil.getcommiteditor(edit=True, editform=editform)
653 e = cmdutil.getcommiteditor(edit=True, editform=editform)
654 return repo.commit(message, opts.get('user'), opts.get('date'),
654 return repo.commit(message, opts.get('user'), opts.get('date'),
655 match, editor=e)
655 match, editor=e)
656 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
656 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
657 if not newnode:
657 if not newnode:
658 ui.status(_("nothing changed\n"))
658 ui.status(_("nothing changed\n"))
659 return 1
659 return 1
660 cmdutil.commitstatus(repo, newnode, branch, bheads)
660 cmdutil.commitstatus(repo, newnode, branch, bheads)
661
661
662 def nice(node):
662 def nice(node):
663 return '%d:%s' % (repo.changelog.rev(node), short(node))
663 return '%d:%s' % (repo.changelog.rev(node), short(node))
664 ui.status(_('changeset %s backs out changeset %s\n') %
664 ui.status(_('changeset %s backs out changeset %s\n') %
665 (nice(repo.changelog.tip()), nice(node)))
665 (nice(repo.changelog.tip()), nice(node)))
666 if opts.get('merge') and op1 != node:
666 if opts.get('merge') and op1 != node:
667 hg.clean(repo, op1, show_stats=False)
667 hg.clean(repo, op1, show_stats=False)
668 ui.status(_('merging with changeset %s\n')
668 ui.status(_('merging with changeset %s\n')
669 % nice(repo.changelog.tip()))
669 % nice(repo.changelog.tip()))
670 try:
670 try:
671 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
671 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
672 'backout')
672 'backout')
673 return hg.merge(repo, hex(repo.changelog.tip()))
673 return hg.merge(repo, hex(repo.changelog.tip()))
674 finally:
674 finally:
675 ui.setconfig('ui', 'forcemerge', '', '')
675 ui.setconfig('ui', 'forcemerge', '', '')
676 return 0
676 return 0
677
677
678 @command('bisect',
678 @command('bisect',
679 [('r', 'reset', False, _('reset bisect state')),
679 [('r', 'reset', False, _('reset bisect state')),
680 ('g', 'good', False, _('mark changeset good')),
680 ('g', 'good', False, _('mark changeset good')),
681 ('b', 'bad', False, _('mark changeset bad')),
681 ('b', 'bad', False, _('mark changeset bad')),
682 ('s', 'skip', False, _('skip testing changeset')),
682 ('s', 'skip', False, _('skip testing changeset')),
683 ('e', 'extend', False, _('extend the bisect range')),
683 ('e', 'extend', False, _('extend the bisect range')),
684 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
684 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
685 ('U', 'noupdate', False, _('do not update to target'))],
685 ('U', 'noupdate', False, _('do not update to target'))],
686 _("[-gbsr] [-U] [-c CMD] [REV]"))
686 _("[-gbsr] [-U] [-c CMD] [REV]"))
687 def bisect(ui, repo, rev=None, extra=None, command=None,
687 def bisect(ui, repo, rev=None, extra=None, command=None,
688 reset=None, good=None, bad=None, skip=None, extend=None,
688 reset=None, good=None, bad=None, skip=None, extend=None,
689 noupdate=None):
689 noupdate=None):
690 """subdivision search of changesets
690 """subdivision search of changesets
691
691
692 This command helps to find changesets which introduce problems. To
692 This command helps to find changesets which introduce problems. To
693 use, mark the earliest changeset you know exhibits the problem as
693 use, mark the earliest changeset you know exhibits the problem as
694 bad, then mark the latest changeset which is free from the problem
694 bad, then mark the latest changeset which is free from the problem
695 as good. Bisect will update your working directory to a revision
695 as good. Bisect will update your working directory to a revision
696 for testing (unless the -U/--noupdate option is specified). Once
696 for testing (unless the -U/--noupdate option is specified). Once
697 you have performed tests, mark the working directory as good or
697 you have performed tests, mark the working directory as good or
698 bad, and bisect will either update to another candidate changeset
698 bad, and bisect will either update to another candidate changeset
699 or announce that it has found the bad revision.
699 or announce that it has found the bad revision.
700
700
701 As a shortcut, you can also use the revision argument to mark a
701 As a shortcut, you can also use the revision argument to mark a
702 revision as good or bad without checking it out first.
702 revision as good or bad without checking it out first.
703
703
704 If you supply a command, it will be used for automatic bisection.
704 If you supply a command, it will be used for automatic bisection.
705 The environment variable HG_NODE will contain the ID of the
705 The environment variable HG_NODE will contain the ID of the
706 changeset being tested. The exit status of the command will be
706 changeset being tested. The exit status of the command will be
707 used to mark revisions as good or bad: status 0 means good, 125
707 used to mark revisions as good or bad: status 0 means good, 125
708 means to skip the revision, 127 (command not found) will abort the
708 means to skip the revision, 127 (command not found) will abort the
709 bisection, and any other non-zero exit status means the revision
709 bisection, and any other non-zero exit status means the revision
710 is bad.
710 is bad.
711
711
712 .. container:: verbose
712 .. container:: verbose
713
713
714 Some examples:
714 Some examples:
715
715
716 - start a bisection with known bad revision 34, and good revision 12::
716 - start a bisection with known bad revision 34, and good revision 12::
717
717
718 hg bisect --bad 34
718 hg bisect --bad 34
719 hg bisect --good 12
719 hg bisect --good 12
720
720
721 - advance the current bisection by marking current revision as good or
721 - advance the current bisection by marking current revision as good or
722 bad::
722 bad::
723
723
724 hg bisect --good
724 hg bisect --good
725 hg bisect --bad
725 hg bisect --bad
726
726
727 - mark the current revision, or a known revision, to be skipped (e.g. if
727 - mark the current revision, or a known revision, to be skipped (e.g. if
728 that revision is not usable because of another issue)::
728 that revision is not usable because of another issue)::
729
729
730 hg bisect --skip
730 hg bisect --skip
731 hg bisect --skip 23
731 hg bisect --skip 23
732
732
733 - skip all revisions that do not touch directories ``foo`` or ``bar``::
733 - skip all revisions that do not touch directories ``foo`` or ``bar``::
734
734
735 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
735 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
736
736
737 - forget the current bisection::
737 - forget the current bisection::
738
738
739 hg bisect --reset
739 hg bisect --reset
740
740
741 - use 'make && make tests' to automatically find the first broken
741 - use 'make && make tests' to automatically find the first broken
742 revision::
742 revision::
743
743
744 hg bisect --reset
744 hg bisect --reset
745 hg bisect --bad 34
745 hg bisect --bad 34
746 hg bisect --good 12
746 hg bisect --good 12
747 hg bisect --command "make && make tests"
747 hg bisect --command "make && make tests"
748
748
749 - see all changesets whose states are already known in the current
749 - see all changesets whose states are already known in the current
750 bisection::
750 bisection::
751
751
752 hg log -r "bisect(pruned)"
752 hg log -r "bisect(pruned)"
753
753
754 - see the changeset currently being bisected (especially useful
754 - see the changeset currently being bisected (especially useful
755 if running with -U/--noupdate)::
755 if running with -U/--noupdate)::
756
756
757 hg log -r "bisect(current)"
757 hg log -r "bisect(current)"
758
758
759 - see all changesets that took part in the current bisection::
759 - see all changesets that took part in the current bisection::
760
760
761 hg log -r "bisect(range)"
761 hg log -r "bisect(range)"
762
762
763 - you can even get a nice graph::
763 - you can even get a nice graph::
764
764
765 hg log --graph -r "bisect(range)"
765 hg log --graph -r "bisect(range)"
766
766
767 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
767 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
768
768
769 Returns 0 on success.
769 Returns 0 on success.
770 """
770 """
771 # backward compatibility
771 # backward compatibility
772 if rev in "good bad reset init".split():
772 if rev in "good bad reset init".split():
773 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
773 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
774 cmd, rev, extra = rev, extra, None
774 cmd, rev, extra = rev, extra, None
775 if cmd == "good":
775 if cmd == "good":
776 good = True
776 good = True
777 elif cmd == "bad":
777 elif cmd == "bad":
778 bad = True
778 bad = True
779 else:
779 else:
780 reset = True
780 reset = True
781 elif extra:
781 elif extra:
782 raise error.Abort(_('incompatible arguments'))
782 raise error.Abort(_('incompatible arguments'))
783
783
784 incompatibles = {
784 incompatibles = {
785 '--bad': bad,
785 '--bad': bad,
786 '--command': bool(command),
786 '--command': bool(command),
787 '--extend': extend,
787 '--extend': extend,
788 '--good': good,
788 '--good': good,
789 '--reset': reset,
789 '--reset': reset,
790 '--skip': skip,
790 '--skip': skip,
791 }
791 }
792
792
793 enabled = [x for x in incompatibles if incompatibles[x]]
793 enabled = [x for x in incompatibles if incompatibles[x]]
794
794
795 if len(enabled) > 1:
795 if len(enabled) > 1:
796 raise error.Abort(_('%s and %s are incompatible') %
796 raise error.Abort(_('%s and %s are incompatible') %
797 tuple(sorted(enabled)[0:2]))
797 tuple(sorted(enabled)[0:2]))
798
798
799 if reset:
799 if reset:
800 hbisect.resetstate(repo)
800 hbisect.resetstate(repo)
801 return
801 return
802
802
803 state = hbisect.load_state(repo)
803 state = hbisect.load_state(repo)
804
804
805 # update state
805 # update state
806 if good or bad or skip:
806 if good or bad or skip:
807 if rev:
807 if rev:
808 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
808 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
809 else:
809 else:
810 nodes = [repo.lookup('.')]
810 nodes = [repo.lookup('.')]
811 if good:
811 if good:
812 state['good'] += nodes
812 state['good'] += nodes
813 elif bad:
813 elif bad:
814 state['bad'] += nodes
814 state['bad'] += nodes
815 elif skip:
815 elif skip:
816 state['skip'] += nodes
816 state['skip'] += nodes
817 hbisect.save_state(repo, state)
817 hbisect.save_state(repo, state)
818 if not (state['good'] and state['bad']):
818 if not (state['good'] and state['bad']):
819 return
819 return
820
820
821 def mayupdate(repo, node, show_stats=True):
821 def mayupdate(repo, node, show_stats=True):
822 """common used update sequence"""
822 """common used update sequence"""
823 if noupdate:
823 if noupdate:
824 return
824 return
825 cmdutil.checkunfinished(repo)
825 cmdutil.checkunfinished(repo)
826 cmdutil.bailifchanged(repo)
826 cmdutil.bailifchanged(repo)
827 return hg.clean(repo, node, show_stats=show_stats)
827 return hg.clean(repo, node, show_stats=show_stats)
828
828
829 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
829 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
830
830
831 if command:
831 if command:
832 changesets = 1
832 changesets = 1
833 if noupdate:
833 if noupdate:
834 try:
834 try:
835 node = state['current'][0]
835 node = state['current'][0]
836 except LookupError:
836 except LookupError:
837 raise error.Abort(_('current bisect revision is unknown - '
837 raise error.Abort(_('current bisect revision is unknown - '
838 'start a new bisect to fix'))
838 'start a new bisect to fix'))
839 else:
839 else:
840 node, p2 = repo.dirstate.parents()
840 node, p2 = repo.dirstate.parents()
841 if p2 != nullid:
841 if p2 != nullid:
842 raise error.Abort(_('current bisect revision is a merge'))
842 raise error.Abort(_('current bisect revision is a merge'))
843 if rev:
843 if rev:
844 node = repo[scmutil.revsingle(repo, rev, node)].node()
844 node = repo[scmutil.revsingle(repo, rev, node)].node()
845 try:
845 try:
846 while changesets:
846 while changesets:
847 # update state
847 # update state
848 state['current'] = [node]
848 state['current'] = [node]
849 hbisect.save_state(repo, state)
849 hbisect.save_state(repo, state)
850 status = ui.system(command, environ={'HG_NODE': hex(node)},
850 status = ui.system(command, environ={'HG_NODE': hex(node)},
851 blockedtag='bisect_check')
851 blockedtag='bisect_check')
852 if status == 125:
852 if status == 125:
853 transition = "skip"
853 transition = "skip"
854 elif status == 0:
854 elif status == 0:
855 transition = "good"
855 transition = "good"
856 # status < 0 means process was killed
856 # status < 0 means process was killed
857 elif status == 127:
857 elif status == 127:
858 raise error.Abort(_("failed to execute %s") % command)
858 raise error.Abort(_("failed to execute %s") % command)
859 elif status < 0:
859 elif status < 0:
860 raise error.Abort(_("%s killed") % command)
860 raise error.Abort(_("%s killed") % command)
861 else:
861 else:
862 transition = "bad"
862 transition = "bad"
863 state[transition].append(node)
863 state[transition].append(node)
864 ctx = repo[node]
864 ctx = repo[node]
865 ui.status(_('changeset %d:%s: %s\n') % (ctx.rev(), ctx,
865 ui.status(_('changeset %d:%s: %s\n') % (ctx.rev(), ctx,
866 transition))
866 transition))
867 hbisect.checkstate(state)
867 hbisect.checkstate(state)
868 # bisect
868 # bisect
869 nodes, changesets, bgood = hbisect.bisect(repo, state)
869 nodes, changesets, bgood = hbisect.bisect(repo, state)
870 # update to next check
870 # update to next check
871 node = nodes[0]
871 node = nodes[0]
872 mayupdate(repo, node, show_stats=False)
872 mayupdate(repo, node, show_stats=False)
873 finally:
873 finally:
874 state['current'] = [node]
874 state['current'] = [node]
875 hbisect.save_state(repo, state)
875 hbisect.save_state(repo, state)
876 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
876 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
877 return
877 return
878
878
879 hbisect.checkstate(state)
879 hbisect.checkstate(state)
880
880
881 # actually bisect
881 # actually bisect
882 nodes, changesets, good = hbisect.bisect(repo, state)
882 nodes, changesets, good = hbisect.bisect(repo, state)
883 if extend:
883 if extend:
884 if not changesets:
884 if not changesets:
885 extendnode = hbisect.extendrange(repo, state, nodes, good)
885 extendnode = hbisect.extendrange(repo, state, nodes, good)
886 if extendnode is not None:
886 if extendnode is not None:
887 ui.write(_("Extending search to changeset %d:%s\n")
887 ui.write(_("Extending search to changeset %d:%s\n")
888 % (extendnode.rev(), extendnode))
888 % (extendnode.rev(), extendnode))
889 state['current'] = [extendnode.node()]
889 state['current'] = [extendnode.node()]
890 hbisect.save_state(repo, state)
890 hbisect.save_state(repo, state)
891 return mayupdate(repo, extendnode.node())
891 return mayupdate(repo, extendnode.node())
892 raise error.Abort(_("nothing to extend"))
892 raise error.Abort(_("nothing to extend"))
893
893
894 if changesets == 0:
894 if changesets == 0:
895 hbisect.printresult(ui, repo, state, displayer, nodes, good)
895 hbisect.printresult(ui, repo, state, displayer, nodes, good)
896 else:
896 else:
897 assert len(nodes) == 1 # only a single node can be tested next
897 assert len(nodes) == 1 # only a single node can be tested next
898 node = nodes[0]
898 node = nodes[0]
899 # compute the approximate number of remaining tests
899 # compute the approximate number of remaining tests
900 tests, size = 0, 2
900 tests, size = 0, 2
901 while size <= changesets:
901 while size <= changesets:
902 tests, size = tests + 1, size * 2
902 tests, size = tests + 1, size * 2
903 rev = repo.changelog.rev(node)
903 rev = repo.changelog.rev(node)
904 ui.write(_("Testing changeset %d:%s "
904 ui.write(_("Testing changeset %d:%s "
905 "(%d changesets remaining, ~%d tests)\n")
905 "(%d changesets remaining, ~%d tests)\n")
906 % (rev, short(node), changesets, tests))
906 % (rev, short(node), changesets, tests))
907 state['current'] = [node]
907 state['current'] = [node]
908 hbisect.save_state(repo, state)
908 hbisect.save_state(repo, state)
909 return mayupdate(repo, node)
909 return mayupdate(repo, node)
910
910
911 @command('bookmarks|bookmark',
911 @command('bookmarks|bookmark',
912 [('f', 'force', False, _('force')),
912 [('f', 'force', False, _('force')),
913 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
913 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
914 ('d', 'delete', False, _('delete a given bookmark')),
914 ('d', 'delete', False, _('delete a given bookmark')),
915 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
915 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
916 ('i', 'inactive', False, _('mark a bookmark inactive')),
916 ('i', 'inactive', False, _('mark a bookmark inactive')),
917 ] + formatteropts,
917 ] + formatteropts,
918 _('hg bookmarks [OPTIONS]... [NAME]...'))
918 _('hg bookmarks [OPTIONS]... [NAME]...'))
919 def bookmark(ui, repo, *names, **opts):
919 def bookmark(ui, repo, *names, **opts):
920 '''create a new bookmark or list existing bookmarks
920 '''create a new bookmark or list existing bookmarks
921
921
922 Bookmarks are labels on changesets to help track lines of development.
922 Bookmarks are labels on changesets to help track lines of development.
923 Bookmarks are unversioned and can be moved, renamed and deleted.
923 Bookmarks are unversioned and can be moved, renamed and deleted.
924 Deleting or moving a bookmark has no effect on the associated changesets.
924 Deleting or moving a bookmark has no effect on the associated changesets.
925
925
926 Creating or updating to a bookmark causes it to be marked as 'active'.
926 Creating or updating to a bookmark causes it to be marked as 'active'.
927 The active bookmark is indicated with a '*'.
927 The active bookmark is indicated with a '*'.
928 When a commit is made, the active bookmark will advance to the new commit.
928 When a commit is made, the active bookmark will advance to the new commit.
929 A plain :hg:`update` will also advance an active bookmark, if possible.
929 A plain :hg:`update` will also advance an active bookmark, if possible.
930 Updating away from a bookmark will cause it to be deactivated.
930 Updating away from a bookmark will cause it to be deactivated.
931
931
932 Bookmarks can be pushed and pulled between repositories (see
932 Bookmarks can be pushed and pulled between repositories (see
933 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
933 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
934 diverged, a new 'divergent bookmark' of the form 'name@path' will
934 diverged, a new 'divergent bookmark' of the form 'name@path' will
935 be created. Using :hg:`merge` will resolve the divergence.
935 be created. Using :hg:`merge` will resolve the divergence.
936
936
937 Specifying bookmark as '.' to -m or -d options is equivalent to specifying
937 Specifying bookmark as '.' to -m or -d options is equivalent to specifying
938 the active bookmark's name.
938 the active bookmark's name.
939
939
940 A bookmark named '@' has the special property that :hg:`clone` will
940 A bookmark named '@' has the special property that :hg:`clone` will
941 check it out by default if it exists.
941 check it out by default if it exists.
942
942
943 .. container:: verbose
943 .. container:: verbose
944
944
945 Examples:
945 Examples:
946
946
947 - create an active bookmark for a new line of development::
947 - create an active bookmark for a new line of development::
948
948
949 hg book new-feature
949 hg book new-feature
950
950
951 - create an inactive bookmark as a place marker::
951 - create an inactive bookmark as a place marker::
952
952
953 hg book -i reviewed
953 hg book -i reviewed
954
954
955 - create an inactive bookmark on another changeset::
955 - create an inactive bookmark on another changeset::
956
956
957 hg book -r .^ tested
957 hg book -r .^ tested
958
958
959 - rename bookmark turkey to dinner::
959 - rename bookmark turkey to dinner::
960
960
961 hg book -m turkey dinner
961 hg book -m turkey dinner
962
962
963 - move the '@' bookmark from another branch::
963 - move the '@' bookmark from another branch::
964
964
965 hg book -f @
965 hg book -f @
966 '''
966 '''
967 force = opts.get(r'force')
967 force = opts.get(r'force')
968 rev = opts.get(r'rev')
968 rev = opts.get(r'rev')
969 delete = opts.get(r'delete')
969 delete = opts.get(r'delete')
970 rename = opts.get(r'rename')
970 rename = opts.get(r'rename')
971 inactive = opts.get(r'inactive')
971 inactive = opts.get(r'inactive')
972
972
973 if delete and rename:
973 if delete and rename:
974 raise error.Abort(_("--delete and --rename are incompatible"))
974 raise error.Abort(_("--delete and --rename are incompatible"))
975 if delete and rev:
975 if delete and rev:
976 raise error.Abort(_("--rev is incompatible with --delete"))
976 raise error.Abort(_("--rev is incompatible with --delete"))
977 if rename and rev:
977 if rename and rev:
978 raise error.Abort(_("--rev is incompatible with --rename"))
978 raise error.Abort(_("--rev is incompatible with --rename"))
979 if not names and (delete or rev):
979 if not names and (delete or rev):
980 raise error.Abort(_("bookmark name required"))
980 raise error.Abort(_("bookmark name required"))
981
981
982 if delete or rename or names or inactive:
982 if delete or rename or names or inactive:
983 with repo.wlock(), repo.lock(), repo.transaction('bookmark') as tr:
983 with repo.wlock(), repo.lock(), repo.transaction('bookmark') as tr:
984 if delete:
984 if delete:
985 names = pycompat.maplist(repo._bookmarks.expandname, names)
985 names = pycompat.maplist(repo._bookmarks.expandname, names)
986 bookmarks.delete(repo, tr, names)
986 bookmarks.delete(repo, tr, names)
987 elif rename:
987 elif rename:
988 if not names:
988 if not names:
989 raise error.Abort(_("new bookmark name required"))
989 raise error.Abort(_("new bookmark name required"))
990 elif len(names) > 1:
990 elif len(names) > 1:
991 raise error.Abort(_("only one new bookmark name allowed"))
991 raise error.Abort(_("only one new bookmark name allowed"))
992 rename = repo._bookmarks.expandname(rename)
992 rename = repo._bookmarks.expandname(rename)
993 bookmarks.rename(repo, tr, rename, names[0], force, inactive)
993 bookmarks.rename(repo, tr, rename, names[0], force, inactive)
994 elif names:
994 elif names:
995 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
995 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
996 elif inactive:
996 elif inactive:
997 if len(repo._bookmarks) == 0:
997 if len(repo._bookmarks) == 0:
998 ui.status(_("no bookmarks set\n"))
998 ui.status(_("no bookmarks set\n"))
999 elif not repo._activebookmark:
999 elif not repo._activebookmark:
1000 ui.status(_("no active bookmark\n"))
1000 ui.status(_("no active bookmark\n"))
1001 else:
1001 else:
1002 bookmarks.deactivate(repo)
1002 bookmarks.deactivate(repo)
1003 else: # show bookmarks
1003 else: # show bookmarks
1004 bookmarks.printbookmarks(ui, repo, **opts)
1004 bookmarks.printbookmarks(ui, repo, **opts)
1005
1005
1006 @command('branch',
1006 @command('branch',
1007 [('f', 'force', None,
1007 [('f', 'force', None,
1008 _('set branch name even if it shadows an existing branch')),
1008 _('set branch name even if it shadows an existing branch')),
1009 ('C', 'clean', None, _('reset branch name to parent branch name')),
1009 ('C', 'clean', None, _('reset branch name to parent branch name')),
1010 ('r', 'rev', [], _('change branches of the given revs (EXPERIMENTAL)')),
1010 ('r', 'rev', [], _('change branches of the given revs (EXPERIMENTAL)')),
1011 ],
1011 ],
1012 _('[-fC] [NAME]'))
1012 _('[-fC] [NAME]'))
1013 def branch(ui, repo, label=None, **opts):
1013 def branch(ui, repo, label=None, **opts):
1014 """set or show the current branch name
1014 """set or show the current branch name
1015
1015
1016 .. note::
1016 .. note::
1017
1017
1018 Branch names are permanent and global. Use :hg:`bookmark` to create a
1018 Branch names are permanent and global. Use :hg:`bookmark` to create a
1019 light-weight bookmark instead. See :hg:`help glossary` for more
1019 light-weight bookmark instead. See :hg:`help glossary` for more
1020 information about named branches and bookmarks.
1020 information about named branches and bookmarks.
1021
1021
1022 With no argument, show the current branch name. With one argument,
1022 With no argument, show the current branch name. With one argument,
1023 set the working directory branch name (the branch will not exist
1023 set the working directory branch name (the branch will not exist
1024 in the repository until the next commit). Standard practice
1024 in the repository until the next commit). Standard practice
1025 recommends that primary development take place on the 'default'
1025 recommends that primary development take place on the 'default'
1026 branch.
1026 branch.
1027
1027
1028 Unless -f/--force is specified, branch will not let you set a
1028 Unless -f/--force is specified, branch will not let you set a
1029 branch name that already exists.
1029 branch name that already exists.
1030
1030
1031 Use -C/--clean to reset the working directory branch to that of
1031 Use -C/--clean to reset the working directory branch to that of
1032 the parent of the working directory, negating a previous branch
1032 the parent of the working directory, negating a previous branch
1033 change.
1033 change.
1034
1034
1035 Use the command :hg:`update` to switch to an existing branch. Use
1035 Use the command :hg:`update` to switch to an existing branch. Use
1036 :hg:`commit --close-branch` to mark this branch head as closed.
1036 :hg:`commit --close-branch` to mark this branch head as closed.
1037 When all heads of a branch are closed, the branch will be
1037 When all heads of a branch are closed, the branch will be
1038 considered closed.
1038 considered closed.
1039
1039
1040 Returns 0 on success.
1040 Returns 0 on success.
1041 """
1041 """
1042 opts = pycompat.byteskwargs(opts)
1042 opts = pycompat.byteskwargs(opts)
1043 revs = opts.get('rev')
1043 revs = opts.get('rev')
1044 if label:
1044 if label:
1045 label = label.strip()
1045 label = label.strip()
1046
1046
1047 if not opts.get('clean') and not label:
1047 if not opts.get('clean') and not label:
1048 if revs:
1048 if revs:
1049 raise error.Abort(_("no branch name specified for the revisions"))
1049 raise error.Abort(_("no branch name specified for the revisions"))
1050 ui.write("%s\n" % repo.dirstate.branch())
1050 ui.write("%s\n" % repo.dirstate.branch())
1051 return
1051 return
1052
1052
1053 with repo.wlock():
1053 with repo.wlock():
1054 if opts.get('clean'):
1054 if opts.get('clean'):
1055 label = repo[None].p1().branch()
1055 label = repo[None].p1().branch()
1056 repo.dirstate.setbranch(label)
1056 repo.dirstate.setbranch(label)
1057 ui.status(_('reset working directory to branch %s\n') % label)
1057 ui.status(_('reset working directory to branch %s\n') % label)
1058 elif label:
1058 elif label:
1059
1059
1060 scmutil.checknewlabel(repo, label, 'branch')
1060 scmutil.checknewlabel(repo, label, 'branch')
1061 if revs:
1061 if revs:
1062 return cmdutil.changebranch(ui, repo, revs, label)
1062 return cmdutil.changebranch(ui, repo, revs, label)
1063
1063
1064 if not opts.get('force') and label in repo.branchmap():
1064 if not opts.get('force') and label in repo.branchmap():
1065 if label not in [p.branch() for p in repo[None].parents()]:
1065 if label not in [p.branch() for p in repo[None].parents()]:
1066 raise error.Abort(_('a branch of the same name already'
1066 raise error.Abort(_('a branch of the same name already'
1067 ' exists'),
1067 ' exists'),
1068 # i18n: "it" refers to an existing branch
1068 # i18n: "it" refers to an existing branch
1069 hint=_("use 'hg update' to switch to it"))
1069 hint=_("use 'hg update' to switch to it"))
1070
1070
1071 repo.dirstate.setbranch(label)
1071 repo.dirstate.setbranch(label)
1072 ui.status(_('marked working directory as branch %s\n') % label)
1072 ui.status(_('marked working directory as branch %s\n') % label)
1073
1073
1074 # find any open named branches aside from default
1074 # find any open named branches aside from default
1075 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1075 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1076 if n != "default" and not c]
1076 if n != "default" and not c]
1077 if not others:
1077 if not others:
1078 ui.status(_('(branches are permanent and global, '
1078 ui.status(_('(branches are permanent and global, '
1079 'did you want a bookmark?)\n'))
1079 'did you want a bookmark?)\n'))
1080
1080
1081 @command('branches',
1081 @command('branches',
1082 [('a', 'active', False,
1082 [('a', 'active', False,
1083 _('show only branches that have unmerged heads (DEPRECATED)')),
1083 _('show only branches that have unmerged heads (DEPRECATED)')),
1084 ('c', 'closed', False, _('show normal and closed branches')),
1084 ('c', 'closed', False, _('show normal and closed branches')),
1085 ] + formatteropts,
1085 ] + formatteropts,
1086 _('[-c]'), cmdtype=readonly)
1086 _('[-c]'), cmdtype=readonly)
1087 def branches(ui, repo, active=False, closed=False, **opts):
1087 def branches(ui, repo, active=False, closed=False, **opts):
1088 """list repository named branches
1088 """list repository named branches
1089
1089
1090 List the repository's named branches, indicating which ones are
1090 List the repository's named branches, indicating which ones are
1091 inactive. If -c/--closed is specified, also list branches which have
1091 inactive. If -c/--closed is specified, also list branches which have
1092 been marked closed (see :hg:`commit --close-branch`).
1092 been marked closed (see :hg:`commit --close-branch`).
1093
1093
1094 Use the command :hg:`update` to switch to an existing branch.
1094 Use the command :hg:`update` to switch to an existing branch.
1095
1095
1096 Returns 0.
1096 Returns 0.
1097 """
1097 """
1098
1098
1099 opts = pycompat.byteskwargs(opts)
1099 opts = pycompat.byteskwargs(opts)
1100 ui.pager('branches')
1100 ui.pager('branches')
1101 fm = ui.formatter('branches', opts)
1101 fm = ui.formatter('branches', opts)
1102 hexfunc = fm.hexfunc
1102 hexfunc = fm.hexfunc
1103
1103
1104 allheads = set(repo.heads())
1104 allheads = set(repo.heads())
1105 branches = []
1105 branches = []
1106 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1106 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1107 isactive = False
1107 isactive = False
1108 if not isclosed:
1108 if not isclosed:
1109 openheads = set(repo.branchmap().iteropen(heads))
1109 openheads = set(repo.branchmap().iteropen(heads))
1110 isactive = bool(openheads & allheads)
1110 isactive = bool(openheads & allheads)
1111 branches.append((tag, repo[tip], isactive, not isclosed))
1111 branches.append((tag, repo[tip], isactive, not isclosed))
1112 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1112 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1113 reverse=True)
1113 reverse=True)
1114
1114
1115 for tag, ctx, isactive, isopen in branches:
1115 for tag, ctx, isactive, isopen in branches:
1116 if active and not isactive:
1116 if active and not isactive:
1117 continue
1117 continue
1118 if isactive:
1118 if isactive:
1119 label = 'branches.active'
1119 label = 'branches.active'
1120 notice = ''
1120 notice = ''
1121 elif not isopen:
1121 elif not isopen:
1122 if not closed:
1122 if not closed:
1123 continue
1123 continue
1124 label = 'branches.closed'
1124 label = 'branches.closed'
1125 notice = _(' (closed)')
1125 notice = _(' (closed)')
1126 else:
1126 else:
1127 label = 'branches.inactive'
1127 label = 'branches.inactive'
1128 notice = _(' (inactive)')
1128 notice = _(' (inactive)')
1129 current = (tag == repo.dirstate.branch())
1129 current = (tag == repo.dirstate.branch())
1130 if current:
1130 if current:
1131 label = 'branches.current'
1131 label = 'branches.current'
1132
1132
1133 fm.startitem()
1133 fm.startitem()
1134 fm.write('branch', '%s', tag, label=label)
1134 fm.write('branch', '%s', tag, label=label)
1135 rev = ctx.rev()
1135 rev = ctx.rev()
1136 padsize = max(31 - len("%d" % rev) - encoding.colwidth(tag), 0)
1136 padsize = max(31 - len("%d" % rev) - encoding.colwidth(tag), 0)
1137 fmt = ' ' * padsize + ' %d:%s'
1137 fmt = ' ' * padsize + ' %d:%s'
1138 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1138 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1139 label='log.changeset changeset.%s' % ctx.phasestr())
1139 label='log.changeset changeset.%s' % ctx.phasestr())
1140 fm.context(ctx=ctx)
1140 fm.context(ctx=ctx)
1141 fm.data(active=isactive, closed=not isopen, current=current)
1141 fm.data(active=isactive, closed=not isopen, current=current)
1142 if not ui.quiet:
1142 if not ui.quiet:
1143 fm.plain(notice)
1143 fm.plain(notice)
1144 fm.plain('\n')
1144 fm.plain('\n')
1145 fm.end()
1145 fm.end()
1146
1146
1147 @command('bundle',
1147 @command('bundle',
1148 [('f', 'force', None, _('run even when the destination is unrelated')),
1148 [('f', 'force', None, _('run even when the destination is unrelated')),
1149 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1149 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1150 _('REV')),
1150 _('REV')),
1151 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1151 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1152 _('BRANCH')),
1152 _('BRANCH')),
1153 ('', 'base', [],
1153 ('', 'base', [],
1154 _('a base changeset assumed to be available at the destination'),
1154 _('a base changeset assumed to be available at the destination'),
1155 _('REV')),
1155 _('REV')),
1156 ('a', 'all', None, _('bundle all changesets in the repository')),
1156 ('a', 'all', None, _('bundle all changesets in the repository')),
1157 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1157 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1158 ] + remoteopts,
1158 ] + remoteopts,
1159 _('[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1159 _('[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1160 def bundle(ui, repo, fname, dest=None, **opts):
1160 def bundle(ui, repo, fname, dest=None, **opts):
1161 """create a bundle file
1161 """create a bundle file
1162
1162
1163 Generate a bundle file containing data to be transferred to another
1163 Generate a bundle file containing data to be transferred to another
1164 repository.
1164 repository.
1165
1165
1166 To create a bundle containing all changesets, use -a/--all
1166 To create a bundle containing all changesets, use -a/--all
1167 (or --base null). Otherwise, hg assumes the destination will have
1167 (or --base null). Otherwise, hg assumes the destination will have
1168 all the nodes you specify with --base parameters. Otherwise, hg
1168 all the nodes you specify with --base parameters. Otherwise, hg
1169 will assume the repository has all the nodes in destination, or
1169 will assume the repository has all the nodes in destination, or
1170 default-push/default if no destination is specified, where destination
1170 default-push/default if no destination is specified, where destination
1171 is the repository you provide through DEST option.
1171 is the repository you provide through DEST option.
1172
1172
1173 You can change bundle format with the -t/--type option. See
1173 You can change bundle format with the -t/--type option. See
1174 :hg:`help bundlespec` for documentation on this format. By default,
1174 :hg:`help bundlespec` for documentation on this format. By default,
1175 the most appropriate format is used and compression defaults to
1175 the most appropriate format is used and compression defaults to
1176 bzip2.
1176 bzip2.
1177
1177
1178 The bundle file can then be transferred using conventional means
1178 The bundle file can then be transferred using conventional means
1179 and applied to another repository with the unbundle or pull
1179 and applied to another repository with the unbundle or pull
1180 command. This is useful when direct push and pull are not
1180 command. This is useful when direct push and pull are not
1181 available or when exporting an entire repository is undesirable.
1181 available or when exporting an entire repository is undesirable.
1182
1182
1183 Applying bundles preserves all changeset contents including
1183 Applying bundles preserves all changeset contents including
1184 permissions, copy/rename information, and revision history.
1184 permissions, copy/rename information, and revision history.
1185
1185
1186 Returns 0 on success, 1 if no changes found.
1186 Returns 0 on success, 1 if no changes found.
1187 """
1187 """
1188 opts = pycompat.byteskwargs(opts)
1188 opts = pycompat.byteskwargs(opts)
1189 revs = None
1189 revs = None
1190 if 'rev' in opts:
1190 if 'rev' in opts:
1191 revstrings = opts['rev']
1191 revstrings = opts['rev']
1192 revs = scmutil.revrange(repo, revstrings)
1192 revs = scmutil.revrange(repo, revstrings)
1193 if revstrings and not revs:
1193 if revstrings and not revs:
1194 raise error.Abort(_('no commits to bundle'))
1194 raise error.Abort(_('no commits to bundle'))
1195
1195
1196 bundletype = opts.get('type', 'bzip2').lower()
1196 bundletype = opts.get('type', 'bzip2').lower()
1197 try:
1197 try:
1198 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1198 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1199 except error.UnsupportedBundleSpecification as e:
1199 except error.UnsupportedBundleSpecification as e:
1200 raise error.Abort(pycompat.bytestr(e),
1200 raise error.Abort(pycompat.bytestr(e),
1201 hint=_("see 'hg help bundlespec' for supported "
1201 hint=_("see 'hg help bundlespec' for supported "
1202 "values for --type"))
1202 "values for --type"))
1203 cgversion = bundlespec.contentopts["cg.version"]
1203 cgversion = bundlespec.contentopts["cg.version"]
1204
1204
1205 # Packed bundles are a pseudo bundle format for now.
1205 # Packed bundles are a pseudo bundle format for now.
1206 if cgversion == 's1':
1206 if cgversion == 's1':
1207 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1207 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1208 hint=_("use 'hg debugcreatestreamclonebundle'"))
1208 hint=_("use 'hg debugcreatestreamclonebundle'"))
1209
1209
1210 if opts.get('all'):
1210 if opts.get('all'):
1211 if dest:
1211 if dest:
1212 raise error.Abort(_("--all is incompatible with specifying "
1212 raise error.Abort(_("--all is incompatible with specifying "
1213 "a destination"))
1213 "a destination"))
1214 if opts.get('base'):
1214 if opts.get('base'):
1215 ui.warn(_("ignoring --base because --all was specified\n"))
1215 ui.warn(_("ignoring --base because --all was specified\n"))
1216 base = ['null']
1216 base = ['null']
1217 else:
1217 else:
1218 base = scmutil.revrange(repo, opts.get('base'))
1218 base = scmutil.revrange(repo, opts.get('base'))
1219 if cgversion not in changegroup.supportedoutgoingversions(repo):
1219 if cgversion not in changegroup.supportedoutgoingversions(repo):
1220 raise error.Abort(_("repository does not support bundle version %s") %
1220 raise error.Abort(_("repository does not support bundle version %s") %
1221 cgversion)
1221 cgversion)
1222
1222
1223 if base:
1223 if base:
1224 if dest:
1224 if dest:
1225 raise error.Abort(_("--base is incompatible with specifying "
1225 raise error.Abort(_("--base is incompatible with specifying "
1226 "a destination"))
1226 "a destination"))
1227 common = [repo[rev].node() for rev in base]
1227 common = [repo[rev].node() for rev in base]
1228 heads = [repo[r].node() for r in revs] if revs else None
1228 heads = [repo[r].node() for r in revs] if revs else None
1229 outgoing = discovery.outgoing(repo, common, heads)
1229 outgoing = discovery.outgoing(repo, common, heads)
1230 else:
1230 else:
1231 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1231 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1232 dest, branches = hg.parseurl(dest, opts.get('branch'))
1232 dest, branches = hg.parseurl(dest, opts.get('branch'))
1233 other = hg.peer(repo, opts, dest)
1233 other = hg.peer(repo, opts, dest)
1234 revs = [repo[r].hex() for r in revs]
1234 revs = [repo[r].hex() for r in revs]
1235 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1235 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1236 heads = revs and map(repo.lookup, revs) or revs
1236 heads = revs and map(repo.lookup, revs) or revs
1237 outgoing = discovery.findcommonoutgoing(repo, other,
1237 outgoing = discovery.findcommonoutgoing(repo, other,
1238 onlyheads=heads,
1238 onlyheads=heads,
1239 force=opts.get('force'),
1239 force=opts.get('force'),
1240 portable=True)
1240 portable=True)
1241
1241
1242 if not outgoing.missing:
1242 if not outgoing.missing:
1243 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1243 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1244 return 1
1244 return 1
1245
1245
1246 bcompression = bundlespec.compression
1246 bcompression = bundlespec.compression
1247 if cgversion == '01': #bundle1
1247 if cgversion == '01': #bundle1
1248 if bcompression is None:
1248 if bcompression is None:
1249 bcompression = 'UN'
1249 bcompression = 'UN'
1250 bversion = 'HG10' + bcompression
1250 bversion = 'HG10' + bcompression
1251 bcompression = None
1251 bcompression = None
1252 elif cgversion in ('02', '03'):
1252 elif cgversion in ('02', '03'):
1253 bversion = 'HG20'
1253 bversion = 'HG20'
1254 else:
1254 else:
1255 raise error.ProgrammingError(
1255 raise error.ProgrammingError(
1256 'bundle: unexpected changegroup version %s' % cgversion)
1256 'bundle: unexpected changegroup version %s' % cgversion)
1257
1257
1258 # TODO compression options should be derived from bundlespec parsing.
1258 # TODO compression options should be derived from bundlespec parsing.
1259 # This is a temporary hack to allow adjusting bundle compression
1259 # This is a temporary hack to allow adjusting bundle compression
1260 # level without a) formalizing the bundlespec changes to declare it
1260 # level without a) formalizing the bundlespec changes to declare it
1261 # b) introducing a command flag.
1261 # b) introducing a command flag.
1262 compopts = {}
1262 compopts = {}
1263 complevel = ui.configint('experimental', 'bundlecomplevel')
1263 complevel = ui.configint('experimental', 'bundlecomplevel')
1264 if complevel is not None:
1264 if complevel is not None:
1265 compopts['level'] = complevel
1265 compopts['level'] = complevel
1266
1266
1267 # Allow overriding the bundling of obsmarker in phases through
1267 # Allow overriding the bundling of obsmarker in phases through
1268 # configuration while we don't have a bundle version that include them
1268 # configuration while we don't have a bundle version that include them
1269 if repo.ui.configbool('experimental', 'evolution.bundle-obsmarker'):
1269 if repo.ui.configbool('experimental', 'evolution.bundle-obsmarker'):
1270 bundlespec.contentopts['obsolescence'] = True
1270 bundlespec.contentopts['obsolescence'] = True
1271 if repo.ui.configbool('experimental', 'bundle-phases'):
1271 if repo.ui.configbool('experimental', 'bundle-phases'):
1272 bundlespec.contentopts['phases'] = True
1272 bundlespec.contentopts['phases'] = True
1273
1273
1274 bundle2.writenewbundle(ui, repo, 'bundle', fname, bversion, outgoing,
1274 bundle2.writenewbundle(ui, repo, 'bundle', fname, bversion, outgoing,
1275 bundlespec.contentopts, compression=bcompression,
1275 bundlespec.contentopts, compression=bcompression,
1276 compopts=compopts)
1276 compopts=compopts)
1277
1277
1278 @command('cat',
1278 @command('cat',
1279 [('o', 'output', '',
1279 [('o', 'output', '',
1280 _('print output to file with formatted name'), _('FORMAT')),
1280 _('print output to file with formatted name'), _('FORMAT')),
1281 ('r', 'rev', '', _('print the given revision'), _('REV')),
1281 ('r', 'rev', '', _('print the given revision'), _('REV')),
1282 ('', 'decode', None, _('apply any matching decode filter')),
1282 ('', 'decode', None, _('apply any matching decode filter')),
1283 ] + walkopts + formatteropts,
1283 ] + walkopts + formatteropts,
1284 _('[OPTION]... FILE...'),
1284 _('[OPTION]... FILE...'),
1285 inferrepo=True, cmdtype=readonly)
1285 inferrepo=True, cmdtype=readonly)
1286 def cat(ui, repo, file1, *pats, **opts):
1286 def cat(ui, repo, file1, *pats, **opts):
1287 """output the current or given revision of files
1287 """output the current or given revision of files
1288
1288
1289 Print the specified files as they were at the given revision. If
1289 Print the specified files as they were at the given revision. If
1290 no revision is given, the parent of the working directory is used.
1290 no revision is given, the parent of the working directory is used.
1291
1291
1292 Output may be to a file, in which case the name of the file is
1292 Output may be to a file, in which case the name of the file is
1293 given using a template string. See :hg:`help templates`. In addition
1293 given using a template string. See :hg:`help templates`. In addition
1294 to the common template keywords, the following formatting rules are
1294 to the common template keywords, the following formatting rules are
1295 supported:
1295 supported:
1296
1296
1297 :``%%``: literal "%" character
1297 :``%%``: literal "%" character
1298 :``%s``: basename of file being printed
1298 :``%s``: basename of file being printed
1299 :``%d``: dirname of file being printed, or '.' if in repository root
1299 :``%d``: dirname of file being printed, or '.' if in repository root
1300 :``%p``: root-relative path name of file being printed
1300 :``%p``: root-relative path name of file being printed
1301 :``%H``: changeset hash (40 hexadecimal digits)
1301 :``%H``: changeset hash (40 hexadecimal digits)
1302 :``%R``: changeset revision number
1302 :``%R``: changeset revision number
1303 :``%h``: short-form changeset hash (12 hexadecimal digits)
1303 :``%h``: short-form changeset hash (12 hexadecimal digits)
1304 :``%r``: zero-padded changeset revision number
1304 :``%r``: zero-padded changeset revision number
1305 :``%b``: basename of the exporting repository
1305 :``%b``: basename of the exporting repository
1306 :``\\``: literal "\\" character
1306 :``\\``: literal "\\" character
1307
1307
1308 Returns 0 on success.
1308 Returns 0 on success.
1309 """
1309 """
1310 opts = pycompat.byteskwargs(opts)
1310 opts = pycompat.byteskwargs(opts)
1311 rev = opts.get('rev')
1311 rev = opts.get('rev')
1312 if rev:
1312 if rev:
1313 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
1313 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
1314 ctx = scmutil.revsingle(repo, rev)
1314 ctx = scmutil.revsingle(repo, rev)
1315 m = scmutil.match(ctx, (file1,) + pats, opts)
1315 m = scmutil.match(ctx, (file1,) + pats, opts)
1316 fntemplate = opts.pop('output', '')
1316 fntemplate = opts.pop('output', '')
1317 if cmdutil.isstdiofilename(fntemplate):
1317 if cmdutil.isstdiofilename(fntemplate):
1318 fntemplate = ''
1318 fntemplate = ''
1319
1319
1320 if fntemplate:
1320 if fntemplate:
1321 fm = formatter.nullformatter(ui, 'cat')
1321 fm = formatter.nullformatter(ui, 'cat')
1322 else:
1322 else:
1323 ui.pager('cat')
1323 ui.pager('cat')
1324 fm = ui.formatter('cat', opts)
1324 fm = ui.formatter('cat', opts)
1325 with fm:
1325 with fm:
1326 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, '',
1326 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, '',
1327 **pycompat.strkwargs(opts))
1327 **pycompat.strkwargs(opts))
1328
1328
1329 @command('^clone',
1329 @command('^clone',
1330 [('U', 'noupdate', None, _('the clone will include an empty working '
1330 [('U', 'noupdate', None, _('the clone will include an empty working '
1331 'directory (only a repository)')),
1331 'directory (only a repository)')),
1332 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1332 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1333 _('REV')),
1333 _('REV')),
1334 ('r', 'rev', [], _('do not clone everything, but include this changeset'
1334 ('r', 'rev', [], _('do not clone everything, but include this changeset'
1335 ' and its ancestors'), _('REV')),
1335 ' and its ancestors'), _('REV')),
1336 ('b', 'branch', [], _('do not clone everything, but include this branch\'s'
1336 ('b', 'branch', [], _('do not clone everything, but include this branch\'s'
1337 ' changesets and their ancestors'), _('BRANCH')),
1337 ' changesets and their ancestors'), _('BRANCH')),
1338 ('', 'pull', None, _('use pull protocol to copy metadata')),
1338 ('', 'pull', None, _('use pull protocol to copy metadata')),
1339 ('', 'uncompressed', None,
1339 ('', 'uncompressed', None,
1340 _('an alias to --stream (DEPRECATED)')),
1340 _('an alias to --stream (DEPRECATED)')),
1341 ('', 'stream', None,
1341 ('', 'stream', None,
1342 _('clone with minimal data processing')),
1342 _('clone with minimal data processing')),
1343 ] + remoteopts,
1343 ] + remoteopts,
1344 _('[OPTION]... SOURCE [DEST]'),
1344 _('[OPTION]... SOURCE [DEST]'),
1345 norepo=True)
1345 norepo=True)
1346 def clone(ui, source, dest=None, **opts):
1346 def clone(ui, source, dest=None, **opts):
1347 """make a copy of an existing repository
1347 """make a copy of an existing repository
1348
1348
1349 Create a copy of an existing repository in a new directory.
1349 Create a copy of an existing repository in a new directory.
1350
1350
1351 If no destination directory name is specified, it defaults to the
1351 If no destination directory name is specified, it defaults to the
1352 basename of the source.
1352 basename of the source.
1353
1353
1354 The location of the source is added to the new repository's
1354 The location of the source is added to the new repository's
1355 ``.hg/hgrc`` file, as the default to be used for future pulls.
1355 ``.hg/hgrc`` file, as the default to be used for future pulls.
1356
1356
1357 Only local paths and ``ssh://`` URLs are supported as
1357 Only local paths and ``ssh://`` URLs are supported as
1358 destinations. For ``ssh://`` destinations, no working directory or
1358 destinations. For ``ssh://`` destinations, no working directory or
1359 ``.hg/hgrc`` will be created on the remote side.
1359 ``.hg/hgrc`` will be created on the remote side.
1360
1360
1361 If the source repository has a bookmark called '@' set, that
1361 If the source repository has a bookmark called '@' set, that
1362 revision will be checked out in the new repository by default.
1362 revision will be checked out in the new repository by default.
1363
1363
1364 To check out a particular version, use -u/--update, or
1364 To check out a particular version, use -u/--update, or
1365 -U/--noupdate to create a clone with no working directory.
1365 -U/--noupdate to create a clone with no working directory.
1366
1366
1367 To pull only a subset of changesets, specify one or more revisions
1367 To pull only a subset of changesets, specify one or more revisions
1368 identifiers with -r/--rev or branches with -b/--branch. The
1368 identifiers with -r/--rev or branches with -b/--branch. The
1369 resulting clone will contain only the specified changesets and
1369 resulting clone will contain only the specified changesets and
1370 their ancestors. These options (or 'clone src#rev dest') imply
1370 their ancestors. These options (or 'clone src#rev dest') imply
1371 --pull, even for local source repositories.
1371 --pull, even for local source repositories.
1372
1372
1373 In normal clone mode, the remote normalizes repository data into a common
1373 In normal clone mode, the remote normalizes repository data into a common
1374 exchange format and the receiving end translates this data into its local
1374 exchange format and the receiving end translates this data into its local
1375 storage format. --stream activates a different clone mode that essentially
1375 storage format. --stream activates a different clone mode that essentially
1376 copies repository files from the remote with minimal data processing. This
1376 copies repository files from the remote with minimal data processing. This
1377 significantly reduces the CPU cost of a clone both remotely and locally.
1377 significantly reduces the CPU cost of a clone both remotely and locally.
1378 However, it often increases the transferred data size by 30-40%. This can
1378 However, it often increases the transferred data size by 30-40%. This can
1379 result in substantially faster clones where I/O throughput is plentiful,
1379 result in substantially faster clones where I/O throughput is plentiful,
1380 especially for larger repositories. A side-effect of --stream clones is
1380 especially for larger repositories. A side-effect of --stream clones is
1381 that storage settings and requirements on the remote are applied locally:
1381 that storage settings and requirements on the remote are applied locally:
1382 a modern client may inherit legacy or inefficient storage used by the
1382 a modern client may inherit legacy or inefficient storage used by the
1383 remote or a legacy Mercurial client may not be able to clone from a
1383 remote or a legacy Mercurial client may not be able to clone from a
1384 modern Mercurial remote.
1384 modern Mercurial remote.
1385
1385
1386 .. note::
1386 .. note::
1387
1387
1388 Specifying a tag will include the tagged changeset but not the
1388 Specifying a tag will include the tagged changeset but not the
1389 changeset containing the tag.
1389 changeset containing the tag.
1390
1390
1391 .. container:: verbose
1391 .. container:: verbose
1392
1392
1393 For efficiency, hardlinks are used for cloning whenever the
1393 For efficiency, hardlinks are used for cloning whenever the
1394 source and destination are on the same filesystem (note this
1394 source and destination are on the same filesystem (note this
1395 applies only to the repository data, not to the working
1395 applies only to the repository data, not to the working
1396 directory). Some filesystems, such as AFS, implement hardlinking
1396 directory). Some filesystems, such as AFS, implement hardlinking
1397 incorrectly, but do not report errors. In these cases, use the
1397 incorrectly, but do not report errors. In these cases, use the
1398 --pull option to avoid hardlinking.
1398 --pull option to avoid hardlinking.
1399
1399
1400 Mercurial will update the working directory to the first applicable
1400 Mercurial will update the working directory to the first applicable
1401 revision from this list:
1401 revision from this list:
1402
1402
1403 a) null if -U or the source repository has no changesets
1403 a) null if -U or the source repository has no changesets
1404 b) if -u . and the source repository is local, the first parent of
1404 b) if -u . and the source repository is local, the first parent of
1405 the source repository's working directory
1405 the source repository's working directory
1406 c) the changeset specified with -u (if a branch name, this means the
1406 c) the changeset specified with -u (if a branch name, this means the
1407 latest head of that branch)
1407 latest head of that branch)
1408 d) the changeset specified with -r
1408 d) the changeset specified with -r
1409 e) the tipmost head specified with -b
1409 e) the tipmost head specified with -b
1410 f) the tipmost head specified with the url#branch source syntax
1410 f) the tipmost head specified with the url#branch source syntax
1411 g) the revision marked with the '@' bookmark, if present
1411 g) the revision marked with the '@' bookmark, if present
1412 h) the tipmost head of the default branch
1412 h) the tipmost head of the default branch
1413 i) tip
1413 i) tip
1414
1414
1415 When cloning from servers that support it, Mercurial may fetch
1415 When cloning from servers that support it, Mercurial may fetch
1416 pre-generated data from a server-advertised URL. When this is done,
1416 pre-generated data from a server-advertised URL. When this is done,
1417 hooks operating on incoming changesets and changegroups may fire twice,
1417 hooks operating on incoming changesets and changegroups may fire twice,
1418 once for the bundle fetched from the URL and another for any additional
1418 once for the bundle fetched from the URL and another for any additional
1419 data not fetched from this URL. In addition, if an error occurs, the
1419 data not fetched from this URL. In addition, if an error occurs, the
1420 repository may be rolled back to a partial clone. This behavior may
1420 repository may be rolled back to a partial clone. This behavior may
1421 change in future releases. See :hg:`help -e clonebundles` for more.
1421 change in future releases. See :hg:`help -e clonebundles` for more.
1422
1422
1423 Examples:
1423 Examples:
1424
1424
1425 - clone a remote repository to a new directory named hg/::
1425 - clone a remote repository to a new directory named hg/::
1426
1426
1427 hg clone https://www.mercurial-scm.org/repo/hg/
1427 hg clone https://www.mercurial-scm.org/repo/hg/
1428
1428
1429 - create a lightweight local clone::
1429 - create a lightweight local clone::
1430
1430
1431 hg clone project/ project-feature/
1431 hg clone project/ project-feature/
1432
1432
1433 - clone from an absolute path on an ssh server (note double-slash)::
1433 - clone from an absolute path on an ssh server (note double-slash)::
1434
1434
1435 hg clone ssh://user@server//home/projects/alpha/
1435 hg clone ssh://user@server//home/projects/alpha/
1436
1436
1437 - do a streaming clone while checking out a specified version::
1437 - do a streaming clone while checking out a specified version::
1438
1438
1439 hg clone --stream http://server/repo -u 1.5
1439 hg clone --stream http://server/repo -u 1.5
1440
1440
1441 - create a repository without changesets after a particular revision::
1441 - create a repository without changesets after a particular revision::
1442
1442
1443 hg clone -r 04e544 experimental/ good/
1443 hg clone -r 04e544 experimental/ good/
1444
1444
1445 - clone (and track) a particular named branch::
1445 - clone (and track) a particular named branch::
1446
1446
1447 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1447 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1448
1448
1449 See :hg:`help urls` for details on specifying URLs.
1449 See :hg:`help urls` for details on specifying URLs.
1450
1450
1451 Returns 0 on success.
1451 Returns 0 on success.
1452 """
1452 """
1453 opts = pycompat.byteskwargs(opts)
1453 opts = pycompat.byteskwargs(opts)
1454 if opts.get('noupdate') and opts.get('updaterev'):
1454 if opts.get('noupdate') and opts.get('updaterev'):
1455 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1455 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1456
1456
1457 r = hg.clone(ui, opts, source, dest,
1457 r = hg.clone(ui, opts, source, dest,
1458 pull=opts.get('pull'),
1458 pull=opts.get('pull'),
1459 stream=opts.get('stream') or opts.get('uncompressed'),
1459 stream=opts.get('stream') or opts.get('uncompressed'),
1460 revs=opts.get('rev'),
1460 revs=opts.get('rev'),
1461 update=opts.get('updaterev') or not opts.get('noupdate'),
1461 update=opts.get('updaterev') or not opts.get('noupdate'),
1462 branch=opts.get('branch'),
1462 branch=opts.get('branch'),
1463 shareopts=opts.get('shareopts'))
1463 shareopts=opts.get('shareopts'))
1464
1464
1465 return r is None
1465 return r is None
1466
1466
1467 @command('^commit|ci',
1467 @command('^commit|ci',
1468 [('A', 'addremove', None,
1468 [('A', 'addremove', None,
1469 _('mark new/missing files as added/removed before committing')),
1469 _('mark new/missing files as added/removed before committing')),
1470 ('', 'close-branch', None,
1470 ('', 'close-branch', None,
1471 _('mark a branch head as closed')),
1471 _('mark a branch head as closed')),
1472 ('', 'amend', None, _('amend the parent of the working directory')),
1472 ('', 'amend', None, _('amend the parent of the working directory')),
1473 ('s', 'secret', None, _('use the secret phase for committing')),
1473 ('s', 'secret', None, _('use the secret phase for committing')),
1474 ('e', 'edit', None, _('invoke editor on commit messages')),
1474 ('e', 'edit', None, _('invoke editor on commit messages')),
1475 ('i', 'interactive', None, _('use interactive mode')),
1475 ('i', 'interactive', None, _('use interactive mode')),
1476 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1476 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1477 _('[OPTION]... [FILE]...'),
1477 _('[OPTION]... [FILE]...'),
1478 inferrepo=True)
1478 inferrepo=True)
1479 def commit(ui, repo, *pats, **opts):
1479 def commit(ui, repo, *pats, **opts):
1480 """commit the specified files or all outstanding changes
1480 """commit the specified files or all outstanding changes
1481
1481
1482 Commit changes to the given files into the repository. Unlike a
1482 Commit changes to the given files into the repository. Unlike a
1483 centralized SCM, this operation is a local operation. See
1483 centralized SCM, this operation is a local operation. See
1484 :hg:`push` for a way to actively distribute your changes.
1484 :hg:`push` for a way to actively distribute your changes.
1485
1485
1486 If a list of files is omitted, all changes reported by :hg:`status`
1486 If a list of files is omitted, all changes reported by :hg:`status`
1487 will be committed.
1487 will be committed.
1488
1488
1489 If you are committing the result of a merge, do not provide any
1489 If you are committing the result of a merge, do not provide any
1490 filenames or -I/-X filters.
1490 filenames or -I/-X filters.
1491
1491
1492 If no commit message is specified, Mercurial starts your
1492 If no commit message is specified, Mercurial starts your
1493 configured editor where you can enter a message. In case your
1493 configured editor where you can enter a message. In case your
1494 commit fails, you will find a backup of your message in
1494 commit fails, you will find a backup of your message in
1495 ``.hg/last-message.txt``.
1495 ``.hg/last-message.txt``.
1496
1496
1497 The --close-branch flag can be used to mark the current branch
1497 The --close-branch flag can be used to mark the current branch
1498 head closed. When all heads of a branch are closed, the branch
1498 head closed. When all heads of a branch are closed, the branch
1499 will be considered closed and no longer listed.
1499 will be considered closed and no longer listed.
1500
1500
1501 The --amend flag can be used to amend the parent of the
1501 The --amend flag can be used to amend the parent of the
1502 working directory with a new commit that contains the changes
1502 working directory with a new commit that contains the changes
1503 in the parent in addition to those currently reported by :hg:`status`,
1503 in the parent in addition to those currently reported by :hg:`status`,
1504 if there are any. The old commit is stored in a backup bundle in
1504 if there are any. The old commit is stored in a backup bundle in
1505 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1505 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1506 on how to restore it).
1506 on how to restore it).
1507
1507
1508 Message, user and date are taken from the amended commit unless
1508 Message, user and date are taken from the amended commit unless
1509 specified. When a message isn't specified on the command line,
1509 specified. When a message isn't specified on the command line,
1510 the editor will open with the message of the amended commit.
1510 the editor will open with the message of the amended commit.
1511
1511
1512 It is not possible to amend public changesets (see :hg:`help phases`)
1512 It is not possible to amend public changesets (see :hg:`help phases`)
1513 or changesets that have children.
1513 or changesets that have children.
1514
1514
1515 See :hg:`help dates` for a list of formats valid for -d/--date.
1515 See :hg:`help dates` for a list of formats valid for -d/--date.
1516
1516
1517 Returns 0 on success, 1 if nothing changed.
1517 Returns 0 on success, 1 if nothing changed.
1518
1518
1519 .. container:: verbose
1519 .. container:: verbose
1520
1520
1521 Examples:
1521 Examples:
1522
1522
1523 - commit all files ending in .py::
1523 - commit all files ending in .py::
1524
1524
1525 hg commit --include "set:**.py"
1525 hg commit --include "set:**.py"
1526
1526
1527 - commit all non-binary files::
1527 - commit all non-binary files::
1528
1528
1529 hg commit --exclude "set:binary()"
1529 hg commit --exclude "set:binary()"
1530
1530
1531 - amend the current commit and set the date to now::
1531 - amend the current commit and set the date to now::
1532
1532
1533 hg commit --amend --date now
1533 hg commit --amend --date now
1534 """
1534 """
1535 wlock = lock = None
1535 wlock = lock = None
1536 try:
1536 try:
1537 wlock = repo.wlock()
1537 wlock = repo.wlock()
1538 lock = repo.lock()
1538 lock = repo.lock()
1539 return _docommit(ui, repo, *pats, **opts)
1539 return _docommit(ui, repo, *pats, **opts)
1540 finally:
1540 finally:
1541 release(lock, wlock)
1541 release(lock, wlock)
1542
1542
1543 def _docommit(ui, repo, *pats, **opts):
1543 def _docommit(ui, repo, *pats, **opts):
1544 if opts.get(r'interactive'):
1544 if opts.get(r'interactive'):
1545 opts.pop(r'interactive')
1545 opts.pop(r'interactive')
1546 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1546 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1547 cmdutil.recordfilter, *pats,
1547 cmdutil.recordfilter, *pats,
1548 **opts)
1548 **opts)
1549 # ret can be 0 (no changes to record) or the value returned by
1549 # ret can be 0 (no changes to record) or the value returned by
1550 # commit(), 1 if nothing changed or None on success.
1550 # commit(), 1 if nothing changed or None on success.
1551 return 1 if ret == 0 else ret
1551 return 1 if ret == 0 else ret
1552
1552
1553 opts = pycompat.byteskwargs(opts)
1553 opts = pycompat.byteskwargs(opts)
1554 if opts.get('subrepos'):
1554 if opts.get('subrepos'):
1555 if opts.get('amend'):
1555 if opts.get('amend'):
1556 raise error.Abort(_('cannot amend with --subrepos'))
1556 raise error.Abort(_('cannot amend with --subrepos'))
1557 # Let --subrepos on the command line override config setting.
1557 # Let --subrepos on the command line override config setting.
1558 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1558 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1559
1559
1560 cmdutil.checkunfinished(repo, commit=True)
1560 cmdutil.checkunfinished(repo, commit=True)
1561
1561
1562 branch = repo[None].branch()
1562 branch = repo[None].branch()
1563 bheads = repo.branchheads(branch)
1563 bheads = repo.branchheads(branch)
1564
1564
1565 extra = {}
1565 extra = {}
1566 if opts.get('close_branch'):
1566 if opts.get('close_branch'):
1567 extra['close'] = '1'
1567 extra['close'] = '1'
1568
1568
1569 if not bheads:
1569 if not bheads:
1570 raise error.Abort(_('can only close branch heads'))
1570 raise error.Abort(_('can only close branch heads'))
1571 elif opts.get('amend'):
1571 elif opts.get('amend'):
1572 if repo[None].parents()[0].p1().branch() != branch and \
1572 if repo[None].parents()[0].p1().branch() != branch and \
1573 repo[None].parents()[0].p2().branch() != branch:
1573 repo[None].parents()[0].p2().branch() != branch:
1574 raise error.Abort(_('can only close branch heads'))
1574 raise error.Abort(_('can only close branch heads'))
1575
1575
1576 if opts.get('amend'):
1576 if opts.get('amend'):
1577 if ui.configbool('ui', 'commitsubrepos'):
1577 if ui.configbool('ui', 'commitsubrepos'):
1578 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1578 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1579
1579
1580 old = repo['.']
1580 old = repo['.']
1581 rewriteutil.precheck(repo, [old.rev()], 'amend')
1581 rewriteutil.precheck(repo, [old.rev()], 'amend')
1582
1582
1583 # Currently histedit gets confused if an amend happens while histedit
1583 # Currently histedit gets confused if an amend happens while histedit
1584 # is in progress. Since we have a checkunfinished command, we are
1584 # is in progress. Since we have a checkunfinished command, we are
1585 # temporarily honoring it.
1585 # temporarily honoring it.
1586 #
1586 #
1587 # Note: eventually this guard will be removed. Please do not expect
1587 # Note: eventually this guard will be removed. Please do not expect
1588 # this behavior to remain.
1588 # this behavior to remain.
1589 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1589 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1590 cmdutil.checkunfinished(repo)
1590 cmdutil.checkunfinished(repo)
1591
1591
1592 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
1592 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
1593 if node == old.node():
1593 if node == old.node():
1594 ui.status(_("nothing changed\n"))
1594 ui.status(_("nothing changed\n"))
1595 return 1
1595 return 1
1596 else:
1596 else:
1597 def commitfunc(ui, repo, message, match, opts):
1597 def commitfunc(ui, repo, message, match, opts):
1598 overrides = {}
1598 overrides = {}
1599 if opts.get('secret'):
1599 if opts.get('secret'):
1600 overrides[('phases', 'new-commit')] = 'secret'
1600 overrides[('phases', 'new-commit')] = 'secret'
1601
1601
1602 baseui = repo.baseui
1602 baseui = repo.baseui
1603 with baseui.configoverride(overrides, 'commit'):
1603 with baseui.configoverride(overrides, 'commit'):
1604 with ui.configoverride(overrides, 'commit'):
1604 with ui.configoverride(overrides, 'commit'):
1605 editform = cmdutil.mergeeditform(repo[None],
1605 editform = cmdutil.mergeeditform(repo[None],
1606 'commit.normal')
1606 'commit.normal')
1607 editor = cmdutil.getcommiteditor(
1607 editor = cmdutil.getcommiteditor(
1608 editform=editform, **pycompat.strkwargs(opts))
1608 editform=editform, **pycompat.strkwargs(opts))
1609 return repo.commit(message,
1609 return repo.commit(message,
1610 opts.get('user'),
1610 opts.get('user'),
1611 opts.get('date'),
1611 opts.get('date'),
1612 match,
1612 match,
1613 editor=editor,
1613 editor=editor,
1614 extra=extra)
1614 extra=extra)
1615
1615
1616 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1616 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1617
1617
1618 if not node:
1618 if not node:
1619 stat = cmdutil.postcommitstatus(repo, pats, opts)
1619 stat = cmdutil.postcommitstatus(repo, pats, opts)
1620 if stat[3]:
1620 if stat[3]:
1621 ui.status(_("nothing changed (%d missing files, see "
1621 ui.status(_("nothing changed (%d missing files, see "
1622 "'hg status')\n") % len(stat[3]))
1622 "'hg status')\n") % len(stat[3]))
1623 else:
1623 else:
1624 ui.status(_("nothing changed\n"))
1624 ui.status(_("nothing changed\n"))
1625 return 1
1625 return 1
1626
1626
1627 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1627 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1628
1628
1629 @command('config|showconfig|debugconfig',
1629 @command('config|showconfig|debugconfig',
1630 [('u', 'untrusted', None, _('show untrusted configuration options')),
1630 [('u', 'untrusted', None, _('show untrusted configuration options')),
1631 ('e', 'edit', None, _('edit user config')),
1631 ('e', 'edit', None, _('edit user config')),
1632 ('l', 'local', None, _('edit repository config')),
1632 ('l', 'local', None, _('edit repository config')),
1633 ('g', 'global', None, _('edit global config'))] + formatteropts,
1633 ('g', 'global', None, _('edit global config'))] + formatteropts,
1634 _('[-u] [NAME]...'),
1634 _('[-u] [NAME]...'),
1635 optionalrepo=True, cmdtype=readonly)
1635 optionalrepo=True, cmdtype=readonly)
1636 def config(ui, repo, *values, **opts):
1636 def config(ui, repo, *values, **opts):
1637 """show combined config settings from all hgrc files
1637 """show combined config settings from all hgrc files
1638
1638
1639 With no arguments, print names and values of all config items.
1639 With no arguments, print names and values of all config items.
1640
1640
1641 With one argument of the form section.name, print just the value
1641 With one argument of the form section.name, print just the value
1642 of that config item.
1642 of that config item.
1643
1643
1644 With multiple arguments, print names and values of all config
1644 With multiple arguments, print names and values of all config
1645 items with matching section names or section.names.
1645 items with matching section names or section.names.
1646
1646
1647 With --edit, start an editor on the user-level config file. With
1647 With --edit, start an editor on the user-level config file. With
1648 --global, edit the system-wide config file. With --local, edit the
1648 --global, edit the system-wide config file. With --local, edit the
1649 repository-level config file.
1649 repository-level config file.
1650
1650
1651 With --debug, the source (filename and line number) is printed
1651 With --debug, the source (filename and line number) is printed
1652 for each config item.
1652 for each config item.
1653
1653
1654 See :hg:`help config` for more information about config files.
1654 See :hg:`help config` for more information about config files.
1655
1655
1656 Returns 0 on success, 1 if NAME does not exist.
1656 Returns 0 on success, 1 if NAME does not exist.
1657
1657
1658 """
1658 """
1659
1659
1660 opts = pycompat.byteskwargs(opts)
1660 opts = pycompat.byteskwargs(opts)
1661 if opts.get('edit') or opts.get('local') or opts.get('global'):
1661 if opts.get('edit') or opts.get('local') or opts.get('global'):
1662 if opts.get('local') and opts.get('global'):
1662 if opts.get('local') and opts.get('global'):
1663 raise error.Abort(_("can't use --local and --global together"))
1663 raise error.Abort(_("can't use --local and --global together"))
1664
1664
1665 if opts.get('local'):
1665 if opts.get('local'):
1666 if not repo:
1666 if not repo:
1667 raise error.Abort(_("can't use --local outside a repository"))
1667 raise error.Abort(_("can't use --local outside a repository"))
1668 paths = [repo.vfs.join('hgrc')]
1668 paths = [repo.vfs.join('hgrc')]
1669 elif opts.get('global'):
1669 elif opts.get('global'):
1670 paths = rcutil.systemrcpath()
1670 paths = rcutil.systemrcpath()
1671 else:
1671 else:
1672 paths = rcutil.userrcpath()
1672 paths = rcutil.userrcpath()
1673
1673
1674 for f in paths:
1674 for f in paths:
1675 if os.path.exists(f):
1675 if os.path.exists(f):
1676 break
1676 break
1677 else:
1677 else:
1678 if opts.get('global'):
1678 if opts.get('global'):
1679 samplehgrc = uimod.samplehgrcs['global']
1679 samplehgrc = uimod.samplehgrcs['global']
1680 elif opts.get('local'):
1680 elif opts.get('local'):
1681 samplehgrc = uimod.samplehgrcs['local']
1681 samplehgrc = uimod.samplehgrcs['local']
1682 else:
1682 else:
1683 samplehgrc = uimod.samplehgrcs['user']
1683 samplehgrc = uimod.samplehgrcs['user']
1684
1684
1685 f = paths[0]
1685 f = paths[0]
1686 fp = open(f, "wb")
1686 fp = open(f, "wb")
1687 fp.write(util.tonativeeol(samplehgrc))
1687 fp.write(util.tonativeeol(samplehgrc))
1688 fp.close()
1688 fp.close()
1689
1689
1690 editor = ui.geteditor()
1690 editor = ui.geteditor()
1691 ui.system("%s \"%s\"" % (editor, f),
1691 ui.system("%s \"%s\"" % (editor, f),
1692 onerr=error.Abort, errprefix=_("edit failed"),
1692 onerr=error.Abort, errprefix=_("edit failed"),
1693 blockedtag='config_edit')
1693 blockedtag='config_edit')
1694 return
1694 return
1695 ui.pager('config')
1695 ui.pager('config')
1696 fm = ui.formatter('config', opts)
1696 fm = ui.formatter('config', opts)
1697 for t, f in rcutil.rccomponents():
1697 for t, f in rcutil.rccomponents():
1698 if t == 'path':
1698 if t == 'path':
1699 ui.debug('read config from: %s\n' % f)
1699 ui.debug('read config from: %s\n' % f)
1700 elif t == 'items':
1700 elif t == 'items':
1701 for section, name, value, source in f:
1701 for section, name, value, source in f:
1702 ui.debug('set config by: %s\n' % source)
1702 ui.debug('set config by: %s\n' % source)
1703 else:
1703 else:
1704 raise error.ProgrammingError('unknown rctype: %s' % t)
1704 raise error.ProgrammingError('unknown rctype: %s' % t)
1705 untrusted = bool(opts.get('untrusted'))
1705 untrusted = bool(opts.get('untrusted'))
1706
1706
1707 selsections = selentries = []
1707 selsections = selentries = []
1708 if values:
1708 if values:
1709 selsections = [v for v in values if '.' not in v]
1709 selsections = [v for v in values if '.' not in v]
1710 selentries = [v for v in values if '.' in v]
1710 selentries = [v for v in values if '.' in v]
1711 uniquesel = (len(selentries) == 1 and not selsections)
1711 uniquesel = (len(selentries) == 1 and not selsections)
1712 selsections = set(selsections)
1712 selsections = set(selsections)
1713 selentries = set(selentries)
1713 selentries = set(selentries)
1714
1714
1715 matched = False
1715 matched = False
1716 for section, name, value in ui.walkconfig(untrusted=untrusted):
1716 for section, name, value in ui.walkconfig(untrusted=untrusted):
1717 source = ui.configsource(section, name, untrusted)
1717 source = ui.configsource(section, name, untrusted)
1718 value = pycompat.bytestr(value)
1718 value = pycompat.bytestr(value)
1719 if fm.isplain():
1719 if fm.isplain():
1720 source = source or 'none'
1720 source = source or 'none'
1721 value = value.replace('\n', '\\n')
1721 value = value.replace('\n', '\\n')
1722 entryname = section + '.' + name
1722 entryname = section + '.' + name
1723 if values and not (section in selsections or entryname in selentries):
1723 if values and not (section in selsections or entryname in selentries):
1724 continue
1724 continue
1725 fm.startitem()
1725 fm.startitem()
1726 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1726 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1727 if uniquesel:
1727 if uniquesel:
1728 fm.data(name=entryname)
1728 fm.data(name=entryname)
1729 fm.write('value', '%s\n', value)
1729 fm.write('value', '%s\n', value)
1730 else:
1730 else:
1731 fm.write('name value', '%s=%s\n', entryname, value)
1731 fm.write('name value', '%s=%s\n', entryname, value)
1732 matched = True
1732 matched = True
1733 fm.end()
1733 fm.end()
1734 if matched:
1734 if matched:
1735 return 0
1735 return 0
1736 return 1
1736 return 1
1737
1737
1738 @command('copy|cp',
1738 @command('copy|cp',
1739 [('A', 'after', None, _('record a copy that has already occurred')),
1739 [('A', 'after', None, _('record a copy that has already occurred')),
1740 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1740 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1741 ] + walkopts + dryrunopts,
1741 ] + walkopts + dryrunopts,
1742 _('[OPTION]... [SOURCE]... DEST'))
1742 _('[OPTION]... [SOURCE]... DEST'))
1743 def copy(ui, repo, *pats, **opts):
1743 def copy(ui, repo, *pats, **opts):
1744 """mark files as copied for the next commit
1744 """mark files as copied for the next commit
1745
1745
1746 Mark dest as having copies of source files. If dest is a
1746 Mark dest as having copies of source files. If dest is a
1747 directory, copies are put in that directory. If dest is a file,
1747 directory, copies are put in that directory. If dest is a file,
1748 the source must be a single file.
1748 the source must be a single file.
1749
1749
1750 By default, this command copies the contents of files as they
1750 By default, this command copies the contents of files as they
1751 exist in the working directory. If invoked with -A/--after, the
1751 exist in the working directory. If invoked with -A/--after, the
1752 operation is recorded, but no copying is performed.
1752 operation is recorded, but no copying is performed.
1753
1753
1754 This command takes effect with the next commit. To undo a copy
1754 This command takes effect with the next commit. To undo a copy
1755 before that, see :hg:`revert`.
1755 before that, see :hg:`revert`.
1756
1756
1757 Returns 0 on success, 1 if errors are encountered.
1757 Returns 0 on success, 1 if errors are encountered.
1758 """
1758 """
1759 opts = pycompat.byteskwargs(opts)
1759 opts = pycompat.byteskwargs(opts)
1760 with repo.wlock(False):
1760 with repo.wlock(False):
1761 return cmdutil.copy(ui, repo, pats, opts)
1761 return cmdutil.copy(ui, repo, pats, opts)
1762
1762
1763 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1763 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1764 def debugcommands(ui, cmd='', *args):
1764 def debugcommands(ui, cmd='', *args):
1765 """list all available commands and options"""
1765 """list all available commands and options"""
1766 for cmd, vals in sorted(table.iteritems()):
1766 for cmd, vals in sorted(table.iteritems()):
1767 cmd = cmd.split('|')[0].strip('^')
1767 cmd = cmd.split('|')[0].strip('^')
1768 opts = ', '.join([i[1] for i in vals[1]])
1768 opts = ', '.join([i[1] for i in vals[1]])
1769 ui.write('%s: %s\n' % (cmd, opts))
1769 ui.write('%s: %s\n' % (cmd, opts))
1770
1770
1771 @command('debugcomplete',
1771 @command('debugcomplete',
1772 [('o', 'options', None, _('show the command options'))],
1772 [('o', 'options', None, _('show the command options'))],
1773 _('[-o] CMD'),
1773 _('[-o] CMD'),
1774 norepo=True)
1774 norepo=True)
1775 def debugcomplete(ui, cmd='', **opts):
1775 def debugcomplete(ui, cmd='', **opts):
1776 """returns the completion list associated with the given command"""
1776 """returns the completion list associated with the given command"""
1777
1777
1778 if opts.get(r'options'):
1778 if opts.get(r'options'):
1779 options = []
1779 options = []
1780 otables = [globalopts]
1780 otables = [globalopts]
1781 if cmd:
1781 if cmd:
1782 aliases, entry = cmdutil.findcmd(cmd, table, False)
1782 aliases, entry = cmdutil.findcmd(cmd, table, False)
1783 otables.append(entry[1])
1783 otables.append(entry[1])
1784 for t in otables:
1784 for t in otables:
1785 for o in t:
1785 for o in t:
1786 if "(DEPRECATED)" in o[3]:
1786 if "(DEPRECATED)" in o[3]:
1787 continue
1787 continue
1788 if o[0]:
1788 if o[0]:
1789 options.append('-%s' % o[0])
1789 options.append('-%s' % o[0])
1790 options.append('--%s' % o[1])
1790 options.append('--%s' % o[1])
1791 ui.write("%s\n" % "\n".join(options))
1791 ui.write("%s\n" % "\n".join(options))
1792 return
1792 return
1793
1793
1794 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1794 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1795 if ui.verbose:
1795 if ui.verbose:
1796 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1796 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1797 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1797 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1798
1798
1799 @command('^diff',
1799 @command('^diff',
1800 [('r', 'rev', [], _('revision'), _('REV')),
1800 [('r', 'rev', [], _('revision'), _('REV')),
1801 ('c', 'change', '', _('change made by revision'), _('REV'))
1801 ('c', 'change', '', _('change made by revision'), _('REV'))
1802 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1802 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1803 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1803 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1804 inferrepo=True, cmdtype=readonly)
1804 inferrepo=True, cmdtype=readonly)
1805 def diff(ui, repo, *pats, **opts):
1805 def diff(ui, repo, *pats, **opts):
1806 """diff repository (or selected files)
1806 """diff repository (or selected files)
1807
1807
1808 Show differences between revisions for the specified files.
1808 Show differences between revisions for the specified files.
1809
1809
1810 Differences between files are shown using the unified diff format.
1810 Differences between files are shown using the unified diff format.
1811
1811
1812 .. note::
1812 .. note::
1813
1813
1814 :hg:`diff` may generate unexpected results for merges, as it will
1814 :hg:`diff` may generate unexpected results for merges, as it will
1815 default to comparing against the working directory's first
1815 default to comparing against the working directory's first
1816 parent changeset if no revisions are specified.
1816 parent changeset if no revisions are specified.
1817
1817
1818 When two revision arguments are given, then changes are shown
1818 When two revision arguments are given, then changes are shown
1819 between those revisions. If only one revision is specified then
1819 between those revisions. If only one revision is specified then
1820 that revision is compared to the working directory, and, when no
1820 that revision is compared to the working directory, and, when no
1821 revisions are specified, the working directory files are compared
1821 revisions are specified, the working directory files are compared
1822 to its first parent.
1822 to its first parent.
1823
1823
1824 Alternatively you can specify -c/--change with a revision to see
1824 Alternatively you can specify -c/--change with a revision to see
1825 the changes in that changeset relative to its first parent.
1825 the changes in that changeset relative to its first parent.
1826
1826
1827 Without the -a/--text option, diff will avoid generating diffs of
1827 Without the -a/--text option, diff will avoid generating diffs of
1828 files it detects as binary. With -a, diff will generate a diff
1828 files it detects as binary. With -a, diff will generate a diff
1829 anyway, probably with undesirable results.
1829 anyway, probably with undesirable results.
1830
1830
1831 Use the -g/--git option to generate diffs in the git extended diff
1831 Use the -g/--git option to generate diffs in the git extended diff
1832 format. For more information, read :hg:`help diffs`.
1832 format. For more information, read :hg:`help diffs`.
1833
1833
1834 .. container:: verbose
1834 .. container:: verbose
1835
1835
1836 Examples:
1836 Examples:
1837
1837
1838 - compare a file in the current working directory to its parent::
1838 - compare a file in the current working directory to its parent::
1839
1839
1840 hg diff foo.c
1840 hg diff foo.c
1841
1841
1842 - compare two historical versions of a directory, with rename info::
1842 - compare two historical versions of a directory, with rename info::
1843
1843
1844 hg diff --git -r 1.0:1.2 lib/
1844 hg diff --git -r 1.0:1.2 lib/
1845
1845
1846 - get change stats relative to the last change on some date::
1846 - get change stats relative to the last change on some date::
1847
1847
1848 hg diff --stat -r "date('may 2')"
1848 hg diff --stat -r "date('may 2')"
1849
1849
1850 - diff all newly-added files that contain a keyword::
1850 - diff all newly-added files that contain a keyword::
1851
1851
1852 hg diff "set:added() and grep(GNU)"
1852 hg diff "set:added() and grep(GNU)"
1853
1853
1854 - compare a revision and its parents::
1854 - compare a revision and its parents::
1855
1855
1856 hg diff -c 9353 # compare against first parent
1856 hg diff -c 9353 # compare against first parent
1857 hg diff -r 9353^:9353 # same using revset syntax
1857 hg diff -r 9353^:9353 # same using revset syntax
1858 hg diff -r 9353^2:9353 # compare against the second parent
1858 hg diff -r 9353^2:9353 # compare against the second parent
1859
1859
1860 Returns 0 on success.
1860 Returns 0 on success.
1861 """
1861 """
1862
1862
1863 opts = pycompat.byteskwargs(opts)
1863 opts = pycompat.byteskwargs(opts)
1864 revs = opts.get('rev')
1864 revs = opts.get('rev')
1865 change = opts.get('change')
1865 change = opts.get('change')
1866 stat = opts.get('stat')
1866 stat = opts.get('stat')
1867 reverse = opts.get('reverse')
1867 reverse = opts.get('reverse')
1868
1868
1869 if revs and change:
1869 if revs and change:
1870 msg = _('cannot specify --rev and --change at the same time')
1870 msg = _('cannot specify --rev and --change at the same time')
1871 raise error.Abort(msg)
1871 raise error.Abort(msg)
1872 elif change:
1872 elif change:
1873 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
1873 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
1874 ctx2 = scmutil.revsingle(repo, change, None)
1874 ctx2 = scmutil.revsingle(repo, change, None)
1875 ctx1 = ctx2.p1()
1875 ctx1 = ctx2.p1()
1876 else:
1876 else:
1877 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
1877 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
1878 ctx1, ctx2 = scmutil.revpair(repo, revs)
1878 ctx1, ctx2 = scmutil.revpair(repo, revs)
1879 node1, node2 = ctx1.node(), ctx2.node()
1879 node1, node2 = ctx1.node(), ctx2.node()
1880
1880
1881 if reverse:
1881 if reverse:
1882 node1, node2 = node2, node1
1882 node1, node2 = node2, node1
1883
1883
1884 diffopts = patch.diffallopts(ui, opts)
1884 diffopts = patch.diffallopts(ui, opts)
1885 m = scmutil.match(ctx2, pats, opts)
1885 m = scmutil.match(ctx2, pats, opts)
1886 ui.pager('diff')
1886 ui.pager('diff')
1887 logcmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1887 logcmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1888 listsubrepos=opts.get('subrepos'),
1888 listsubrepos=opts.get('subrepos'),
1889 root=opts.get('root'))
1889 root=opts.get('root'))
1890
1890
1891 @command('^export',
1891 @command('^export',
1892 [('o', 'output', '',
1892 [('o', 'output', '',
1893 _('print output to file with formatted name'), _('FORMAT')),
1893 _('print output to file with formatted name'), _('FORMAT')),
1894 ('', 'switch-parent', None, _('diff against the second parent')),
1894 ('', 'switch-parent', None, _('diff against the second parent')),
1895 ('r', 'rev', [], _('revisions to export'), _('REV')),
1895 ('r', 'rev', [], _('revisions to export'), _('REV')),
1896 ] + diffopts,
1896 ] + diffopts,
1897 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'), cmdtype=readonly)
1897 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'), cmdtype=readonly)
1898 def export(ui, repo, *changesets, **opts):
1898 def export(ui, repo, *changesets, **opts):
1899 """dump the header and diffs for one or more changesets
1899 """dump the header and diffs for one or more changesets
1900
1900
1901 Print the changeset header and diffs for one or more revisions.
1901 Print the changeset header and diffs for one or more revisions.
1902 If no revision is given, the parent of the working directory is used.
1902 If no revision is given, the parent of the working directory is used.
1903
1903
1904 The information shown in the changeset header is: author, date,
1904 The information shown in the changeset header is: author, date,
1905 branch name (if non-default), changeset hash, parent(s) and commit
1905 branch name (if non-default), changeset hash, parent(s) and commit
1906 comment.
1906 comment.
1907
1907
1908 .. note::
1908 .. note::
1909
1909
1910 :hg:`export` may generate unexpected diff output for merge
1910 :hg:`export` may generate unexpected diff output for merge
1911 changesets, as it will compare the merge changeset against its
1911 changesets, as it will compare the merge changeset against its
1912 first parent only.
1912 first parent only.
1913
1913
1914 Output may be to a file, in which case the name of the file is
1914 Output may be to a file, in which case the name of the file is
1915 given using a template string. See :hg:`help templates`. In addition
1915 given using a template string. See :hg:`help templates`. In addition
1916 to the common template keywords, the following formatting rules are
1916 to the common template keywords, the following formatting rules are
1917 supported:
1917 supported:
1918
1918
1919 :``%%``: literal "%" character
1919 :``%%``: literal "%" character
1920 :``%H``: changeset hash (40 hexadecimal digits)
1920 :``%H``: changeset hash (40 hexadecimal digits)
1921 :``%N``: number of patches being generated
1921 :``%N``: number of patches being generated
1922 :``%R``: changeset revision number
1922 :``%R``: changeset revision number
1923 :``%b``: basename of the exporting repository
1923 :``%b``: basename of the exporting repository
1924 :``%h``: short-form changeset hash (12 hexadecimal digits)
1924 :``%h``: short-form changeset hash (12 hexadecimal digits)
1925 :``%m``: first line of the commit message (only alphanumeric characters)
1925 :``%m``: first line of the commit message (only alphanumeric characters)
1926 :``%n``: zero-padded sequence number, starting at 1
1926 :``%n``: zero-padded sequence number, starting at 1
1927 :``%r``: zero-padded changeset revision number
1927 :``%r``: zero-padded changeset revision number
1928 :``\\``: literal "\\" character
1928 :``\\``: literal "\\" character
1929
1929
1930 Without the -a/--text option, export will avoid generating diffs
1930 Without the -a/--text option, export will avoid generating diffs
1931 of files it detects as binary. With -a, export will generate a
1931 of files it detects as binary. With -a, export will generate a
1932 diff anyway, probably with undesirable results.
1932 diff anyway, probably with undesirable results.
1933
1933
1934 Use the -g/--git option to generate diffs in the git extended diff
1934 Use the -g/--git option to generate diffs in the git extended diff
1935 format. See :hg:`help diffs` for more information.
1935 format. See :hg:`help diffs` for more information.
1936
1936
1937 With the --switch-parent option, the diff will be against the
1937 With the --switch-parent option, the diff will be against the
1938 second parent. It can be useful to review a merge.
1938 second parent. It can be useful to review a merge.
1939
1939
1940 .. container:: verbose
1940 .. container:: verbose
1941
1941
1942 Examples:
1942 Examples:
1943
1943
1944 - use export and import to transplant a bugfix to the current
1944 - use export and import to transplant a bugfix to the current
1945 branch::
1945 branch::
1946
1946
1947 hg export -r 9353 | hg import -
1947 hg export -r 9353 | hg import -
1948
1948
1949 - export all the changesets between two revisions to a file with
1949 - export all the changesets between two revisions to a file with
1950 rename information::
1950 rename information::
1951
1951
1952 hg export --git -r 123:150 > changes.txt
1952 hg export --git -r 123:150 > changes.txt
1953
1953
1954 - split outgoing changes into a series of patches with
1954 - split outgoing changes into a series of patches with
1955 descriptive names::
1955 descriptive names::
1956
1956
1957 hg export -r "outgoing()" -o "%n-%m.patch"
1957 hg export -r "outgoing()" -o "%n-%m.patch"
1958
1958
1959 Returns 0 on success.
1959 Returns 0 on success.
1960 """
1960 """
1961 opts = pycompat.byteskwargs(opts)
1961 opts = pycompat.byteskwargs(opts)
1962 changesets += tuple(opts.get('rev', []))
1962 changesets += tuple(opts.get('rev', []))
1963 if not changesets:
1963 if not changesets:
1964 changesets = ['.']
1964 changesets = ['.']
1965 repo = scmutil.unhidehashlikerevs(repo, changesets, 'nowarn')
1965 repo = scmutil.unhidehashlikerevs(repo, changesets, 'nowarn')
1966 revs = scmutil.revrange(repo, changesets)
1966 revs = scmutil.revrange(repo, changesets)
1967 if not revs:
1967 if not revs:
1968 raise error.Abort(_("export requires at least one changeset"))
1968 raise error.Abort(_("export requires at least one changeset"))
1969 if len(revs) > 1:
1969 if len(revs) > 1:
1970 ui.note(_('exporting patches:\n'))
1970 ui.note(_('exporting patches:\n'))
1971 else:
1971 else:
1972 ui.note(_('exporting patch:\n'))
1972 ui.note(_('exporting patch:\n'))
1973 ui.pager('export')
1973 ui.pager('export')
1974 cmdutil.export(repo, revs, fntemplate=opts.get('output'),
1974 cmdutil.export(repo, revs, fntemplate=opts.get('output'),
1975 switch_parent=opts.get('switch_parent'),
1975 switch_parent=opts.get('switch_parent'),
1976 opts=patch.diffallopts(ui, opts))
1976 opts=patch.diffallopts(ui, opts))
1977
1977
1978 @command('files',
1978 @command('files',
1979 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
1979 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
1980 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
1980 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
1981 ] + walkopts + formatteropts + subrepoopts,
1981 ] + walkopts + formatteropts + subrepoopts,
1982 _('[OPTION]... [FILE]...'), cmdtype=readonly)
1982 _('[OPTION]... [FILE]...'), cmdtype=readonly)
1983 def files(ui, repo, *pats, **opts):
1983 def files(ui, repo, *pats, **opts):
1984 """list tracked files
1984 """list tracked files
1985
1985
1986 Print files under Mercurial control in the working directory or
1986 Print files under Mercurial control in the working directory or
1987 specified revision for given files (excluding removed files).
1987 specified revision for given files (excluding removed files).
1988 Files can be specified as filenames or filesets.
1988 Files can be specified as filenames or filesets.
1989
1989
1990 If no files are given to match, this command prints the names
1990 If no files are given to match, this command prints the names
1991 of all files under Mercurial control.
1991 of all files under Mercurial control.
1992
1992
1993 .. container:: verbose
1993 .. container:: verbose
1994
1994
1995 Examples:
1995 Examples:
1996
1996
1997 - list all files under the current directory::
1997 - list all files under the current directory::
1998
1998
1999 hg files .
1999 hg files .
2000
2000
2001 - shows sizes and flags for current revision::
2001 - shows sizes and flags for current revision::
2002
2002
2003 hg files -vr .
2003 hg files -vr .
2004
2004
2005 - list all files named README::
2005 - list all files named README::
2006
2006
2007 hg files -I "**/README"
2007 hg files -I "**/README"
2008
2008
2009 - list all binary files::
2009 - list all binary files::
2010
2010
2011 hg files "set:binary()"
2011 hg files "set:binary()"
2012
2012
2013 - find files containing a regular expression::
2013 - find files containing a regular expression::
2014
2014
2015 hg files "set:grep('bob')"
2015 hg files "set:grep('bob')"
2016
2016
2017 - search tracked file contents with xargs and grep::
2017 - search tracked file contents with xargs and grep::
2018
2018
2019 hg files -0 | xargs -0 grep foo
2019 hg files -0 | xargs -0 grep foo
2020
2020
2021 See :hg:`help patterns` and :hg:`help filesets` for more information
2021 See :hg:`help patterns` and :hg:`help filesets` for more information
2022 on specifying file patterns.
2022 on specifying file patterns.
2023
2023
2024 Returns 0 if a match is found, 1 otherwise.
2024 Returns 0 if a match is found, 1 otherwise.
2025
2025
2026 """
2026 """
2027
2027
2028 opts = pycompat.byteskwargs(opts)
2028 opts = pycompat.byteskwargs(opts)
2029 rev = opts.get('rev')
2029 rev = opts.get('rev')
2030 if rev:
2030 if rev:
2031 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2031 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2032 ctx = scmutil.revsingle(repo, rev, None)
2032 ctx = scmutil.revsingle(repo, rev, None)
2033
2033
2034 end = '\n'
2034 end = '\n'
2035 if opts.get('print0'):
2035 if opts.get('print0'):
2036 end = '\0'
2036 end = '\0'
2037 fmt = '%s' + end
2037 fmt = '%s' + end
2038
2038
2039 m = scmutil.match(ctx, pats, opts)
2039 m = scmutil.match(ctx, pats, opts)
2040 ui.pager('files')
2040 ui.pager('files')
2041 with ui.formatter('files', opts) as fm:
2041 with ui.formatter('files', opts) as fm:
2042 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2042 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2043
2043
2044 @command(
2044 @command(
2045 '^forget',
2045 '^forget',
2046 walkopts + dryrunopts,
2046 walkopts + dryrunopts,
2047 _('[OPTION]... FILE...'), inferrepo=True)
2047 _('[OPTION]... FILE...'), inferrepo=True)
2048 def forget(ui, repo, *pats, **opts):
2048 def forget(ui, repo, *pats, **opts):
2049 """forget the specified files on the next commit
2049 """forget the specified files on the next commit
2050
2050
2051 Mark the specified files so they will no longer be tracked
2051 Mark the specified files so they will no longer be tracked
2052 after the next commit.
2052 after the next commit.
2053
2053
2054 This only removes files from the current branch, not from the
2054 This only removes files from the current branch, not from the
2055 entire project history, and it does not delete them from the
2055 entire project history, and it does not delete them from the
2056 working directory.
2056 working directory.
2057
2057
2058 To delete the file from the working directory, see :hg:`remove`.
2058 To delete the file from the working directory, see :hg:`remove`.
2059
2059
2060 To undo a forget before the next commit, see :hg:`add`.
2060 To undo a forget before the next commit, see :hg:`add`.
2061
2061
2062 .. container:: verbose
2062 .. container:: verbose
2063
2063
2064 Examples:
2064 Examples:
2065
2065
2066 - forget newly-added binary files::
2066 - forget newly-added binary files::
2067
2067
2068 hg forget "set:added() and binary()"
2068 hg forget "set:added() and binary()"
2069
2069
2070 - forget files that would be excluded by .hgignore::
2070 - forget files that would be excluded by .hgignore::
2071
2071
2072 hg forget "set:hgignore()"
2072 hg forget "set:hgignore()"
2073
2073
2074 Returns 0 on success.
2074 Returns 0 on success.
2075 """
2075 """
2076
2076
2077 opts = pycompat.byteskwargs(opts)
2077 opts = pycompat.byteskwargs(opts)
2078 if not pats:
2078 if not pats:
2079 raise error.Abort(_('no files specified'))
2079 raise error.Abort(_('no files specified'))
2080
2080
2081 m = scmutil.match(repo[None], pats, opts)
2081 m = scmutil.match(repo[None], pats, opts)
2082 dryrun = opts.get(r'dry_run')
2082 dryrun = opts.get(r'dry_run')
2083 rejected = cmdutil.forget(ui, repo, m, prefix="",
2083 rejected = cmdutil.forget(ui, repo, m, prefix="",
2084 explicitonly=False, dryrun=dryrun)[0]
2084 explicitonly=False, dryrun=dryrun)[0]
2085 return rejected and 1 or 0
2085 return rejected and 1 or 0
2086
2086
2087 @command(
2087 @command(
2088 'graft',
2088 'graft',
2089 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2089 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2090 ('c', 'continue', False, _('resume interrupted graft')),
2090 ('c', 'continue', False, _('resume interrupted graft')),
2091 ('e', 'edit', False, _('invoke editor on commit messages')),
2091 ('e', 'edit', False, _('invoke editor on commit messages')),
2092 ('', 'log', None, _('append graft info to log message')),
2092 ('', 'log', None, _('append graft info to log message')),
2093 ('f', 'force', False, _('force graft')),
2093 ('f', 'force', False, _('force graft')),
2094 ('D', 'currentdate', False,
2094 ('D', 'currentdate', False,
2095 _('record the current date as commit date')),
2095 _('record the current date as commit date')),
2096 ('U', 'currentuser', False,
2096 ('U', 'currentuser', False,
2097 _('record the current user as committer'), _('DATE'))]
2097 _('record the current user as committer'), _('DATE'))]
2098 + commitopts2 + mergetoolopts + dryrunopts,
2098 + commitopts2 + mergetoolopts + dryrunopts,
2099 _('[OPTION]... [-r REV]... REV...'))
2099 _('[OPTION]... [-r REV]... REV...'))
2100 def graft(ui, repo, *revs, **opts):
2100 def graft(ui, repo, *revs, **opts):
2101 '''copy changes from other branches onto the current branch
2101 '''copy changes from other branches onto the current branch
2102
2102
2103 This command uses Mercurial's merge logic to copy individual
2103 This command uses Mercurial's merge logic to copy individual
2104 changes from other branches without merging branches in the
2104 changes from other branches without merging branches in the
2105 history graph. This is sometimes known as 'backporting' or
2105 history graph. This is sometimes known as 'backporting' or
2106 'cherry-picking'. By default, graft will copy user, date, and
2106 'cherry-picking'. By default, graft will copy user, date, and
2107 description from the source changesets.
2107 description from the source changesets.
2108
2108
2109 Changesets that are ancestors of the current revision, that have
2109 Changesets that are ancestors of the current revision, that have
2110 already been grafted, or that are merges will be skipped.
2110 already been grafted, or that are merges will be skipped.
2111
2111
2112 If --log is specified, log messages will have a comment appended
2112 If --log is specified, log messages will have a comment appended
2113 of the form::
2113 of the form::
2114
2114
2115 (grafted from CHANGESETHASH)
2115 (grafted from CHANGESETHASH)
2116
2116
2117 If --force is specified, revisions will be grafted even if they
2117 If --force is specified, revisions will be grafted even if they
2118 are already ancestors of, or have been grafted to, the destination.
2118 are already ancestors of, or have been grafted to, the destination.
2119 This is useful when the revisions have since been backed out.
2119 This is useful when the revisions have since been backed out.
2120
2120
2121 If a graft merge results in conflicts, the graft process is
2121 If a graft merge results in conflicts, the graft process is
2122 interrupted so that the current merge can be manually resolved.
2122 interrupted so that the current merge can be manually resolved.
2123 Once all conflicts are addressed, the graft process can be
2123 Once all conflicts are addressed, the graft process can be
2124 continued with the -c/--continue option.
2124 continued with the -c/--continue option.
2125
2125
2126 .. note::
2126 .. note::
2127
2127
2128 The -c/--continue option does not reapply earlier options, except
2128 The -c/--continue option does not reapply earlier options, except
2129 for --force.
2129 for --force.
2130
2130
2131 .. container:: verbose
2131 .. container:: verbose
2132
2132
2133 Examples:
2133 Examples:
2134
2134
2135 - copy a single change to the stable branch and edit its description::
2135 - copy a single change to the stable branch and edit its description::
2136
2136
2137 hg update stable
2137 hg update stable
2138 hg graft --edit 9393
2138 hg graft --edit 9393
2139
2139
2140 - graft a range of changesets with one exception, updating dates::
2140 - graft a range of changesets with one exception, updating dates::
2141
2141
2142 hg graft -D "2085::2093 and not 2091"
2142 hg graft -D "2085::2093 and not 2091"
2143
2143
2144 - continue a graft after resolving conflicts::
2144 - continue a graft after resolving conflicts::
2145
2145
2146 hg graft -c
2146 hg graft -c
2147
2147
2148 - show the source of a grafted changeset::
2148 - show the source of a grafted changeset::
2149
2149
2150 hg log --debug -r .
2150 hg log --debug -r .
2151
2151
2152 - show revisions sorted by date::
2152 - show revisions sorted by date::
2153
2153
2154 hg log -r "sort(all(), date)"
2154 hg log -r "sort(all(), date)"
2155
2155
2156 See :hg:`help revisions` for more about specifying revisions.
2156 See :hg:`help revisions` for more about specifying revisions.
2157
2157
2158 Returns 0 on successful completion.
2158 Returns 0 on successful completion.
2159 '''
2159 '''
2160 with repo.wlock():
2160 with repo.wlock():
2161 return _dograft(ui, repo, *revs, **opts)
2161 return _dograft(ui, repo, *revs, **opts)
2162
2162
2163 def _dograft(ui, repo, *revs, **opts):
2163 def _dograft(ui, repo, *revs, **opts):
2164 opts = pycompat.byteskwargs(opts)
2164 opts = pycompat.byteskwargs(opts)
2165 if revs and opts.get('rev'):
2165 if revs and opts.get('rev'):
2166 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2166 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2167 'revision ordering!\n'))
2167 'revision ordering!\n'))
2168
2168
2169 revs = list(revs)
2169 revs = list(revs)
2170 revs.extend(opts.get('rev'))
2170 revs.extend(opts.get('rev'))
2171
2171
2172 if not opts.get('user') and opts.get('currentuser'):
2172 if not opts.get('user') and opts.get('currentuser'):
2173 opts['user'] = ui.username()
2173 opts['user'] = ui.username()
2174 if not opts.get('date') and opts.get('currentdate'):
2174 if not opts.get('date') and opts.get('currentdate'):
2175 opts['date'] = "%d %d" % dateutil.makedate()
2175 opts['date'] = "%d %d" % dateutil.makedate()
2176
2176
2177 editor = cmdutil.getcommiteditor(editform='graft',
2177 editor = cmdutil.getcommiteditor(editform='graft',
2178 **pycompat.strkwargs(opts))
2178 **pycompat.strkwargs(opts))
2179
2179
2180 cont = False
2180 cont = False
2181 if opts.get('continue'):
2181 if opts.get('continue'):
2182 cont = True
2182 cont = True
2183 if revs:
2183 if revs:
2184 raise error.Abort(_("can't specify --continue and revisions"))
2184 raise error.Abort(_("can't specify --continue and revisions"))
2185 # read in unfinished revisions
2185 # read in unfinished revisions
2186 try:
2186 try:
2187 nodes = repo.vfs.read('graftstate').splitlines()
2187 nodes = repo.vfs.read('graftstate').splitlines()
2188 revs = [repo[node].rev() for node in nodes]
2188 revs = [repo[node].rev() for node in nodes]
2189 except IOError as inst:
2189 except IOError as inst:
2190 if inst.errno != errno.ENOENT:
2190 if inst.errno != errno.ENOENT:
2191 raise
2191 raise
2192 cmdutil.wrongtooltocontinue(repo, _('graft'))
2192 cmdutil.wrongtooltocontinue(repo, _('graft'))
2193 else:
2193 else:
2194 if not revs:
2194 if not revs:
2195 raise error.Abort(_('no revisions specified'))
2195 raise error.Abort(_('no revisions specified'))
2196 cmdutil.checkunfinished(repo)
2196 cmdutil.checkunfinished(repo)
2197 cmdutil.bailifchanged(repo)
2197 cmdutil.bailifchanged(repo)
2198 revs = scmutil.revrange(repo, revs)
2198 revs = scmutil.revrange(repo, revs)
2199
2199
2200 skipped = set()
2200 skipped = set()
2201 # check for merges
2201 # check for merges
2202 for rev in repo.revs('%ld and merge()', revs):
2202 for rev in repo.revs('%ld and merge()', revs):
2203 ui.warn(_('skipping ungraftable merge revision %d\n') % rev)
2203 ui.warn(_('skipping ungraftable merge revision %d\n') % rev)
2204 skipped.add(rev)
2204 skipped.add(rev)
2205 revs = [r for r in revs if r not in skipped]
2205 revs = [r for r in revs if r not in skipped]
2206 if not revs:
2206 if not revs:
2207 return -1
2207 return -1
2208
2208
2209 # Don't check in the --continue case, in effect retaining --force across
2209 # Don't check in the --continue case, in effect retaining --force across
2210 # --continues. That's because without --force, any revisions we decided to
2210 # --continues. That's because without --force, any revisions we decided to
2211 # skip would have been filtered out here, so they wouldn't have made their
2211 # skip would have been filtered out here, so they wouldn't have made their
2212 # way to the graftstate. With --force, any revisions we would have otherwise
2212 # way to the graftstate. With --force, any revisions we would have otherwise
2213 # skipped would not have been filtered out, and if they hadn't been applied
2213 # skipped would not have been filtered out, and if they hadn't been applied
2214 # already, they'd have been in the graftstate.
2214 # already, they'd have been in the graftstate.
2215 if not (cont or opts.get('force')):
2215 if not (cont or opts.get('force')):
2216 # check for ancestors of dest branch
2216 # check for ancestors of dest branch
2217 crev = repo['.'].rev()
2217 crev = repo['.'].rev()
2218 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2218 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2219 # XXX make this lazy in the future
2219 # XXX make this lazy in the future
2220 # don't mutate while iterating, create a copy
2220 # don't mutate while iterating, create a copy
2221 for rev in list(revs):
2221 for rev in list(revs):
2222 if rev in ancestors:
2222 if rev in ancestors:
2223 ui.warn(_('skipping ancestor revision %d:%s\n') %
2223 ui.warn(_('skipping ancestor revision %d:%s\n') %
2224 (rev, repo[rev]))
2224 (rev, repo[rev]))
2225 # XXX remove on list is slow
2225 # XXX remove on list is slow
2226 revs.remove(rev)
2226 revs.remove(rev)
2227 if not revs:
2227 if not revs:
2228 return -1
2228 return -1
2229
2229
2230 # analyze revs for earlier grafts
2230 # analyze revs for earlier grafts
2231 ids = {}
2231 ids = {}
2232 for ctx in repo.set("%ld", revs):
2232 for ctx in repo.set("%ld", revs):
2233 ids[ctx.hex()] = ctx.rev()
2233 ids[ctx.hex()] = ctx.rev()
2234 n = ctx.extra().get('source')
2234 n = ctx.extra().get('source')
2235 if n:
2235 if n:
2236 ids[n] = ctx.rev()
2236 ids[n] = ctx.rev()
2237
2237
2238 # check ancestors for earlier grafts
2238 # check ancestors for earlier grafts
2239 ui.debug('scanning for duplicate grafts\n')
2239 ui.debug('scanning for duplicate grafts\n')
2240
2240
2241 # The only changesets we can be sure doesn't contain grafts of any
2241 # The only changesets we can be sure doesn't contain grafts of any
2242 # revs, are the ones that are common ancestors of *all* revs:
2242 # revs, are the ones that are common ancestors of *all* revs:
2243 for rev in repo.revs('only(%d,ancestor(%ld))', crev, revs):
2243 for rev in repo.revs('only(%d,ancestor(%ld))', crev, revs):
2244 ctx = repo[rev]
2244 ctx = repo[rev]
2245 n = ctx.extra().get('source')
2245 n = ctx.extra().get('source')
2246 if n in ids:
2246 if n in ids:
2247 try:
2247 try:
2248 r = repo[n].rev()
2248 r = repo[n].rev()
2249 except error.RepoLookupError:
2249 except error.RepoLookupError:
2250 r = None
2250 r = None
2251 if r in revs:
2251 if r in revs:
2252 ui.warn(_('skipping revision %d:%s '
2252 ui.warn(_('skipping revision %d:%s '
2253 '(already grafted to %d:%s)\n')
2253 '(already grafted to %d:%s)\n')
2254 % (r, repo[r], rev, ctx))
2254 % (r, repo[r], rev, ctx))
2255 revs.remove(r)
2255 revs.remove(r)
2256 elif ids[n] in revs:
2256 elif ids[n] in revs:
2257 if r is None:
2257 if r is None:
2258 ui.warn(_('skipping already grafted revision %d:%s '
2258 ui.warn(_('skipping already grafted revision %d:%s '
2259 '(%d:%s also has unknown origin %s)\n')
2259 '(%d:%s also has unknown origin %s)\n')
2260 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2260 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2261 else:
2261 else:
2262 ui.warn(_('skipping already grafted revision %d:%s '
2262 ui.warn(_('skipping already grafted revision %d:%s '
2263 '(%d:%s also has origin %d:%s)\n')
2263 '(%d:%s also has origin %d:%s)\n')
2264 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2264 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2265 revs.remove(ids[n])
2265 revs.remove(ids[n])
2266 elif ctx.hex() in ids:
2266 elif ctx.hex() in ids:
2267 r = ids[ctx.hex()]
2267 r = ids[ctx.hex()]
2268 ui.warn(_('skipping already grafted revision %d:%s '
2268 ui.warn(_('skipping already grafted revision %d:%s '
2269 '(was grafted from %d:%s)\n') %
2269 '(was grafted from %d:%s)\n') %
2270 (r, repo[r], rev, ctx))
2270 (r, repo[r], rev, ctx))
2271 revs.remove(r)
2271 revs.remove(r)
2272 if not revs:
2272 if not revs:
2273 return -1
2273 return -1
2274
2274
2275 for pos, ctx in enumerate(repo.set("%ld", revs)):
2275 for pos, ctx in enumerate(repo.set("%ld", revs)):
2276 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2276 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2277 ctx.description().split('\n', 1)[0])
2277 ctx.description().split('\n', 1)[0])
2278 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2278 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2279 if names:
2279 if names:
2280 desc += ' (%s)' % ' '.join(names)
2280 desc += ' (%s)' % ' '.join(names)
2281 ui.status(_('grafting %s\n') % desc)
2281 ui.status(_('grafting %s\n') % desc)
2282 if opts.get('dry_run'):
2282 if opts.get('dry_run'):
2283 continue
2283 continue
2284
2284
2285 source = ctx.extra().get('source')
2285 source = ctx.extra().get('source')
2286 extra = {}
2286 extra = {}
2287 if source:
2287 if source:
2288 extra['source'] = source
2288 extra['source'] = source
2289 extra['intermediate-source'] = ctx.hex()
2289 extra['intermediate-source'] = ctx.hex()
2290 else:
2290 else:
2291 extra['source'] = ctx.hex()
2291 extra['source'] = ctx.hex()
2292 user = ctx.user()
2292 user = ctx.user()
2293 if opts.get('user'):
2293 if opts.get('user'):
2294 user = opts['user']
2294 user = opts['user']
2295 date = ctx.date()
2295 date = ctx.date()
2296 if opts.get('date'):
2296 if opts.get('date'):
2297 date = opts['date']
2297 date = opts['date']
2298 message = ctx.description()
2298 message = ctx.description()
2299 if opts.get('log'):
2299 if opts.get('log'):
2300 message += '\n(grafted from %s)' % ctx.hex()
2300 message += '\n(grafted from %s)' % ctx.hex()
2301
2301
2302 # we don't merge the first commit when continuing
2302 # we don't merge the first commit when continuing
2303 if not cont:
2303 if not cont:
2304 # perform the graft merge with p1(rev) as 'ancestor'
2304 # perform the graft merge with p1(rev) as 'ancestor'
2305 try:
2305 try:
2306 # ui.forcemerge is an internal variable, do not document
2306 # ui.forcemerge is an internal variable, do not document
2307 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
2307 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
2308 'graft')
2308 'graft')
2309 stats = mergemod.graft(repo, ctx, ctx.p1(),
2309 stats = mergemod.graft(repo, ctx, ctx.p1(),
2310 ['local', 'graft'])
2310 ['local', 'graft'])
2311 finally:
2311 finally:
2312 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
2312 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
2313 # report any conflicts
2313 # report any conflicts
2314 if stats.unresolvedcount > 0:
2314 if stats.unresolvedcount > 0:
2315 # write out state for --continue
2315 # write out state for --continue
2316 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2316 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2317 repo.vfs.write('graftstate', ''.join(nodelines))
2317 repo.vfs.write('graftstate', ''.join(nodelines))
2318 extra = ''
2318 extra = ''
2319 if opts.get('user'):
2319 if opts.get('user'):
2320 extra += ' --user %s' % procutil.shellquote(opts['user'])
2320 extra += ' --user %s' % procutil.shellquote(opts['user'])
2321 if opts.get('date'):
2321 if opts.get('date'):
2322 extra += ' --date %s' % procutil.shellquote(opts['date'])
2322 extra += ' --date %s' % procutil.shellquote(opts['date'])
2323 if opts.get('log'):
2323 if opts.get('log'):
2324 extra += ' --log'
2324 extra += ' --log'
2325 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
2325 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
2326 raise error.Abort(
2326 raise error.Abort(
2327 _("unresolved conflicts, can't continue"),
2327 _("unresolved conflicts, can't continue"),
2328 hint=hint)
2328 hint=hint)
2329 else:
2329 else:
2330 cont = False
2330 cont = False
2331
2331
2332 # commit
2332 # commit
2333 node = repo.commit(text=message, user=user,
2333 node = repo.commit(text=message, user=user,
2334 date=date, extra=extra, editor=editor)
2334 date=date, extra=extra, editor=editor)
2335 if node is None:
2335 if node is None:
2336 ui.warn(
2336 ui.warn(
2337 _('note: graft of %d:%s created no changes to commit\n') %
2337 _('note: graft of %d:%s created no changes to commit\n') %
2338 (ctx.rev(), ctx))
2338 (ctx.rev(), ctx))
2339
2339
2340 # remove state when we complete successfully
2340 # remove state when we complete successfully
2341 if not opts.get('dry_run'):
2341 if not opts.get('dry_run'):
2342 repo.vfs.unlinkpath('graftstate', ignoremissing=True)
2342 repo.vfs.unlinkpath('graftstate', ignoremissing=True)
2343
2343
2344 return 0
2344 return 0
2345
2345
2346 @command('grep',
2346 @command('grep',
2347 [('0', 'print0', None, _('end fields with NUL')),
2347 [('0', 'print0', None, _('end fields with NUL')),
2348 ('', 'all', None, _('print all revisions that match')),
2348 ('', 'all', None, _('print all revisions that match')),
2349 ('a', 'text', None, _('treat all files as text')),
2349 ('a', 'text', None, _('treat all files as text')),
2350 ('f', 'follow', None,
2350 ('f', 'follow', None,
2351 _('follow changeset history,'
2351 _('follow changeset history,'
2352 ' or file history across copies and renames')),
2352 ' or file history across copies and renames')),
2353 ('i', 'ignore-case', None, _('ignore case when matching')),
2353 ('i', 'ignore-case', None, _('ignore case when matching')),
2354 ('l', 'files-with-matches', None,
2354 ('l', 'files-with-matches', None,
2355 _('print only filenames and revisions that match')),
2355 _('print only filenames and revisions that match')),
2356 ('n', 'line-number', None, _('print matching line numbers')),
2356 ('n', 'line-number', None, _('print matching line numbers')),
2357 ('r', 'rev', [],
2357 ('r', 'rev', [],
2358 _('only search files changed within revision range'), _('REV')),
2358 _('only search files changed within revision range'), _('REV')),
2359 ('u', 'user', None, _('list the author (long with -v)')),
2359 ('u', 'user', None, _('list the author (long with -v)')),
2360 ('d', 'date', None, _('list the date (short with -q)')),
2360 ('d', 'date', None, _('list the date (short with -q)')),
2361 ] + formatteropts + walkopts,
2361 ] + formatteropts + walkopts,
2362 _('[OPTION]... PATTERN [FILE]...'),
2362 _('[OPTION]... PATTERN [FILE]...'),
2363 inferrepo=True, cmdtype=readonly)
2363 inferrepo=True, cmdtype=readonly)
2364 def grep(ui, repo, pattern, *pats, **opts):
2364 def grep(ui, repo, pattern, *pats, **opts):
2365 """search revision history for a pattern in specified files
2365 """search revision history for a pattern in specified files
2366
2366
2367 Search revision history for a regular expression in the specified
2367 Search revision history for a regular expression in the specified
2368 files or the entire project.
2368 files or the entire project.
2369
2369
2370 By default, grep prints the most recent revision number for each
2370 By default, grep prints the most recent revision number for each
2371 file in which it finds a match. To get it to print every revision
2371 file in which it finds a match. To get it to print every revision
2372 that contains a change in match status ("-" for a match that becomes
2372 that contains a change in match status ("-" for a match that becomes
2373 a non-match, or "+" for a non-match that becomes a match), use the
2373 a non-match, or "+" for a non-match that becomes a match), use the
2374 --all flag.
2374 --all flag.
2375
2375
2376 PATTERN can be any Python (roughly Perl-compatible) regular
2376 PATTERN can be any Python (roughly Perl-compatible) regular
2377 expression.
2377 expression.
2378
2378
2379 If no FILEs are specified (and -f/--follow isn't set), all files in
2379 If no FILEs are specified (and -f/--follow isn't set), all files in
2380 the repository are searched, including those that don't exist in the
2380 the repository are searched, including those that don't exist in the
2381 current branch or have been deleted in a prior changeset.
2381 current branch or have been deleted in a prior changeset.
2382
2382
2383 Returns 0 if a match is found, 1 otherwise.
2383 Returns 0 if a match is found, 1 otherwise.
2384 """
2384 """
2385 opts = pycompat.byteskwargs(opts)
2385 opts = pycompat.byteskwargs(opts)
2386 reflags = re.M
2386 reflags = re.M
2387 if opts.get('ignore_case'):
2387 if opts.get('ignore_case'):
2388 reflags |= re.I
2388 reflags |= re.I
2389 try:
2389 try:
2390 regexp = util.re.compile(pattern, reflags)
2390 regexp = util.re.compile(pattern, reflags)
2391 except re.error as inst:
2391 except re.error as inst:
2392 ui.warn(_("grep: invalid match pattern: %s\n") % pycompat.bytestr(inst))
2392 ui.warn(_("grep: invalid match pattern: %s\n") % pycompat.bytestr(inst))
2393 return 1
2393 return 1
2394 sep, eol = ':', '\n'
2394 sep, eol = ':', '\n'
2395 if opts.get('print0'):
2395 if opts.get('print0'):
2396 sep = eol = '\0'
2396 sep = eol = '\0'
2397
2397
2398 getfile = util.lrucachefunc(repo.file)
2398 getfile = util.lrucachefunc(repo.file)
2399
2399
2400 def matchlines(body):
2400 def matchlines(body):
2401 begin = 0
2401 begin = 0
2402 linenum = 0
2402 linenum = 0
2403 while begin < len(body):
2403 while begin < len(body):
2404 match = regexp.search(body, begin)
2404 match = regexp.search(body, begin)
2405 if not match:
2405 if not match:
2406 break
2406 break
2407 mstart, mend = match.span()
2407 mstart, mend = match.span()
2408 linenum += body.count('\n', begin, mstart) + 1
2408 linenum += body.count('\n', begin, mstart) + 1
2409 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2409 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2410 begin = body.find('\n', mend) + 1 or len(body) + 1
2410 begin = body.find('\n', mend) + 1 or len(body) + 1
2411 lend = begin - 1
2411 lend = begin - 1
2412 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2412 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2413
2413
2414 class linestate(object):
2414 class linestate(object):
2415 def __init__(self, line, linenum, colstart, colend):
2415 def __init__(self, line, linenum, colstart, colend):
2416 self.line = line
2416 self.line = line
2417 self.linenum = linenum
2417 self.linenum = linenum
2418 self.colstart = colstart
2418 self.colstart = colstart
2419 self.colend = colend
2419 self.colend = colend
2420
2420
2421 def __hash__(self):
2421 def __hash__(self):
2422 return hash((self.linenum, self.line))
2422 return hash((self.linenum, self.line))
2423
2423
2424 def __eq__(self, other):
2424 def __eq__(self, other):
2425 return self.line == other.line
2425 return self.line == other.line
2426
2426
2427 def findpos(self):
2427 def findpos(self):
2428 """Iterate all (start, end) indices of matches"""
2428 """Iterate all (start, end) indices of matches"""
2429 yield self.colstart, self.colend
2429 yield self.colstart, self.colend
2430 p = self.colend
2430 p = self.colend
2431 while p < len(self.line):
2431 while p < len(self.line):
2432 m = regexp.search(self.line, p)
2432 m = regexp.search(self.line, p)
2433 if not m:
2433 if not m:
2434 break
2434 break
2435 yield m.span()
2435 yield m.span()
2436 p = m.end()
2436 p = m.end()
2437
2437
2438 matches = {}
2438 matches = {}
2439 copies = {}
2439 copies = {}
2440 def grepbody(fn, rev, body):
2440 def grepbody(fn, rev, body):
2441 matches[rev].setdefault(fn, [])
2441 matches[rev].setdefault(fn, [])
2442 m = matches[rev][fn]
2442 m = matches[rev][fn]
2443 for lnum, cstart, cend, line in matchlines(body):
2443 for lnum, cstart, cend, line in matchlines(body):
2444 s = linestate(line, lnum, cstart, cend)
2444 s = linestate(line, lnum, cstart, cend)
2445 m.append(s)
2445 m.append(s)
2446
2446
2447 def difflinestates(a, b):
2447 def difflinestates(a, b):
2448 sm = difflib.SequenceMatcher(None, a, b)
2448 sm = difflib.SequenceMatcher(None, a, b)
2449 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2449 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2450 if tag == 'insert':
2450 if tag == 'insert':
2451 for i in xrange(blo, bhi):
2451 for i in xrange(blo, bhi):
2452 yield ('+', b[i])
2452 yield ('+', b[i])
2453 elif tag == 'delete':
2453 elif tag == 'delete':
2454 for i in xrange(alo, ahi):
2454 for i in xrange(alo, ahi):
2455 yield ('-', a[i])
2455 yield ('-', a[i])
2456 elif tag == 'replace':
2456 elif tag == 'replace':
2457 for i in xrange(alo, ahi):
2457 for i in xrange(alo, ahi):
2458 yield ('-', a[i])
2458 yield ('-', a[i])
2459 for i in xrange(blo, bhi):
2459 for i in xrange(blo, bhi):
2460 yield ('+', b[i])
2460 yield ('+', b[i])
2461
2461
2462 def display(fm, fn, ctx, pstates, states):
2462 def display(fm, fn, ctx, pstates, states):
2463 rev = ctx.rev()
2463 rev = ctx.rev()
2464 if fm.isplain():
2464 if fm.isplain():
2465 formatuser = ui.shortuser
2465 formatuser = ui.shortuser
2466 else:
2466 else:
2467 formatuser = str
2467 formatuser = str
2468 if ui.quiet:
2468 if ui.quiet:
2469 datefmt = '%Y-%m-%d'
2469 datefmt = '%Y-%m-%d'
2470 else:
2470 else:
2471 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2471 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2472 found = False
2472 found = False
2473 @util.cachefunc
2473 @util.cachefunc
2474 def binary():
2474 def binary():
2475 flog = getfile(fn)
2475 flog = getfile(fn)
2476 return stringutil.binary(flog.read(ctx.filenode(fn)))
2476 return stringutil.binary(flog.read(ctx.filenode(fn)))
2477
2477
2478 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
2478 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
2479 if opts.get('all'):
2479 if opts.get('all'):
2480 iter = difflinestates(pstates, states)
2480 iter = difflinestates(pstates, states)
2481 else:
2481 else:
2482 iter = [('', l) for l in states]
2482 iter = [('', l) for l in states]
2483 for change, l in iter:
2483 for change, l in iter:
2484 fm.startitem()
2484 fm.startitem()
2485 fm.data(node=fm.hexfunc(ctx.node()))
2485 fm.data(node=fm.hexfunc(ctx.node()))
2486 cols = [
2486 cols = [
2487 ('filename', fn, True),
2487 ('filename', fn, True),
2488 ('rev', rev, True),
2488 ('rev', rev, True),
2489 ('linenumber', l.linenum, opts.get('line_number')),
2489 ('linenumber', l.linenum, opts.get('line_number')),
2490 ]
2490 ]
2491 if opts.get('all'):
2491 if opts.get('all'):
2492 cols.append(('change', change, True))
2492 cols.append(('change', change, True))
2493 cols.extend([
2493 cols.extend([
2494 ('user', formatuser(ctx.user()), opts.get('user')),
2494 ('user', formatuser(ctx.user()), opts.get('user')),
2495 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
2495 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
2496 ])
2496 ])
2497 lastcol = next(name for name, data, cond in reversed(cols) if cond)
2497 lastcol = next(name for name, data, cond in reversed(cols) if cond)
2498 for name, data, cond in cols:
2498 for name, data, cond in cols:
2499 field = fieldnamemap.get(name, name)
2499 field = fieldnamemap.get(name, name)
2500 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
2500 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
2501 if cond and name != lastcol:
2501 if cond and name != lastcol:
2502 fm.plain(sep, label='grep.sep')
2502 fm.plain(sep, label='grep.sep')
2503 if not opts.get('files_with_matches'):
2503 if not opts.get('files_with_matches'):
2504 fm.plain(sep, label='grep.sep')
2504 fm.plain(sep, label='grep.sep')
2505 if not opts.get('text') and binary():
2505 if not opts.get('text') and binary():
2506 fm.plain(_(" Binary file matches"))
2506 fm.plain(_(" Binary file matches"))
2507 else:
2507 else:
2508 displaymatches(fm.nested('texts'), l)
2508 displaymatches(fm.nested('texts'), l)
2509 fm.plain(eol)
2509 fm.plain(eol)
2510 found = True
2510 found = True
2511 if opts.get('files_with_matches'):
2511 if opts.get('files_with_matches'):
2512 break
2512 break
2513 return found
2513 return found
2514
2514
2515 def displaymatches(fm, l):
2515 def displaymatches(fm, l):
2516 p = 0
2516 p = 0
2517 for s, e in l.findpos():
2517 for s, e in l.findpos():
2518 if p < s:
2518 if p < s:
2519 fm.startitem()
2519 fm.startitem()
2520 fm.write('text', '%s', l.line[p:s])
2520 fm.write('text', '%s', l.line[p:s])
2521 fm.data(matched=False)
2521 fm.data(matched=False)
2522 fm.startitem()
2522 fm.startitem()
2523 fm.write('text', '%s', l.line[s:e], label='grep.match')
2523 fm.write('text', '%s', l.line[s:e], label='grep.match')
2524 fm.data(matched=True)
2524 fm.data(matched=True)
2525 p = e
2525 p = e
2526 if p < len(l.line):
2526 if p < len(l.line):
2527 fm.startitem()
2527 fm.startitem()
2528 fm.write('text', '%s', l.line[p:])
2528 fm.write('text', '%s', l.line[p:])
2529 fm.data(matched=False)
2529 fm.data(matched=False)
2530 fm.end()
2530 fm.end()
2531
2531
2532 skip = {}
2532 skip = {}
2533 revfiles = {}
2533 revfiles = {}
2534 match = scmutil.match(repo[None], pats, opts)
2534 match = scmutil.match(repo[None], pats, opts)
2535 found = False
2535 found = False
2536 follow = opts.get('follow')
2536 follow = opts.get('follow')
2537
2537
2538 def prep(ctx, fns):
2538 def prep(ctx, fns):
2539 rev = ctx.rev()
2539 rev = ctx.rev()
2540 pctx = ctx.p1()
2540 pctx = ctx.p1()
2541 parent = pctx.rev()
2541 parent = pctx.rev()
2542 matches.setdefault(rev, {})
2542 matches.setdefault(rev, {})
2543 matches.setdefault(parent, {})
2543 matches.setdefault(parent, {})
2544 files = revfiles.setdefault(rev, [])
2544 files = revfiles.setdefault(rev, [])
2545 for fn in fns:
2545 for fn in fns:
2546 flog = getfile(fn)
2546 flog = getfile(fn)
2547 try:
2547 try:
2548 fnode = ctx.filenode(fn)
2548 fnode = ctx.filenode(fn)
2549 except error.LookupError:
2549 except error.LookupError:
2550 continue
2550 continue
2551
2551
2552 copied = flog.renamed(fnode)
2552 copied = flog.renamed(fnode)
2553 copy = follow and copied and copied[0]
2553 copy = follow and copied and copied[0]
2554 if copy:
2554 if copy:
2555 copies.setdefault(rev, {})[fn] = copy
2555 copies.setdefault(rev, {})[fn] = copy
2556 if fn in skip:
2556 if fn in skip:
2557 if copy:
2557 if copy:
2558 skip[copy] = True
2558 skip[copy] = True
2559 continue
2559 continue
2560 files.append(fn)
2560 files.append(fn)
2561
2561
2562 if fn not in matches[rev]:
2562 if fn not in matches[rev]:
2563 grepbody(fn, rev, flog.read(fnode))
2563 grepbody(fn, rev, flog.read(fnode))
2564
2564
2565 pfn = copy or fn
2565 pfn = copy or fn
2566 if pfn not in matches[parent]:
2566 if pfn not in matches[parent]:
2567 try:
2567 try:
2568 fnode = pctx.filenode(pfn)
2568 fnode = pctx.filenode(pfn)
2569 grepbody(pfn, parent, flog.read(fnode))
2569 grepbody(pfn, parent, flog.read(fnode))
2570 except error.LookupError:
2570 except error.LookupError:
2571 pass
2571 pass
2572
2572
2573 ui.pager('grep')
2573 ui.pager('grep')
2574 fm = ui.formatter('grep', opts)
2574 fm = ui.formatter('grep', opts)
2575 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
2575 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
2576 rev = ctx.rev()
2576 rev = ctx.rev()
2577 parent = ctx.p1().rev()
2577 parent = ctx.p1().rev()
2578 for fn in sorted(revfiles.get(rev, [])):
2578 for fn in sorted(revfiles.get(rev, [])):
2579 states = matches[rev][fn]
2579 states = matches[rev][fn]
2580 copy = copies.get(rev, {}).get(fn)
2580 copy = copies.get(rev, {}).get(fn)
2581 if fn in skip:
2581 if fn in skip:
2582 if copy:
2582 if copy:
2583 skip[copy] = True
2583 skip[copy] = True
2584 continue
2584 continue
2585 pstates = matches.get(parent, {}).get(copy or fn, [])
2585 pstates = matches.get(parent, {}).get(copy or fn, [])
2586 if pstates or states:
2586 if pstates or states:
2587 r = display(fm, fn, ctx, pstates, states)
2587 r = display(fm, fn, ctx, pstates, states)
2588 found = found or r
2588 found = found or r
2589 if r and not opts.get('all'):
2589 if r and not opts.get('all'):
2590 skip[fn] = True
2590 skip[fn] = True
2591 if copy:
2591 if copy:
2592 skip[copy] = True
2592 skip[copy] = True
2593 del revfiles[rev]
2593 del revfiles[rev]
2594 # We will keep the matches dict for the duration of the window
2594 # We will keep the matches dict for the duration of the window
2595 # clear the matches dict once the window is over
2595 # clear the matches dict once the window is over
2596 if not revfiles:
2596 if not revfiles:
2597 matches.clear()
2597 matches.clear()
2598 fm.end()
2598 fm.end()
2599
2599
2600 return not found
2600 return not found
2601
2601
2602 @command('heads',
2602 @command('heads',
2603 [('r', 'rev', '',
2603 [('r', 'rev', '',
2604 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2604 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2605 ('t', 'topo', False, _('show topological heads only')),
2605 ('t', 'topo', False, _('show topological heads only')),
2606 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2606 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2607 ('c', 'closed', False, _('show normal and closed branch heads')),
2607 ('c', 'closed', False, _('show normal and closed branch heads')),
2608 ] + templateopts,
2608 ] + templateopts,
2609 _('[-ct] [-r STARTREV] [REV]...'), cmdtype=readonly)
2609 _('[-ct] [-r STARTREV] [REV]...'), cmdtype=readonly)
2610 def heads(ui, repo, *branchrevs, **opts):
2610 def heads(ui, repo, *branchrevs, **opts):
2611 """show branch heads
2611 """show branch heads
2612
2612
2613 With no arguments, show all open branch heads in the repository.
2613 With no arguments, show all open branch heads in the repository.
2614 Branch heads are changesets that have no descendants on the
2614 Branch heads are changesets that have no descendants on the
2615 same branch. They are where development generally takes place and
2615 same branch. They are where development generally takes place and
2616 are the usual targets for update and merge operations.
2616 are the usual targets for update and merge operations.
2617
2617
2618 If one or more REVs are given, only open branch heads on the
2618 If one or more REVs are given, only open branch heads on the
2619 branches associated with the specified changesets are shown. This
2619 branches associated with the specified changesets are shown. This
2620 means that you can use :hg:`heads .` to see the heads on the
2620 means that you can use :hg:`heads .` to see the heads on the
2621 currently checked-out branch.
2621 currently checked-out branch.
2622
2622
2623 If -c/--closed is specified, also show branch heads marked closed
2623 If -c/--closed is specified, also show branch heads marked closed
2624 (see :hg:`commit --close-branch`).
2624 (see :hg:`commit --close-branch`).
2625
2625
2626 If STARTREV is specified, only those heads that are descendants of
2626 If STARTREV is specified, only those heads that are descendants of
2627 STARTREV will be displayed.
2627 STARTREV will be displayed.
2628
2628
2629 If -t/--topo is specified, named branch mechanics will be ignored and only
2629 If -t/--topo is specified, named branch mechanics will be ignored and only
2630 topological heads (changesets with no children) will be shown.
2630 topological heads (changesets with no children) will be shown.
2631
2631
2632 Returns 0 if matching heads are found, 1 if not.
2632 Returns 0 if matching heads are found, 1 if not.
2633 """
2633 """
2634
2634
2635 opts = pycompat.byteskwargs(opts)
2635 opts = pycompat.byteskwargs(opts)
2636 start = None
2636 start = None
2637 rev = opts.get('rev')
2637 rev = opts.get('rev')
2638 if rev:
2638 if rev:
2639 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2639 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2640 start = scmutil.revsingle(repo, rev, None).node()
2640 start = scmutil.revsingle(repo, rev, None).node()
2641
2641
2642 if opts.get('topo'):
2642 if opts.get('topo'):
2643 heads = [repo[h] for h in repo.heads(start)]
2643 heads = [repo[h] for h in repo.heads(start)]
2644 else:
2644 else:
2645 heads = []
2645 heads = []
2646 for branch in repo.branchmap():
2646 for branch in repo.branchmap():
2647 heads += repo.branchheads(branch, start, opts.get('closed'))
2647 heads += repo.branchheads(branch, start, opts.get('closed'))
2648 heads = [repo[h] for h in heads]
2648 heads = [repo[h] for h in heads]
2649
2649
2650 if branchrevs:
2650 if branchrevs:
2651 branches = set(repo[r].branch()
2651 branches = set(repo[r].branch()
2652 for r in scmutil.revrange(repo, branchrevs))
2652 for r in scmutil.revrange(repo, branchrevs))
2653 heads = [h for h in heads if h.branch() in branches]
2653 heads = [h for h in heads if h.branch() in branches]
2654
2654
2655 if opts.get('active') and branchrevs:
2655 if opts.get('active') and branchrevs:
2656 dagheads = repo.heads(start)
2656 dagheads = repo.heads(start)
2657 heads = [h for h in heads if h.node() in dagheads]
2657 heads = [h for h in heads if h.node() in dagheads]
2658
2658
2659 if branchrevs:
2659 if branchrevs:
2660 haveheads = set(h.branch() for h in heads)
2660 haveheads = set(h.branch() for h in heads)
2661 if branches - haveheads:
2661 if branches - haveheads:
2662 headless = ', '.join(b for b in branches - haveheads)
2662 headless = ', '.join(b for b in branches - haveheads)
2663 msg = _('no open branch heads found on branches %s')
2663 msg = _('no open branch heads found on branches %s')
2664 if opts.get('rev'):
2664 if opts.get('rev'):
2665 msg += _(' (started at %s)') % opts['rev']
2665 msg += _(' (started at %s)') % opts['rev']
2666 ui.warn((msg + '\n') % headless)
2666 ui.warn((msg + '\n') % headless)
2667
2667
2668 if not heads:
2668 if not heads:
2669 return 1
2669 return 1
2670
2670
2671 ui.pager('heads')
2671 ui.pager('heads')
2672 heads = sorted(heads, key=lambda x: -x.rev())
2672 heads = sorted(heads, key=lambda x: -x.rev())
2673 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
2673 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
2674 for ctx in heads:
2674 for ctx in heads:
2675 displayer.show(ctx)
2675 displayer.show(ctx)
2676 displayer.close()
2676 displayer.close()
2677
2677
2678 @command('help',
2678 @command('help',
2679 [('e', 'extension', None, _('show only help for extensions')),
2679 [('e', 'extension', None, _('show only help for extensions')),
2680 ('c', 'command', None, _('show only help for commands')),
2680 ('c', 'command', None, _('show only help for commands')),
2681 ('k', 'keyword', None, _('show topics matching keyword')),
2681 ('k', 'keyword', None, _('show topics matching keyword')),
2682 ('s', 'system', [], _('show help for specific platform(s)')),
2682 ('s', 'system', [], _('show help for specific platform(s)')),
2683 ],
2683 ],
2684 _('[-ecks] [TOPIC]'),
2684 _('[-ecks] [TOPIC]'),
2685 norepo=True, cmdtype=readonly)
2685 norepo=True, cmdtype=readonly)
2686 def help_(ui, name=None, **opts):
2686 def help_(ui, name=None, **opts):
2687 """show help for a given topic or a help overview
2687 """show help for a given topic or a help overview
2688
2688
2689 With no arguments, print a list of commands with short help messages.
2689 With no arguments, print a list of commands with short help messages.
2690
2690
2691 Given a topic, extension, or command name, print help for that
2691 Given a topic, extension, or command name, print help for that
2692 topic.
2692 topic.
2693
2693
2694 Returns 0 if successful.
2694 Returns 0 if successful.
2695 """
2695 """
2696
2696
2697 keep = opts.get(r'system') or []
2697 keep = opts.get(r'system') or []
2698 if len(keep) == 0:
2698 if len(keep) == 0:
2699 if pycompat.sysplatform.startswith('win'):
2699 if pycompat.sysplatform.startswith('win'):
2700 keep.append('windows')
2700 keep.append('windows')
2701 elif pycompat.sysplatform == 'OpenVMS':
2701 elif pycompat.sysplatform == 'OpenVMS':
2702 keep.append('vms')
2702 keep.append('vms')
2703 elif pycompat.sysplatform == 'plan9':
2703 elif pycompat.sysplatform == 'plan9':
2704 keep.append('plan9')
2704 keep.append('plan9')
2705 else:
2705 else:
2706 keep.append('unix')
2706 keep.append('unix')
2707 keep.append(pycompat.sysplatform.lower())
2707 keep.append(pycompat.sysplatform.lower())
2708 if ui.verbose:
2708 if ui.verbose:
2709 keep.append('verbose')
2709 keep.append('verbose')
2710
2710
2711 commands = sys.modules[__name__]
2711 commands = sys.modules[__name__]
2712 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
2712 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
2713 ui.pager('help')
2713 ui.pager('help')
2714 ui.write(formatted)
2714 ui.write(formatted)
2715
2715
2716
2716
2717 @command('identify|id',
2717 @command('identify|id',
2718 [('r', 'rev', '',
2718 [('r', 'rev', '',
2719 _('identify the specified revision'), _('REV')),
2719 _('identify the specified revision'), _('REV')),
2720 ('n', 'num', None, _('show local revision number')),
2720 ('n', 'num', None, _('show local revision number')),
2721 ('i', 'id', None, _('show global revision id')),
2721 ('i', 'id', None, _('show global revision id')),
2722 ('b', 'branch', None, _('show branch')),
2722 ('b', 'branch', None, _('show branch')),
2723 ('t', 'tags', None, _('show tags')),
2723 ('t', 'tags', None, _('show tags')),
2724 ('B', 'bookmarks', None, _('show bookmarks')),
2724 ('B', 'bookmarks', None, _('show bookmarks')),
2725 ] + remoteopts + formatteropts,
2725 ] + remoteopts + formatteropts,
2726 _('[-nibtB] [-r REV] [SOURCE]'),
2726 _('[-nibtB] [-r REV] [SOURCE]'),
2727 optionalrepo=True, cmdtype=readonly)
2727 optionalrepo=True, cmdtype=readonly)
2728 def identify(ui, repo, source=None, rev=None,
2728 def identify(ui, repo, source=None, rev=None,
2729 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
2729 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
2730 """identify the working directory or specified revision
2730 """identify the working directory or specified revision
2731
2731
2732 Print a summary identifying the repository state at REV using one or
2732 Print a summary identifying the repository state at REV using one or
2733 two parent hash identifiers, followed by a "+" if the working
2733 two parent hash identifiers, followed by a "+" if the working
2734 directory has uncommitted changes, the branch name (if not default),
2734 directory has uncommitted changes, the branch name (if not default),
2735 a list of tags, and a list of bookmarks.
2735 a list of tags, and a list of bookmarks.
2736
2736
2737 When REV is not given, print a summary of the current state of the
2737 When REV is not given, print a summary of the current state of the
2738 repository including the working directory. Specify -r. to get information
2738 repository including the working directory. Specify -r. to get information
2739 of the working directory parent without scanning uncommitted changes.
2739 of the working directory parent without scanning uncommitted changes.
2740
2740
2741 Specifying a path to a repository root or Mercurial bundle will
2741 Specifying a path to a repository root or Mercurial bundle will
2742 cause lookup to operate on that repository/bundle.
2742 cause lookup to operate on that repository/bundle.
2743
2743
2744 .. container:: verbose
2744 .. container:: verbose
2745
2745
2746 Examples:
2746 Examples:
2747
2747
2748 - generate a build identifier for the working directory::
2748 - generate a build identifier for the working directory::
2749
2749
2750 hg id --id > build-id.dat
2750 hg id --id > build-id.dat
2751
2751
2752 - find the revision corresponding to a tag::
2752 - find the revision corresponding to a tag::
2753
2753
2754 hg id -n -r 1.3
2754 hg id -n -r 1.3
2755
2755
2756 - check the most recent revision of a remote repository::
2756 - check the most recent revision of a remote repository::
2757
2757
2758 hg id -r tip https://www.mercurial-scm.org/repo/hg/
2758 hg id -r tip https://www.mercurial-scm.org/repo/hg/
2759
2759
2760 See :hg:`log` for generating more information about specific revisions,
2760 See :hg:`log` for generating more information about specific revisions,
2761 including full hash identifiers.
2761 including full hash identifiers.
2762
2762
2763 Returns 0 if successful.
2763 Returns 0 if successful.
2764 """
2764 """
2765
2765
2766 opts = pycompat.byteskwargs(opts)
2766 opts = pycompat.byteskwargs(opts)
2767 if not repo and not source:
2767 if not repo and not source:
2768 raise error.Abort(_("there is no Mercurial repository here "
2768 raise error.Abort(_("there is no Mercurial repository here "
2769 "(.hg not found)"))
2769 "(.hg not found)"))
2770
2770
2771 if ui.debugflag:
2771 if ui.debugflag:
2772 hexfunc = hex
2772 hexfunc = hex
2773 else:
2773 else:
2774 hexfunc = short
2774 hexfunc = short
2775 default = not (num or id or branch or tags or bookmarks)
2775 default = not (num or id or branch or tags or bookmarks)
2776 output = []
2776 output = []
2777 revs = []
2777 revs = []
2778
2778
2779 if source:
2779 if source:
2780 source, branches = hg.parseurl(ui.expandpath(source))
2780 source, branches = hg.parseurl(ui.expandpath(source))
2781 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
2781 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
2782 repo = peer.local()
2782 repo = peer.local()
2783 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
2783 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
2784
2784
2785 fm = ui.formatter('identify', opts)
2785 fm = ui.formatter('identify', opts)
2786 fm.startitem()
2786 fm.startitem()
2787
2787
2788 if not repo:
2788 if not repo:
2789 if num or branch or tags:
2789 if num or branch or tags:
2790 raise error.Abort(
2790 raise error.Abort(
2791 _("can't query remote revision number, branch, or tags"))
2791 _("can't query remote revision number, branch, or tags"))
2792 if not rev and revs:
2792 if not rev and revs:
2793 rev = revs[0]
2793 rev = revs[0]
2794 if not rev:
2794 if not rev:
2795 rev = "tip"
2795 rev = "tip"
2796
2796
2797 remoterev = peer.lookup(rev)
2797 remoterev = peer.lookup(rev)
2798 hexrev = hexfunc(remoterev)
2798 hexrev = hexfunc(remoterev)
2799 if default or id:
2799 if default or id:
2800 output = [hexrev]
2800 output = [hexrev]
2801 fm.data(id=hexrev)
2801 fm.data(id=hexrev)
2802
2802
2803 def getbms():
2803 def getbms():
2804 bms = []
2804 bms = []
2805
2805
2806 if 'bookmarks' in peer.listkeys('namespaces'):
2806 if 'bookmarks' in peer.listkeys('namespaces'):
2807 hexremoterev = hex(remoterev)
2807 hexremoterev = hex(remoterev)
2808 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
2808 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
2809 if bmr == hexremoterev]
2809 if bmr == hexremoterev]
2810
2810
2811 return sorted(bms)
2811 return sorted(bms)
2812
2812
2813 bms = getbms()
2813 bms = getbms()
2814 if bookmarks:
2814 if bookmarks:
2815 output.extend(bms)
2815 output.extend(bms)
2816 elif default and not ui.quiet:
2816 elif default and not ui.quiet:
2817 # multiple bookmarks for a single parent separated by '/'
2817 # multiple bookmarks for a single parent separated by '/'
2818 bm = '/'.join(bms)
2818 bm = '/'.join(bms)
2819 if bm:
2819 if bm:
2820 output.append(bm)
2820 output.append(bm)
2821
2821
2822 fm.data(node=hex(remoterev))
2822 fm.data(node=hex(remoterev))
2823 fm.data(bookmarks=fm.formatlist(bms, name='bookmark'))
2823 fm.data(bookmarks=fm.formatlist(bms, name='bookmark'))
2824 else:
2824 else:
2825 if rev:
2825 if rev:
2826 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2826 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2827 ctx = scmutil.revsingle(repo, rev, None)
2827 ctx = scmutil.revsingle(repo, rev, None)
2828
2828
2829 if ctx.rev() is None:
2829 if ctx.rev() is None:
2830 ctx = repo[None]
2830 ctx = repo[None]
2831 parents = ctx.parents()
2831 parents = ctx.parents()
2832 taglist = []
2832 taglist = []
2833 for p in parents:
2833 for p in parents:
2834 taglist.extend(p.tags())
2834 taglist.extend(p.tags())
2835
2835
2836 dirty = ""
2836 dirty = ""
2837 if ctx.dirty(missing=True, merge=False, branch=False):
2837 if ctx.dirty(missing=True, merge=False, branch=False):
2838 dirty = '+'
2838 dirty = '+'
2839 fm.data(dirty=dirty)
2839 fm.data(dirty=dirty)
2840
2840
2841 hexoutput = [hexfunc(p.node()) for p in parents]
2841 hexoutput = [hexfunc(p.node()) for p in parents]
2842 if default or id:
2842 if default or id:
2843 output = ["%s%s" % ('+'.join(hexoutput), dirty)]
2843 output = ["%s%s" % ('+'.join(hexoutput), dirty)]
2844 fm.data(id="%s%s" % ('+'.join(hexoutput), dirty))
2844 fm.data(id="%s%s" % ('+'.join(hexoutput), dirty))
2845
2845
2846 if num:
2846 if num:
2847 numoutput = ["%d" % p.rev() for p in parents]
2847 numoutput = ["%d" % p.rev() for p in parents]
2848 output.append("%s%s" % ('+'.join(numoutput), dirty))
2848 output.append("%s%s" % ('+'.join(numoutput), dirty))
2849
2849
2850 fn = fm.nested('parents')
2850 fn = fm.nested('parents')
2851 for p in parents:
2851 for p in parents:
2852 fn.startitem()
2852 fn.startitem()
2853 fn.data(rev=p.rev())
2853 fn.data(rev=p.rev())
2854 fn.data(node=p.hex())
2854 fn.data(node=p.hex())
2855 fn.context(ctx=p)
2855 fn.context(ctx=p)
2856 fn.end()
2856 fn.end()
2857 else:
2857 else:
2858 hexoutput = hexfunc(ctx.node())
2858 hexoutput = hexfunc(ctx.node())
2859 if default or id:
2859 if default or id:
2860 output = [hexoutput]
2860 output = [hexoutput]
2861 fm.data(id=hexoutput)
2861 fm.data(id=hexoutput)
2862
2862
2863 if num:
2863 if num:
2864 output.append(pycompat.bytestr(ctx.rev()))
2864 output.append(pycompat.bytestr(ctx.rev()))
2865 taglist = ctx.tags()
2865 taglist = ctx.tags()
2866
2866
2867 if default and not ui.quiet:
2867 if default and not ui.quiet:
2868 b = ctx.branch()
2868 b = ctx.branch()
2869 if b != 'default':
2869 if b != 'default':
2870 output.append("(%s)" % b)
2870 output.append("(%s)" % b)
2871
2871
2872 # multiple tags for a single parent separated by '/'
2872 # multiple tags for a single parent separated by '/'
2873 t = '/'.join(taglist)
2873 t = '/'.join(taglist)
2874 if t:
2874 if t:
2875 output.append(t)
2875 output.append(t)
2876
2876
2877 # multiple bookmarks for a single parent separated by '/'
2877 # multiple bookmarks for a single parent separated by '/'
2878 bm = '/'.join(ctx.bookmarks())
2878 bm = '/'.join(ctx.bookmarks())
2879 if bm:
2879 if bm:
2880 output.append(bm)
2880 output.append(bm)
2881 else:
2881 else:
2882 if branch:
2882 if branch:
2883 output.append(ctx.branch())
2883 output.append(ctx.branch())
2884
2884
2885 if tags:
2885 if tags:
2886 output.extend(taglist)
2886 output.extend(taglist)
2887
2887
2888 if bookmarks:
2888 if bookmarks:
2889 output.extend(ctx.bookmarks())
2889 output.extend(ctx.bookmarks())
2890
2890
2891 fm.data(node=ctx.hex())
2891 fm.data(node=ctx.hex())
2892 fm.data(branch=ctx.branch())
2892 fm.data(branch=ctx.branch())
2893 fm.data(tags=fm.formatlist(taglist, name='tag', sep=':'))
2893 fm.data(tags=fm.formatlist(taglist, name='tag', sep=':'))
2894 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name='bookmark'))
2894 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name='bookmark'))
2895 fm.context(ctx=ctx)
2895 fm.context(ctx=ctx)
2896
2896
2897 fm.plain("%s\n" % ' '.join(output))
2897 fm.plain("%s\n" % ' '.join(output))
2898 fm.end()
2898 fm.end()
2899
2899
2900 @command('import|patch',
2900 @command('import|patch',
2901 [('p', 'strip', 1,
2901 [('p', 'strip', 1,
2902 _('directory strip option for patch. This has the same '
2902 _('directory strip option for patch. This has the same '
2903 'meaning as the corresponding patch option'), _('NUM')),
2903 'meaning as the corresponding patch option'), _('NUM')),
2904 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
2904 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
2905 ('e', 'edit', False, _('invoke editor on commit messages')),
2905 ('e', 'edit', False, _('invoke editor on commit messages')),
2906 ('f', 'force', None,
2906 ('f', 'force', None,
2907 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
2907 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
2908 ('', 'no-commit', None,
2908 ('', 'no-commit', None,
2909 _("don't commit, just update the working directory")),
2909 _("don't commit, just update the working directory")),
2910 ('', 'bypass', None,
2910 ('', 'bypass', None,
2911 _("apply patch without touching the working directory")),
2911 _("apply patch without touching the working directory")),
2912 ('', 'partial', None,
2912 ('', 'partial', None,
2913 _('commit even if some hunks fail')),
2913 _('commit even if some hunks fail')),
2914 ('', 'exact', None,
2914 ('', 'exact', None,
2915 _('abort if patch would apply lossily')),
2915 _('abort if patch would apply lossily')),
2916 ('', 'prefix', '',
2916 ('', 'prefix', '',
2917 _('apply patch to subdirectory'), _('DIR')),
2917 _('apply patch to subdirectory'), _('DIR')),
2918 ('', 'import-branch', None,
2918 ('', 'import-branch', None,
2919 _('use any branch information in patch (implied by --exact)'))] +
2919 _('use any branch information in patch (implied by --exact)'))] +
2920 commitopts + commitopts2 + similarityopts,
2920 commitopts + commitopts2 + similarityopts,
2921 _('[OPTION]... PATCH...'))
2921 _('[OPTION]... PATCH...'))
2922 def import_(ui, repo, patch1=None, *patches, **opts):
2922 def import_(ui, repo, patch1=None, *patches, **opts):
2923 """import an ordered set of patches
2923 """import an ordered set of patches
2924
2924
2925 Import a list of patches and commit them individually (unless
2925 Import a list of patches and commit them individually (unless
2926 --no-commit is specified).
2926 --no-commit is specified).
2927
2927
2928 To read a patch from standard input (stdin), use "-" as the patch
2928 To read a patch from standard input (stdin), use "-" as the patch
2929 name. If a URL is specified, the patch will be downloaded from
2929 name. If a URL is specified, the patch will be downloaded from
2930 there.
2930 there.
2931
2931
2932 Import first applies changes to the working directory (unless
2932 Import first applies changes to the working directory (unless
2933 --bypass is specified), import will abort if there are outstanding
2933 --bypass is specified), import will abort if there are outstanding
2934 changes.
2934 changes.
2935
2935
2936 Use --bypass to apply and commit patches directly to the
2936 Use --bypass to apply and commit patches directly to the
2937 repository, without affecting the working directory. Without
2937 repository, without affecting the working directory. Without
2938 --exact, patches will be applied on top of the working directory
2938 --exact, patches will be applied on top of the working directory
2939 parent revision.
2939 parent revision.
2940
2940
2941 You can import a patch straight from a mail message. Even patches
2941 You can import a patch straight from a mail message. Even patches
2942 as attachments work (to use the body part, it must have type
2942 as attachments work (to use the body part, it must have type
2943 text/plain or text/x-patch). From and Subject headers of email
2943 text/plain or text/x-patch). From and Subject headers of email
2944 message are used as default committer and commit message. All
2944 message are used as default committer and commit message. All
2945 text/plain body parts before first diff are added to the commit
2945 text/plain body parts before first diff are added to the commit
2946 message.
2946 message.
2947
2947
2948 If the imported patch was generated by :hg:`export`, user and
2948 If the imported patch was generated by :hg:`export`, user and
2949 description from patch override values from message headers and
2949 description from patch override values from message headers and
2950 body. Values given on command line with -m/--message and -u/--user
2950 body. Values given on command line with -m/--message and -u/--user
2951 override these.
2951 override these.
2952
2952
2953 If --exact is specified, import will set the working directory to
2953 If --exact is specified, import will set the working directory to
2954 the parent of each patch before applying it, and will abort if the
2954 the parent of each patch before applying it, and will abort if the
2955 resulting changeset has a different ID than the one recorded in
2955 resulting changeset has a different ID than the one recorded in
2956 the patch. This will guard against various ways that portable
2956 the patch. This will guard against various ways that portable
2957 patch formats and mail systems might fail to transfer Mercurial
2957 patch formats and mail systems might fail to transfer Mercurial
2958 data or metadata. See :hg:`bundle` for lossless transmission.
2958 data or metadata. See :hg:`bundle` for lossless transmission.
2959
2959
2960 Use --partial to ensure a changeset will be created from the patch
2960 Use --partial to ensure a changeset will be created from the patch
2961 even if some hunks fail to apply. Hunks that fail to apply will be
2961 even if some hunks fail to apply. Hunks that fail to apply will be
2962 written to a <target-file>.rej file. Conflicts can then be resolved
2962 written to a <target-file>.rej file. Conflicts can then be resolved
2963 by hand before :hg:`commit --amend` is run to update the created
2963 by hand before :hg:`commit --amend` is run to update the created
2964 changeset. This flag exists to let people import patches that
2964 changeset. This flag exists to let people import patches that
2965 partially apply without losing the associated metadata (author,
2965 partially apply without losing the associated metadata (author,
2966 date, description, ...).
2966 date, description, ...).
2967
2967
2968 .. note::
2968 .. note::
2969
2969
2970 When no hunks apply cleanly, :hg:`import --partial` will create
2970 When no hunks apply cleanly, :hg:`import --partial` will create
2971 an empty changeset, importing only the patch metadata.
2971 an empty changeset, importing only the patch metadata.
2972
2972
2973 With -s/--similarity, hg will attempt to discover renames and
2973 With -s/--similarity, hg will attempt to discover renames and
2974 copies in the patch in the same way as :hg:`addremove`.
2974 copies in the patch in the same way as :hg:`addremove`.
2975
2975
2976 It is possible to use external patch programs to perform the patch
2976 It is possible to use external patch programs to perform the patch
2977 by setting the ``ui.patch`` configuration option. For the default
2977 by setting the ``ui.patch`` configuration option. For the default
2978 internal tool, the fuzz can also be configured via ``patch.fuzz``.
2978 internal tool, the fuzz can also be configured via ``patch.fuzz``.
2979 See :hg:`help config` for more information about configuration
2979 See :hg:`help config` for more information about configuration
2980 files and how to use these options.
2980 files and how to use these options.
2981
2981
2982 See :hg:`help dates` for a list of formats valid for -d/--date.
2982 See :hg:`help dates` for a list of formats valid for -d/--date.
2983
2983
2984 .. container:: verbose
2984 .. container:: verbose
2985
2985
2986 Examples:
2986 Examples:
2987
2987
2988 - import a traditional patch from a website and detect renames::
2988 - import a traditional patch from a website and detect renames::
2989
2989
2990 hg import -s 80 http://example.com/bugfix.patch
2990 hg import -s 80 http://example.com/bugfix.patch
2991
2991
2992 - import a changeset from an hgweb server::
2992 - import a changeset from an hgweb server::
2993
2993
2994 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
2994 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
2995
2995
2996 - import all the patches in an Unix-style mbox::
2996 - import all the patches in an Unix-style mbox::
2997
2997
2998 hg import incoming-patches.mbox
2998 hg import incoming-patches.mbox
2999
2999
3000 - import patches from stdin::
3000 - import patches from stdin::
3001
3001
3002 hg import -
3002 hg import -
3003
3003
3004 - attempt to exactly restore an exported changeset (not always
3004 - attempt to exactly restore an exported changeset (not always
3005 possible)::
3005 possible)::
3006
3006
3007 hg import --exact proposed-fix.patch
3007 hg import --exact proposed-fix.patch
3008
3008
3009 - use an external tool to apply a patch which is too fuzzy for
3009 - use an external tool to apply a patch which is too fuzzy for
3010 the default internal tool.
3010 the default internal tool.
3011
3011
3012 hg import --config ui.patch="patch --merge" fuzzy.patch
3012 hg import --config ui.patch="patch --merge" fuzzy.patch
3013
3013
3014 - change the default fuzzing from 2 to a less strict 7
3014 - change the default fuzzing from 2 to a less strict 7
3015
3015
3016 hg import --config ui.fuzz=7 fuzz.patch
3016 hg import --config ui.fuzz=7 fuzz.patch
3017
3017
3018 Returns 0 on success, 1 on partial success (see --partial).
3018 Returns 0 on success, 1 on partial success (see --partial).
3019 """
3019 """
3020
3020
3021 opts = pycompat.byteskwargs(opts)
3021 opts = pycompat.byteskwargs(opts)
3022 if not patch1:
3022 if not patch1:
3023 raise error.Abort(_('need at least one patch to import'))
3023 raise error.Abort(_('need at least one patch to import'))
3024
3024
3025 patches = (patch1,) + patches
3025 patches = (patch1,) + patches
3026
3026
3027 date = opts.get('date')
3027 date = opts.get('date')
3028 if date:
3028 if date:
3029 opts['date'] = dateutil.parsedate(date)
3029 opts['date'] = dateutil.parsedate(date)
3030
3030
3031 exact = opts.get('exact')
3031 exact = opts.get('exact')
3032 update = not opts.get('bypass')
3032 update = not opts.get('bypass')
3033 if not update and opts.get('no_commit'):
3033 if not update and opts.get('no_commit'):
3034 raise error.Abort(_('cannot use --no-commit with --bypass'))
3034 raise error.Abort(_('cannot use --no-commit with --bypass'))
3035 try:
3035 try:
3036 sim = float(opts.get('similarity') or 0)
3036 sim = float(opts.get('similarity') or 0)
3037 except ValueError:
3037 except ValueError:
3038 raise error.Abort(_('similarity must be a number'))
3038 raise error.Abort(_('similarity must be a number'))
3039 if sim < 0 or sim > 100:
3039 if sim < 0 or sim > 100:
3040 raise error.Abort(_('similarity must be between 0 and 100'))
3040 raise error.Abort(_('similarity must be between 0 and 100'))
3041 if sim and not update:
3041 if sim and not update:
3042 raise error.Abort(_('cannot use --similarity with --bypass'))
3042 raise error.Abort(_('cannot use --similarity with --bypass'))
3043 if exact:
3043 if exact:
3044 if opts.get('edit'):
3044 if opts.get('edit'):
3045 raise error.Abort(_('cannot use --exact with --edit'))
3045 raise error.Abort(_('cannot use --exact with --edit'))
3046 if opts.get('prefix'):
3046 if opts.get('prefix'):
3047 raise error.Abort(_('cannot use --exact with --prefix'))
3047 raise error.Abort(_('cannot use --exact with --prefix'))
3048
3048
3049 base = opts["base"]
3049 base = opts["base"]
3050 wlock = dsguard = lock = tr = None
3050 wlock = dsguard = lock = tr = None
3051 msgs = []
3051 msgs = []
3052 ret = 0
3052 ret = 0
3053
3053
3054
3054
3055 try:
3055 try:
3056 wlock = repo.wlock()
3056 wlock = repo.wlock()
3057
3057
3058 if update:
3058 if update:
3059 cmdutil.checkunfinished(repo)
3059 cmdutil.checkunfinished(repo)
3060 if (exact or not opts.get('force')):
3060 if (exact or not opts.get('force')):
3061 cmdutil.bailifchanged(repo)
3061 cmdutil.bailifchanged(repo)
3062
3062
3063 if not opts.get('no_commit'):
3063 if not opts.get('no_commit'):
3064 lock = repo.lock()
3064 lock = repo.lock()
3065 tr = repo.transaction('import')
3065 tr = repo.transaction('import')
3066 else:
3066 else:
3067 dsguard = dirstateguard.dirstateguard(repo, 'import')
3067 dsguard = dirstateguard.dirstateguard(repo, 'import')
3068 parents = repo[None].parents()
3068 parents = repo[None].parents()
3069 for patchurl in patches:
3069 for patchurl in patches:
3070 if patchurl == '-':
3070 if patchurl == '-':
3071 ui.status(_('applying patch from stdin\n'))
3071 ui.status(_('applying patch from stdin\n'))
3072 patchfile = ui.fin
3072 patchfile = ui.fin
3073 patchurl = 'stdin' # for error message
3073 patchurl = 'stdin' # for error message
3074 else:
3074 else:
3075 patchurl = os.path.join(base, patchurl)
3075 patchurl = os.path.join(base, patchurl)
3076 ui.status(_('applying %s\n') % patchurl)
3076 ui.status(_('applying %s\n') % patchurl)
3077 patchfile = hg.openpath(ui, patchurl)
3077 patchfile = hg.openpath(ui, patchurl)
3078
3078
3079 haspatch = False
3079 haspatch = False
3080 for hunk in patch.split(patchfile):
3080 for hunk in patch.split(patchfile):
3081 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
3081 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
3082 parents, opts,
3082 parents, opts,
3083 msgs, hg.clean)
3083 msgs, hg.clean)
3084 if msg:
3084 if msg:
3085 haspatch = True
3085 haspatch = True
3086 ui.note(msg + '\n')
3086 ui.note(msg + '\n')
3087 if update or exact:
3087 if update or exact:
3088 parents = repo[None].parents()
3088 parents = repo[None].parents()
3089 else:
3089 else:
3090 parents = [repo[node]]
3090 parents = [repo[node]]
3091 if rej:
3091 if rej:
3092 ui.write_err(_("patch applied partially\n"))
3092 ui.write_err(_("patch applied partially\n"))
3093 ui.write_err(_("(fix the .rej files and run "
3093 ui.write_err(_("(fix the .rej files and run "
3094 "`hg commit --amend`)\n"))
3094 "`hg commit --amend`)\n"))
3095 ret = 1
3095 ret = 1
3096 break
3096 break
3097
3097
3098 if not haspatch:
3098 if not haspatch:
3099 raise error.Abort(_('%s: no diffs found') % patchurl)
3099 raise error.Abort(_('%s: no diffs found') % patchurl)
3100
3100
3101 if tr:
3101 if tr:
3102 tr.close()
3102 tr.close()
3103 if msgs:
3103 if msgs:
3104 repo.savecommitmessage('\n* * *\n'.join(msgs))
3104 repo.savecommitmessage('\n* * *\n'.join(msgs))
3105 if dsguard:
3105 if dsguard:
3106 dsguard.close()
3106 dsguard.close()
3107 return ret
3107 return ret
3108 finally:
3108 finally:
3109 if tr:
3109 if tr:
3110 tr.release()
3110 tr.release()
3111 release(lock, dsguard, wlock)
3111 release(lock, dsguard, wlock)
3112
3112
3113 @command('incoming|in',
3113 @command('incoming|in',
3114 [('f', 'force', None,
3114 [('f', 'force', None,
3115 _('run even if remote repository is unrelated')),
3115 _('run even if remote repository is unrelated')),
3116 ('n', 'newest-first', None, _('show newest record first')),
3116 ('n', 'newest-first', None, _('show newest record first')),
3117 ('', 'bundle', '',
3117 ('', 'bundle', '',
3118 _('file to store the bundles into'), _('FILE')),
3118 _('file to store the bundles into'), _('FILE')),
3119 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3119 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3120 ('B', 'bookmarks', False, _("compare bookmarks")),
3120 ('B', 'bookmarks', False, _("compare bookmarks")),
3121 ('b', 'branch', [],
3121 ('b', 'branch', [],
3122 _('a specific branch you would like to pull'), _('BRANCH')),
3122 _('a specific branch you would like to pull'), _('BRANCH')),
3123 ] + logopts + remoteopts + subrepoopts,
3123 ] + logopts + remoteopts + subrepoopts,
3124 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3124 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3125 def incoming(ui, repo, source="default", **opts):
3125 def incoming(ui, repo, source="default", **opts):
3126 """show new changesets found in source
3126 """show new changesets found in source
3127
3127
3128 Show new changesets found in the specified path/URL or the default
3128 Show new changesets found in the specified path/URL or the default
3129 pull location. These are the changesets that would have been pulled
3129 pull location. These are the changesets that would have been pulled
3130 by :hg:`pull` at the time you issued this command.
3130 by :hg:`pull` at the time you issued this command.
3131
3131
3132 See pull for valid source format details.
3132 See pull for valid source format details.
3133
3133
3134 .. container:: verbose
3134 .. container:: verbose
3135
3135
3136 With -B/--bookmarks, the result of bookmark comparison between
3136 With -B/--bookmarks, the result of bookmark comparison between
3137 local and remote repositories is displayed. With -v/--verbose,
3137 local and remote repositories is displayed. With -v/--verbose,
3138 status is also displayed for each bookmark like below::
3138 status is also displayed for each bookmark like below::
3139
3139
3140 BM1 01234567890a added
3140 BM1 01234567890a added
3141 BM2 1234567890ab advanced
3141 BM2 1234567890ab advanced
3142 BM3 234567890abc diverged
3142 BM3 234567890abc diverged
3143 BM4 34567890abcd changed
3143 BM4 34567890abcd changed
3144
3144
3145 The action taken locally when pulling depends on the
3145 The action taken locally when pulling depends on the
3146 status of each bookmark:
3146 status of each bookmark:
3147
3147
3148 :``added``: pull will create it
3148 :``added``: pull will create it
3149 :``advanced``: pull will update it
3149 :``advanced``: pull will update it
3150 :``diverged``: pull will create a divergent bookmark
3150 :``diverged``: pull will create a divergent bookmark
3151 :``changed``: result depends on remote changesets
3151 :``changed``: result depends on remote changesets
3152
3152
3153 From the point of view of pulling behavior, bookmark
3153 From the point of view of pulling behavior, bookmark
3154 existing only in the remote repository are treated as ``added``,
3154 existing only in the remote repository are treated as ``added``,
3155 even if it is in fact locally deleted.
3155 even if it is in fact locally deleted.
3156
3156
3157 .. container:: verbose
3157 .. container:: verbose
3158
3158
3159 For remote repository, using --bundle avoids downloading the
3159 For remote repository, using --bundle avoids downloading the
3160 changesets twice if the incoming is followed by a pull.
3160 changesets twice if the incoming is followed by a pull.
3161
3161
3162 Examples:
3162 Examples:
3163
3163
3164 - show incoming changes with patches and full description::
3164 - show incoming changes with patches and full description::
3165
3165
3166 hg incoming -vp
3166 hg incoming -vp
3167
3167
3168 - show incoming changes excluding merges, store a bundle::
3168 - show incoming changes excluding merges, store a bundle::
3169
3169
3170 hg in -vpM --bundle incoming.hg
3170 hg in -vpM --bundle incoming.hg
3171 hg pull incoming.hg
3171 hg pull incoming.hg
3172
3172
3173 - briefly list changes inside a bundle::
3173 - briefly list changes inside a bundle::
3174
3174
3175 hg in changes.hg -T "{desc|firstline}\\n"
3175 hg in changes.hg -T "{desc|firstline}\\n"
3176
3176
3177 Returns 0 if there are incoming changes, 1 otherwise.
3177 Returns 0 if there are incoming changes, 1 otherwise.
3178 """
3178 """
3179 opts = pycompat.byteskwargs(opts)
3179 opts = pycompat.byteskwargs(opts)
3180 if opts.get('graph'):
3180 if opts.get('graph'):
3181 logcmdutil.checkunsupportedgraphflags([], opts)
3181 logcmdutil.checkunsupportedgraphflags([], opts)
3182 def display(other, chlist, displayer):
3182 def display(other, chlist, displayer):
3183 revdag = logcmdutil.graphrevs(other, chlist, opts)
3183 revdag = logcmdutil.graphrevs(other, chlist, opts)
3184 logcmdutil.displaygraph(ui, repo, revdag, displayer,
3184 logcmdutil.displaygraph(ui, repo, revdag, displayer,
3185 graphmod.asciiedges)
3185 graphmod.asciiedges)
3186
3186
3187 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3187 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3188 return 0
3188 return 0
3189
3189
3190 if opts.get('bundle') and opts.get('subrepos'):
3190 if opts.get('bundle') and opts.get('subrepos'):
3191 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3191 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3192
3192
3193 if opts.get('bookmarks'):
3193 if opts.get('bookmarks'):
3194 source, branches = hg.parseurl(ui.expandpath(source),
3194 source, branches = hg.parseurl(ui.expandpath(source),
3195 opts.get('branch'))
3195 opts.get('branch'))
3196 other = hg.peer(repo, opts, source)
3196 other = hg.peer(repo, opts, source)
3197 if 'bookmarks' not in other.listkeys('namespaces'):
3197 if 'bookmarks' not in other.listkeys('namespaces'):
3198 ui.warn(_("remote doesn't support bookmarks\n"))
3198 ui.warn(_("remote doesn't support bookmarks\n"))
3199 return 0
3199 return 0
3200 ui.pager('incoming')
3200 ui.pager('incoming')
3201 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3201 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3202 return bookmarks.incoming(ui, repo, other)
3202 return bookmarks.incoming(ui, repo, other)
3203
3203
3204 repo._subtoppath = ui.expandpath(source)
3204 repo._subtoppath = ui.expandpath(source)
3205 try:
3205 try:
3206 return hg.incoming(ui, repo, source, opts)
3206 return hg.incoming(ui, repo, source, opts)
3207 finally:
3207 finally:
3208 del repo._subtoppath
3208 del repo._subtoppath
3209
3209
3210
3210
3211 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3211 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3212 norepo=True)
3212 norepo=True)
3213 def init(ui, dest=".", **opts):
3213 def init(ui, dest=".", **opts):
3214 """create a new repository in the given directory
3214 """create a new repository in the given directory
3215
3215
3216 Initialize a new repository in the given directory. If the given
3216 Initialize a new repository in the given directory. If the given
3217 directory does not exist, it will be created.
3217 directory does not exist, it will be created.
3218
3218
3219 If no directory is given, the current directory is used.
3219 If no directory is given, the current directory is used.
3220
3220
3221 It is possible to specify an ``ssh://`` URL as the destination.
3221 It is possible to specify an ``ssh://`` URL as the destination.
3222 See :hg:`help urls` for more information.
3222 See :hg:`help urls` for more information.
3223
3223
3224 Returns 0 on success.
3224 Returns 0 on success.
3225 """
3225 """
3226 opts = pycompat.byteskwargs(opts)
3226 opts = pycompat.byteskwargs(opts)
3227 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3227 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3228
3228
3229 @command('locate',
3229 @command('locate',
3230 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3230 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3231 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3231 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3232 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3232 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3233 ] + walkopts,
3233 ] + walkopts,
3234 _('[OPTION]... [PATTERN]...'))
3234 _('[OPTION]... [PATTERN]...'))
3235 def locate(ui, repo, *pats, **opts):
3235 def locate(ui, repo, *pats, **opts):
3236 """locate files matching specific patterns (DEPRECATED)
3236 """locate files matching specific patterns (DEPRECATED)
3237
3237
3238 Print files under Mercurial control in the working directory whose
3238 Print files under Mercurial control in the working directory whose
3239 names match the given patterns.
3239 names match the given patterns.
3240
3240
3241 By default, this command searches all directories in the working
3241 By default, this command searches all directories in the working
3242 directory. To search just the current directory and its
3242 directory. To search just the current directory and its
3243 subdirectories, use "--include .".
3243 subdirectories, use "--include .".
3244
3244
3245 If no patterns are given to match, this command prints the names
3245 If no patterns are given to match, this command prints the names
3246 of all files under Mercurial control in the working directory.
3246 of all files under Mercurial control in the working directory.
3247
3247
3248 If you want to feed the output of this command into the "xargs"
3248 If you want to feed the output of this command into the "xargs"
3249 command, use the -0 option to both this command and "xargs". This
3249 command, use the -0 option to both this command and "xargs". This
3250 will avoid the problem of "xargs" treating single filenames that
3250 will avoid the problem of "xargs" treating single filenames that
3251 contain whitespace as multiple filenames.
3251 contain whitespace as multiple filenames.
3252
3252
3253 See :hg:`help files` for a more versatile command.
3253 See :hg:`help files` for a more versatile command.
3254
3254
3255 Returns 0 if a match is found, 1 otherwise.
3255 Returns 0 if a match is found, 1 otherwise.
3256 """
3256 """
3257 opts = pycompat.byteskwargs(opts)
3257 opts = pycompat.byteskwargs(opts)
3258 if opts.get('print0'):
3258 if opts.get('print0'):
3259 end = '\0'
3259 end = '\0'
3260 else:
3260 else:
3261 end = '\n'
3261 end = '\n'
3262 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3262 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3263
3263
3264 ret = 1
3264 ret = 1
3265 m = scmutil.match(ctx, pats, opts, default='relglob',
3265 m = scmutil.match(ctx, pats, opts, default='relglob',
3266 badfn=lambda x, y: False)
3266 badfn=lambda x, y: False)
3267
3267
3268 ui.pager('locate')
3268 ui.pager('locate')
3269 for abs in ctx.matches(m):
3269 for abs in ctx.matches(m):
3270 if opts.get('fullpath'):
3270 if opts.get('fullpath'):
3271 ui.write(repo.wjoin(abs), end)
3271 ui.write(repo.wjoin(abs), end)
3272 else:
3272 else:
3273 ui.write(((pats and m.rel(abs)) or abs), end)
3273 ui.write(((pats and m.rel(abs)) or abs), end)
3274 ret = 0
3274 ret = 0
3275
3275
3276 return ret
3276 return ret
3277
3277
3278 @command('^log|history',
3278 @command('^log|history',
3279 [('f', 'follow', None,
3279 [('f', 'follow', None,
3280 _('follow changeset history, or file history across copies and renames')),
3280 _('follow changeset history, or file history across copies and renames')),
3281 ('', 'follow-first', None,
3281 ('', 'follow-first', None,
3282 _('only follow the first parent of merge changesets (DEPRECATED)')),
3282 _('only follow the first parent of merge changesets (DEPRECATED)')),
3283 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3283 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3284 ('C', 'copies', None, _('show copied files')),
3284 ('C', 'copies', None, _('show copied files')),
3285 ('k', 'keyword', [],
3285 ('k', 'keyword', [],
3286 _('do case-insensitive search for a given text'), _('TEXT')),
3286 _('do case-insensitive search for a given text'), _('TEXT')),
3287 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3287 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3288 ('L', 'line-range', [],
3288 ('L', 'line-range', [],
3289 _('follow line range of specified file (EXPERIMENTAL)'),
3289 _('follow line range of specified file (EXPERIMENTAL)'),
3290 _('FILE,RANGE')),
3290 _('FILE,RANGE')),
3291 ('', 'removed', None, _('include revisions where files were removed')),
3291 ('', 'removed', None, _('include revisions where files were removed')),
3292 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3292 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3293 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3293 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3294 ('', 'only-branch', [],
3294 ('', 'only-branch', [],
3295 _('show only changesets within the given named branch (DEPRECATED)'),
3295 _('show only changesets within the given named branch (DEPRECATED)'),
3296 _('BRANCH')),
3296 _('BRANCH')),
3297 ('b', 'branch', [],
3297 ('b', 'branch', [],
3298 _('show changesets within the given named branch'), _('BRANCH')),
3298 _('show changesets within the given named branch'), _('BRANCH')),
3299 ('P', 'prune', [],
3299 ('P', 'prune', [],
3300 _('do not display revision or any of its ancestors'), _('REV')),
3300 _('do not display revision or any of its ancestors'), _('REV')),
3301 ] + logopts + walkopts,
3301 ] + logopts + walkopts,
3302 _('[OPTION]... [FILE]'),
3302 _('[OPTION]... [FILE]'),
3303 inferrepo=True, cmdtype=readonly)
3303 inferrepo=True, cmdtype=readonly)
3304 def log(ui, repo, *pats, **opts):
3304 def log(ui, repo, *pats, **opts):
3305 """show revision history of entire repository or files
3305 """show revision history of entire repository or files
3306
3306
3307 Print the revision history of the specified files or the entire
3307 Print the revision history of the specified files or the entire
3308 project.
3308 project.
3309
3309
3310 If no revision range is specified, the default is ``tip:0`` unless
3310 If no revision range is specified, the default is ``tip:0`` unless
3311 --follow is set, in which case the working directory parent is
3311 --follow is set, in which case the working directory parent is
3312 used as the starting revision.
3312 used as the starting revision.
3313
3313
3314 File history is shown without following rename or copy history of
3314 File history is shown without following rename or copy history of
3315 files. Use -f/--follow with a filename to follow history across
3315 files. Use -f/--follow with a filename to follow history across
3316 renames and copies. --follow without a filename will only show
3316 renames and copies. --follow without a filename will only show
3317 ancestors of the starting revision.
3317 ancestors of the starting revision.
3318
3318
3319 By default this command prints revision number and changeset id,
3319 By default this command prints revision number and changeset id,
3320 tags, non-trivial parents, user, date and time, and a summary for
3320 tags, non-trivial parents, user, date and time, and a summary for
3321 each commit. When the -v/--verbose switch is used, the list of
3321 each commit. When the -v/--verbose switch is used, the list of
3322 changed files and full commit message are shown.
3322 changed files and full commit message are shown.
3323
3323
3324 With --graph the revisions are shown as an ASCII art DAG with the most
3324 With --graph the revisions are shown as an ASCII art DAG with the most
3325 recent changeset at the top.
3325 recent changeset at the top.
3326 'o' is a changeset, '@' is a working directory parent, '_' closes a branch,
3326 'o' is a changeset, '@' is a working directory parent, '_' closes a branch,
3327 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
3327 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
3328 changeset from the lines below is a parent of the 'o' merge on the same
3328 changeset from the lines below is a parent of the 'o' merge on the same
3329 line.
3329 line.
3330 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
3330 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
3331 of a '|' indicates one or more revisions in a path are omitted.
3331 of a '|' indicates one or more revisions in a path are omitted.
3332
3332
3333 .. container:: verbose
3333 .. container:: verbose
3334
3334
3335 Use -L/--line-range FILE,M:N options to follow the history of lines
3335 Use -L/--line-range FILE,M:N options to follow the history of lines
3336 from M to N in FILE. With -p/--patch only diff hunks affecting
3336 from M to N in FILE. With -p/--patch only diff hunks affecting
3337 specified line range will be shown. This option requires --follow;
3337 specified line range will be shown. This option requires --follow;
3338 it can be specified multiple times. Currently, this option is not
3338 it can be specified multiple times. Currently, this option is not
3339 compatible with --graph. This option is experimental.
3339 compatible with --graph. This option is experimental.
3340
3340
3341 .. note::
3341 .. note::
3342
3342
3343 :hg:`log --patch` may generate unexpected diff output for merge
3343 :hg:`log --patch` may generate unexpected diff output for merge
3344 changesets, as it will only compare the merge changeset against
3344 changesets, as it will only compare the merge changeset against
3345 its first parent. Also, only files different from BOTH parents
3345 its first parent. Also, only files different from BOTH parents
3346 will appear in files:.
3346 will appear in files:.
3347
3347
3348 .. note::
3348 .. note::
3349
3349
3350 For performance reasons, :hg:`log FILE` may omit duplicate changes
3350 For performance reasons, :hg:`log FILE` may omit duplicate changes
3351 made on branches and will not show removals or mode changes. To
3351 made on branches and will not show removals or mode changes. To
3352 see all such changes, use the --removed switch.
3352 see all such changes, use the --removed switch.
3353
3353
3354 .. container:: verbose
3354 .. container:: verbose
3355
3355
3356 .. note::
3356 .. note::
3357
3357
3358 The history resulting from -L/--line-range options depends on diff
3358 The history resulting from -L/--line-range options depends on diff
3359 options; for instance if white-spaces are ignored, respective changes
3359 options; for instance if white-spaces are ignored, respective changes
3360 with only white-spaces in specified line range will not be listed.
3360 with only white-spaces in specified line range will not be listed.
3361
3361
3362 .. container:: verbose
3362 .. container:: verbose
3363
3363
3364 Some examples:
3364 Some examples:
3365
3365
3366 - changesets with full descriptions and file lists::
3366 - changesets with full descriptions and file lists::
3367
3367
3368 hg log -v
3368 hg log -v
3369
3369
3370 - changesets ancestral to the working directory::
3370 - changesets ancestral to the working directory::
3371
3371
3372 hg log -f
3372 hg log -f
3373
3373
3374 - last 10 commits on the current branch::
3374 - last 10 commits on the current branch::
3375
3375
3376 hg log -l 10 -b .
3376 hg log -l 10 -b .
3377
3377
3378 - changesets showing all modifications of a file, including removals::
3378 - changesets showing all modifications of a file, including removals::
3379
3379
3380 hg log --removed file.c
3380 hg log --removed file.c
3381
3381
3382 - all changesets that touch a directory, with diffs, excluding merges::
3382 - all changesets that touch a directory, with diffs, excluding merges::
3383
3383
3384 hg log -Mp lib/
3384 hg log -Mp lib/
3385
3385
3386 - all revision numbers that match a keyword::
3386 - all revision numbers that match a keyword::
3387
3387
3388 hg log -k bug --template "{rev}\\n"
3388 hg log -k bug --template "{rev}\\n"
3389
3389
3390 - the full hash identifier of the working directory parent::
3390 - the full hash identifier of the working directory parent::
3391
3391
3392 hg log -r . --template "{node}\\n"
3392 hg log -r . --template "{node}\\n"
3393
3393
3394 - list available log templates::
3394 - list available log templates::
3395
3395
3396 hg log -T list
3396 hg log -T list
3397
3397
3398 - check if a given changeset is included in a tagged release::
3398 - check if a given changeset is included in a tagged release::
3399
3399
3400 hg log -r "a21ccf and ancestor(1.9)"
3400 hg log -r "a21ccf and ancestor(1.9)"
3401
3401
3402 - find all changesets by some user in a date range::
3402 - find all changesets by some user in a date range::
3403
3403
3404 hg log -k alice -d "may 2008 to jul 2008"
3404 hg log -k alice -d "may 2008 to jul 2008"
3405
3405
3406 - summary of all changesets after the last tag::
3406 - summary of all changesets after the last tag::
3407
3407
3408 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3408 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3409
3409
3410 - changesets touching lines 13 to 23 for file.c::
3410 - changesets touching lines 13 to 23 for file.c::
3411
3411
3412 hg log -L file.c,13:23
3412 hg log -L file.c,13:23
3413
3413
3414 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
3414 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
3415 main.c with patch::
3415 main.c with patch::
3416
3416
3417 hg log -L file.c,13:23 -L main.c,2:6 -p
3417 hg log -L file.c,13:23 -L main.c,2:6 -p
3418
3418
3419 See :hg:`help dates` for a list of formats valid for -d/--date.
3419 See :hg:`help dates` for a list of formats valid for -d/--date.
3420
3420
3421 See :hg:`help revisions` for more about specifying and ordering
3421 See :hg:`help revisions` for more about specifying and ordering
3422 revisions.
3422 revisions.
3423
3423
3424 See :hg:`help templates` for more about pre-packaged styles and
3424 See :hg:`help templates` for more about pre-packaged styles and
3425 specifying custom templates. The default template used by the log
3425 specifying custom templates. The default template used by the log
3426 command can be customized via the ``ui.logtemplate`` configuration
3426 command can be customized via the ``ui.logtemplate`` configuration
3427 setting.
3427 setting.
3428
3428
3429 Returns 0 on success.
3429 Returns 0 on success.
3430
3430
3431 """
3431 """
3432 opts = pycompat.byteskwargs(opts)
3432 opts = pycompat.byteskwargs(opts)
3433 linerange = opts.get('line_range')
3433 linerange = opts.get('line_range')
3434
3434
3435 if linerange and not opts.get('follow'):
3435 if linerange and not opts.get('follow'):
3436 raise error.Abort(_('--line-range requires --follow'))
3436 raise error.Abort(_('--line-range requires --follow'))
3437
3437
3438 if linerange and pats:
3438 if linerange and pats:
3439 # TODO: take pats as patterns with no line-range filter
3439 # TODO: take pats as patterns with no line-range filter
3440 raise error.Abort(
3440 raise error.Abort(
3441 _('FILE arguments are not compatible with --line-range option')
3441 _('FILE arguments are not compatible with --line-range option')
3442 )
3442 )
3443
3443
3444 repo = scmutil.unhidehashlikerevs(repo, opts.get('rev'), 'nowarn')
3444 repo = scmutil.unhidehashlikerevs(repo, opts.get('rev'), 'nowarn')
3445 revs, differ = logcmdutil.getrevs(repo, pats, opts)
3445 revs, differ = logcmdutil.getrevs(repo, pats, opts)
3446 if linerange:
3446 if linerange:
3447 # TODO: should follow file history from logcmdutil._initialrevs(),
3447 # TODO: should follow file history from logcmdutil._initialrevs(),
3448 # then filter the result by logcmdutil._makerevset() and --limit
3448 # then filter the result by logcmdutil._makerevset() and --limit
3449 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
3449 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
3450
3450
3451 getrenamed = None
3451 getrenamed = None
3452 if opts.get('copies'):
3452 if opts.get('copies'):
3453 endrev = None
3453 endrev = None
3454 if opts.get('rev'):
3454 if opts.get('rev'):
3455 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
3455 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
3456 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3456 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3457
3457
3458 ui.pager('log')
3458 ui.pager('log')
3459 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, differ,
3459 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, differ,
3460 buffered=True)
3460 buffered=True)
3461 if opts.get('graph'):
3461 if opts.get('graph'):
3462 displayfn = logcmdutil.displaygraphrevs
3462 displayfn = logcmdutil.displaygraphrevs
3463 else:
3463 else:
3464 displayfn = logcmdutil.displayrevs
3464 displayfn = logcmdutil.displayrevs
3465 displayfn(ui, repo, revs, displayer, getrenamed)
3465 displayfn(ui, repo, revs, displayer, getrenamed)
3466
3466
3467 @command('manifest',
3467 @command('manifest',
3468 [('r', 'rev', '', _('revision to display'), _('REV')),
3468 [('r', 'rev', '', _('revision to display'), _('REV')),
3469 ('', 'all', False, _("list files from all revisions"))]
3469 ('', 'all', False, _("list files from all revisions"))]
3470 + formatteropts,
3470 + formatteropts,
3471 _('[-r REV]'), cmdtype=readonly)
3471 _('[-r REV]'), cmdtype=readonly)
3472 def manifest(ui, repo, node=None, rev=None, **opts):
3472 def manifest(ui, repo, node=None, rev=None, **opts):
3473 """output the current or given revision of the project manifest
3473 """output the current or given revision of the project manifest
3474
3474
3475 Print a list of version controlled files for the given revision.
3475 Print a list of version controlled files for the given revision.
3476 If no revision is given, the first parent of the working directory
3476 If no revision is given, the first parent of the working directory
3477 is used, or the null revision if no revision is checked out.
3477 is used, or the null revision if no revision is checked out.
3478
3478
3479 With -v, print file permissions, symlink and executable bits.
3479 With -v, print file permissions, symlink and executable bits.
3480 With --debug, print file revision hashes.
3480 With --debug, print file revision hashes.
3481
3481
3482 If option --all is specified, the list of all files from all revisions
3482 If option --all is specified, the list of all files from all revisions
3483 is printed. This includes deleted and renamed files.
3483 is printed. This includes deleted and renamed files.
3484
3484
3485 Returns 0 on success.
3485 Returns 0 on success.
3486 """
3486 """
3487 opts = pycompat.byteskwargs(opts)
3487 opts = pycompat.byteskwargs(opts)
3488 fm = ui.formatter('manifest', opts)
3488 fm = ui.formatter('manifest', opts)
3489
3489
3490 if opts.get('all'):
3490 if opts.get('all'):
3491 if rev or node:
3491 if rev or node:
3492 raise error.Abort(_("can't specify a revision with --all"))
3492 raise error.Abort(_("can't specify a revision with --all"))
3493
3493
3494 res = []
3494 res = []
3495 # TODO this is a massive layering violation. It assumes the repo is
3496 # backed by revlogs with a well-defined naming scheme.
3495 prefix = "data/"
3497 prefix = "data/"
3496 suffix = ".i"
3498 suffix = ".i"
3497 plen = len(prefix)
3499 plen = len(prefix)
3498 slen = len(suffix)
3500 slen = len(suffix)
3499 with repo.lock():
3501 with repo.lock():
3500 for fn, b, size in repo.store.datafiles():
3502 for fn, b, size in repo.store.datafiles():
3501 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3503 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3502 res.append(fn[plen:-slen])
3504 res.append(fn[plen:-slen])
3503 ui.pager('manifest')
3505 ui.pager('manifest')
3504 for f in res:
3506 for f in res:
3505 fm.startitem()
3507 fm.startitem()
3506 fm.write("path", '%s\n', f)
3508 fm.write("path", '%s\n', f)
3507 fm.end()
3509 fm.end()
3508 return
3510 return
3509
3511
3510 if rev and node:
3512 if rev and node:
3511 raise error.Abort(_("please specify just one revision"))
3513 raise error.Abort(_("please specify just one revision"))
3512
3514
3513 if not node:
3515 if not node:
3514 node = rev
3516 node = rev
3515
3517
3516 char = {'l': '@', 'x': '*', '': '', 't': 'd'}
3518 char = {'l': '@', 'x': '*', '': '', 't': 'd'}
3517 mode = {'l': '644', 'x': '755', '': '644', 't': '755'}
3519 mode = {'l': '644', 'x': '755', '': '644', 't': '755'}
3518 if node:
3520 if node:
3519 repo = scmutil.unhidehashlikerevs(repo, [node], 'nowarn')
3521 repo = scmutil.unhidehashlikerevs(repo, [node], 'nowarn')
3520 ctx = scmutil.revsingle(repo, node)
3522 ctx = scmutil.revsingle(repo, node)
3521 mf = ctx.manifest()
3523 mf = ctx.manifest()
3522 ui.pager('manifest')
3524 ui.pager('manifest')
3523 for f in ctx:
3525 for f in ctx:
3524 fm.startitem()
3526 fm.startitem()
3525 fl = ctx[f].flags()
3527 fl = ctx[f].flags()
3526 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3528 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3527 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3529 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3528 fm.write('path', '%s\n', f)
3530 fm.write('path', '%s\n', f)
3529 fm.end()
3531 fm.end()
3530
3532
3531 @command('^merge',
3533 @command('^merge',
3532 [('f', 'force', None,
3534 [('f', 'force', None,
3533 _('force a merge including outstanding changes (DEPRECATED)')),
3535 _('force a merge including outstanding changes (DEPRECATED)')),
3534 ('r', 'rev', '', _('revision to merge'), _('REV')),
3536 ('r', 'rev', '', _('revision to merge'), _('REV')),
3535 ('P', 'preview', None,
3537 ('P', 'preview', None,
3536 _('review revisions to merge (no merge is performed)')),
3538 _('review revisions to merge (no merge is performed)')),
3537 ('', 'abort', None, _('abort the ongoing merge')),
3539 ('', 'abort', None, _('abort the ongoing merge')),
3538 ] + mergetoolopts,
3540 ] + mergetoolopts,
3539 _('[-P] [[-r] REV]'))
3541 _('[-P] [[-r] REV]'))
3540 def merge(ui, repo, node=None, **opts):
3542 def merge(ui, repo, node=None, **opts):
3541 """merge another revision into working directory
3543 """merge another revision into working directory
3542
3544
3543 The current working directory is updated with all changes made in
3545 The current working directory is updated with all changes made in
3544 the requested revision since the last common predecessor revision.
3546 the requested revision since the last common predecessor revision.
3545
3547
3546 Files that changed between either parent are marked as changed for
3548 Files that changed between either parent are marked as changed for
3547 the next commit and a commit must be performed before any further
3549 the next commit and a commit must be performed before any further
3548 updates to the repository are allowed. The next commit will have
3550 updates to the repository are allowed. The next commit will have
3549 two parents.
3551 two parents.
3550
3552
3551 ``--tool`` can be used to specify the merge tool used for file
3553 ``--tool`` can be used to specify the merge tool used for file
3552 merges. It overrides the HGMERGE environment variable and your
3554 merges. It overrides the HGMERGE environment variable and your
3553 configuration files. See :hg:`help merge-tools` for options.
3555 configuration files. See :hg:`help merge-tools` for options.
3554
3556
3555 If no revision is specified, the working directory's parent is a
3557 If no revision is specified, the working directory's parent is a
3556 head revision, and the current branch contains exactly one other
3558 head revision, and the current branch contains exactly one other
3557 head, the other head is merged with by default. Otherwise, an
3559 head, the other head is merged with by default. Otherwise, an
3558 explicit revision with which to merge with must be provided.
3560 explicit revision with which to merge with must be provided.
3559
3561
3560 See :hg:`help resolve` for information on handling file conflicts.
3562 See :hg:`help resolve` for information on handling file conflicts.
3561
3563
3562 To undo an uncommitted merge, use :hg:`merge --abort` which
3564 To undo an uncommitted merge, use :hg:`merge --abort` which
3563 will check out a clean copy of the original merge parent, losing
3565 will check out a clean copy of the original merge parent, losing
3564 all changes.
3566 all changes.
3565
3567
3566 Returns 0 on success, 1 if there are unresolved files.
3568 Returns 0 on success, 1 if there are unresolved files.
3567 """
3569 """
3568
3570
3569 opts = pycompat.byteskwargs(opts)
3571 opts = pycompat.byteskwargs(opts)
3570 abort = opts.get('abort')
3572 abort = opts.get('abort')
3571 if abort and repo.dirstate.p2() == nullid:
3573 if abort and repo.dirstate.p2() == nullid:
3572 cmdutil.wrongtooltocontinue(repo, _('merge'))
3574 cmdutil.wrongtooltocontinue(repo, _('merge'))
3573 if abort:
3575 if abort:
3574 if node:
3576 if node:
3575 raise error.Abort(_("cannot specify a node with --abort"))
3577 raise error.Abort(_("cannot specify a node with --abort"))
3576 if opts.get('rev'):
3578 if opts.get('rev'):
3577 raise error.Abort(_("cannot specify both --rev and --abort"))
3579 raise error.Abort(_("cannot specify both --rev and --abort"))
3578 if opts.get('preview'):
3580 if opts.get('preview'):
3579 raise error.Abort(_("cannot specify --preview with --abort"))
3581 raise error.Abort(_("cannot specify --preview with --abort"))
3580 if opts.get('rev') and node:
3582 if opts.get('rev') and node:
3581 raise error.Abort(_("please specify just one revision"))
3583 raise error.Abort(_("please specify just one revision"))
3582 if not node:
3584 if not node:
3583 node = opts.get('rev')
3585 node = opts.get('rev')
3584
3586
3585 if node:
3587 if node:
3586 node = scmutil.revsingle(repo, node).node()
3588 node = scmutil.revsingle(repo, node).node()
3587
3589
3588 if not node and not abort:
3590 if not node and not abort:
3589 node = repo[destutil.destmerge(repo)].node()
3591 node = repo[destutil.destmerge(repo)].node()
3590
3592
3591 if opts.get('preview'):
3593 if opts.get('preview'):
3592 # find nodes that are ancestors of p2 but not of p1
3594 # find nodes that are ancestors of p2 but not of p1
3593 p1 = repo.lookup('.')
3595 p1 = repo.lookup('.')
3594 p2 = repo.lookup(node)
3596 p2 = repo.lookup(node)
3595 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3597 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3596
3598
3597 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3599 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3598 for node in nodes:
3600 for node in nodes:
3599 displayer.show(repo[node])
3601 displayer.show(repo[node])
3600 displayer.close()
3602 displayer.close()
3601 return 0
3603 return 0
3602
3604
3603 try:
3605 try:
3604 # ui.forcemerge is an internal variable, do not document
3606 # ui.forcemerge is an internal variable, do not document
3605 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
3607 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
3606 force = opts.get('force')
3608 force = opts.get('force')
3607 labels = ['working copy', 'merge rev']
3609 labels = ['working copy', 'merge rev']
3608 return hg.merge(repo, node, force=force, mergeforce=force,
3610 return hg.merge(repo, node, force=force, mergeforce=force,
3609 labels=labels, abort=abort)
3611 labels=labels, abort=abort)
3610 finally:
3612 finally:
3611 ui.setconfig('ui', 'forcemerge', '', 'merge')
3613 ui.setconfig('ui', 'forcemerge', '', 'merge')
3612
3614
3613 @command('outgoing|out',
3615 @command('outgoing|out',
3614 [('f', 'force', None, _('run even when the destination is unrelated')),
3616 [('f', 'force', None, _('run even when the destination is unrelated')),
3615 ('r', 'rev', [],
3617 ('r', 'rev', [],
3616 _('a changeset intended to be included in the destination'), _('REV')),
3618 _('a changeset intended to be included in the destination'), _('REV')),
3617 ('n', 'newest-first', None, _('show newest record first')),
3619 ('n', 'newest-first', None, _('show newest record first')),
3618 ('B', 'bookmarks', False, _('compare bookmarks')),
3620 ('B', 'bookmarks', False, _('compare bookmarks')),
3619 ('b', 'branch', [], _('a specific branch you would like to push'),
3621 ('b', 'branch', [], _('a specific branch you would like to push'),
3620 _('BRANCH')),
3622 _('BRANCH')),
3621 ] + logopts + remoteopts + subrepoopts,
3623 ] + logopts + remoteopts + subrepoopts,
3622 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3624 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3623 def outgoing(ui, repo, dest=None, **opts):
3625 def outgoing(ui, repo, dest=None, **opts):
3624 """show changesets not found in the destination
3626 """show changesets not found in the destination
3625
3627
3626 Show changesets not found in the specified destination repository
3628 Show changesets not found in the specified destination repository
3627 or the default push location. These are the changesets that would
3629 or the default push location. These are the changesets that would
3628 be pushed if a push was requested.
3630 be pushed if a push was requested.
3629
3631
3630 See pull for details of valid destination formats.
3632 See pull for details of valid destination formats.
3631
3633
3632 .. container:: verbose
3634 .. container:: verbose
3633
3635
3634 With -B/--bookmarks, the result of bookmark comparison between
3636 With -B/--bookmarks, the result of bookmark comparison between
3635 local and remote repositories is displayed. With -v/--verbose,
3637 local and remote repositories is displayed. With -v/--verbose,
3636 status is also displayed for each bookmark like below::
3638 status is also displayed for each bookmark like below::
3637
3639
3638 BM1 01234567890a added
3640 BM1 01234567890a added
3639 BM2 deleted
3641 BM2 deleted
3640 BM3 234567890abc advanced
3642 BM3 234567890abc advanced
3641 BM4 34567890abcd diverged
3643 BM4 34567890abcd diverged
3642 BM5 4567890abcde changed
3644 BM5 4567890abcde changed
3643
3645
3644 The action taken when pushing depends on the
3646 The action taken when pushing depends on the
3645 status of each bookmark:
3647 status of each bookmark:
3646
3648
3647 :``added``: push with ``-B`` will create it
3649 :``added``: push with ``-B`` will create it
3648 :``deleted``: push with ``-B`` will delete it
3650 :``deleted``: push with ``-B`` will delete it
3649 :``advanced``: push will update it
3651 :``advanced``: push will update it
3650 :``diverged``: push with ``-B`` will update it
3652 :``diverged``: push with ``-B`` will update it
3651 :``changed``: push with ``-B`` will update it
3653 :``changed``: push with ``-B`` will update it
3652
3654
3653 From the point of view of pushing behavior, bookmarks
3655 From the point of view of pushing behavior, bookmarks
3654 existing only in the remote repository are treated as
3656 existing only in the remote repository are treated as
3655 ``deleted``, even if it is in fact added remotely.
3657 ``deleted``, even if it is in fact added remotely.
3656
3658
3657 Returns 0 if there are outgoing changes, 1 otherwise.
3659 Returns 0 if there are outgoing changes, 1 otherwise.
3658 """
3660 """
3659 opts = pycompat.byteskwargs(opts)
3661 opts = pycompat.byteskwargs(opts)
3660 if opts.get('graph'):
3662 if opts.get('graph'):
3661 logcmdutil.checkunsupportedgraphflags([], opts)
3663 logcmdutil.checkunsupportedgraphflags([], opts)
3662 o, other = hg._outgoing(ui, repo, dest, opts)
3664 o, other = hg._outgoing(ui, repo, dest, opts)
3663 if not o:
3665 if not o:
3664 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3666 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3665 return
3667 return
3666
3668
3667 revdag = logcmdutil.graphrevs(repo, o, opts)
3669 revdag = logcmdutil.graphrevs(repo, o, opts)
3668 ui.pager('outgoing')
3670 ui.pager('outgoing')
3669 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
3671 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
3670 logcmdutil.displaygraph(ui, repo, revdag, displayer,
3672 logcmdutil.displaygraph(ui, repo, revdag, displayer,
3671 graphmod.asciiedges)
3673 graphmod.asciiedges)
3672 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3674 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3673 return 0
3675 return 0
3674
3676
3675 if opts.get('bookmarks'):
3677 if opts.get('bookmarks'):
3676 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3678 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3677 dest, branches = hg.parseurl(dest, opts.get('branch'))
3679 dest, branches = hg.parseurl(dest, opts.get('branch'))
3678 other = hg.peer(repo, opts, dest)
3680 other = hg.peer(repo, opts, dest)
3679 if 'bookmarks' not in other.listkeys('namespaces'):
3681 if 'bookmarks' not in other.listkeys('namespaces'):
3680 ui.warn(_("remote doesn't support bookmarks\n"))
3682 ui.warn(_("remote doesn't support bookmarks\n"))
3681 return 0
3683 return 0
3682 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3684 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3683 ui.pager('outgoing')
3685 ui.pager('outgoing')
3684 return bookmarks.outgoing(ui, repo, other)
3686 return bookmarks.outgoing(ui, repo, other)
3685
3687
3686 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3688 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3687 try:
3689 try:
3688 return hg.outgoing(ui, repo, dest, opts)
3690 return hg.outgoing(ui, repo, dest, opts)
3689 finally:
3691 finally:
3690 del repo._subtoppath
3692 del repo._subtoppath
3691
3693
3692 @command('parents',
3694 @command('parents',
3693 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3695 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3694 ] + templateopts,
3696 ] + templateopts,
3695 _('[-r REV] [FILE]'),
3697 _('[-r REV] [FILE]'),
3696 inferrepo=True)
3698 inferrepo=True)
3697 def parents(ui, repo, file_=None, **opts):
3699 def parents(ui, repo, file_=None, **opts):
3698 """show the parents of the working directory or revision (DEPRECATED)
3700 """show the parents of the working directory or revision (DEPRECATED)
3699
3701
3700 Print the working directory's parent revisions. If a revision is
3702 Print the working directory's parent revisions. If a revision is
3701 given via -r/--rev, the parent of that revision will be printed.
3703 given via -r/--rev, the parent of that revision will be printed.
3702 If a file argument is given, the revision in which the file was
3704 If a file argument is given, the revision in which the file was
3703 last changed (before the working directory revision or the
3705 last changed (before the working directory revision or the
3704 argument to --rev if given) is printed.
3706 argument to --rev if given) is printed.
3705
3707
3706 This command is equivalent to::
3708 This command is equivalent to::
3707
3709
3708 hg log -r "p1()+p2()" or
3710 hg log -r "p1()+p2()" or
3709 hg log -r "p1(REV)+p2(REV)" or
3711 hg log -r "p1(REV)+p2(REV)" or
3710 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
3712 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
3711 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
3713 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
3712
3714
3713 See :hg:`summary` and :hg:`help revsets` for related information.
3715 See :hg:`summary` and :hg:`help revsets` for related information.
3714
3716
3715 Returns 0 on success.
3717 Returns 0 on success.
3716 """
3718 """
3717
3719
3718 opts = pycompat.byteskwargs(opts)
3720 opts = pycompat.byteskwargs(opts)
3719 rev = opts.get('rev')
3721 rev = opts.get('rev')
3720 if rev:
3722 if rev:
3721 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3723 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3722 ctx = scmutil.revsingle(repo, rev, None)
3724 ctx = scmutil.revsingle(repo, rev, None)
3723
3725
3724 if file_:
3726 if file_:
3725 m = scmutil.match(ctx, (file_,), opts)
3727 m = scmutil.match(ctx, (file_,), opts)
3726 if m.anypats() or len(m.files()) != 1:
3728 if m.anypats() or len(m.files()) != 1:
3727 raise error.Abort(_('can only specify an explicit filename'))
3729 raise error.Abort(_('can only specify an explicit filename'))
3728 file_ = m.files()[0]
3730 file_ = m.files()[0]
3729 filenodes = []
3731 filenodes = []
3730 for cp in ctx.parents():
3732 for cp in ctx.parents():
3731 if not cp:
3733 if not cp:
3732 continue
3734 continue
3733 try:
3735 try:
3734 filenodes.append(cp.filenode(file_))
3736 filenodes.append(cp.filenode(file_))
3735 except error.LookupError:
3737 except error.LookupError:
3736 pass
3738 pass
3737 if not filenodes:
3739 if not filenodes:
3738 raise error.Abort(_("'%s' not found in manifest!") % file_)
3740 raise error.Abort(_("'%s' not found in manifest!") % file_)
3739 p = []
3741 p = []
3740 for fn in filenodes:
3742 for fn in filenodes:
3741 fctx = repo.filectx(file_, fileid=fn)
3743 fctx = repo.filectx(file_, fileid=fn)
3742 p.append(fctx.node())
3744 p.append(fctx.node())
3743 else:
3745 else:
3744 p = [cp.node() for cp in ctx.parents()]
3746 p = [cp.node() for cp in ctx.parents()]
3745
3747
3746 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3748 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3747 for n in p:
3749 for n in p:
3748 if n != nullid:
3750 if n != nullid:
3749 displayer.show(repo[n])
3751 displayer.show(repo[n])
3750 displayer.close()
3752 displayer.close()
3751
3753
3752 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True,
3754 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True,
3753 cmdtype=readonly)
3755 cmdtype=readonly)
3754 def paths(ui, repo, search=None, **opts):
3756 def paths(ui, repo, search=None, **opts):
3755 """show aliases for remote repositories
3757 """show aliases for remote repositories
3756
3758
3757 Show definition of symbolic path name NAME. If no name is given,
3759 Show definition of symbolic path name NAME. If no name is given,
3758 show definition of all available names.
3760 show definition of all available names.
3759
3761
3760 Option -q/--quiet suppresses all output when searching for NAME
3762 Option -q/--quiet suppresses all output when searching for NAME
3761 and shows only the path names when listing all definitions.
3763 and shows only the path names when listing all definitions.
3762
3764
3763 Path names are defined in the [paths] section of your
3765 Path names are defined in the [paths] section of your
3764 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3766 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3765 repository, ``.hg/hgrc`` is used, too.
3767 repository, ``.hg/hgrc`` is used, too.
3766
3768
3767 The path names ``default`` and ``default-push`` have a special
3769 The path names ``default`` and ``default-push`` have a special
3768 meaning. When performing a push or pull operation, they are used
3770 meaning. When performing a push or pull operation, they are used
3769 as fallbacks if no location is specified on the command-line.
3771 as fallbacks if no location is specified on the command-line.
3770 When ``default-push`` is set, it will be used for push and
3772 When ``default-push`` is set, it will be used for push and
3771 ``default`` will be used for pull; otherwise ``default`` is used
3773 ``default`` will be used for pull; otherwise ``default`` is used
3772 as the fallback for both. When cloning a repository, the clone
3774 as the fallback for both. When cloning a repository, the clone
3773 source is written as ``default`` in ``.hg/hgrc``.
3775 source is written as ``default`` in ``.hg/hgrc``.
3774
3776
3775 .. note::
3777 .. note::
3776
3778
3777 ``default`` and ``default-push`` apply to all inbound (e.g.
3779 ``default`` and ``default-push`` apply to all inbound (e.g.
3778 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
3780 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
3779 and :hg:`bundle`) operations.
3781 and :hg:`bundle`) operations.
3780
3782
3781 See :hg:`help urls` for more information.
3783 See :hg:`help urls` for more information.
3782
3784
3783 Returns 0 on success.
3785 Returns 0 on success.
3784 """
3786 """
3785
3787
3786 opts = pycompat.byteskwargs(opts)
3788 opts = pycompat.byteskwargs(opts)
3787 ui.pager('paths')
3789 ui.pager('paths')
3788 if search:
3790 if search:
3789 pathitems = [(name, path) for name, path in ui.paths.iteritems()
3791 pathitems = [(name, path) for name, path in ui.paths.iteritems()
3790 if name == search]
3792 if name == search]
3791 else:
3793 else:
3792 pathitems = sorted(ui.paths.iteritems())
3794 pathitems = sorted(ui.paths.iteritems())
3793
3795
3794 fm = ui.formatter('paths', opts)
3796 fm = ui.formatter('paths', opts)
3795 if fm.isplain():
3797 if fm.isplain():
3796 hidepassword = util.hidepassword
3798 hidepassword = util.hidepassword
3797 else:
3799 else:
3798 hidepassword = bytes
3800 hidepassword = bytes
3799 if ui.quiet:
3801 if ui.quiet:
3800 namefmt = '%s\n'
3802 namefmt = '%s\n'
3801 else:
3803 else:
3802 namefmt = '%s = '
3804 namefmt = '%s = '
3803 showsubopts = not search and not ui.quiet
3805 showsubopts = not search and not ui.quiet
3804
3806
3805 for name, path in pathitems:
3807 for name, path in pathitems:
3806 fm.startitem()
3808 fm.startitem()
3807 fm.condwrite(not search, 'name', namefmt, name)
3809 fm.condwrite(not search, 'name', namefmt, name)
3808 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
3810 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
3809 for subopt, value in sorted(path.suboptions.items()):
3811 for subopt, value in sorted(path.suboptions.items()):
3810 assert subopt not in ('name', 'url')
3812 assert subopt not in ('name', 'url')
3811 if showsubopts:
3813 if showsubopts:
3812 fm.plain('%s:%s = ' % (name, subopt))
3814 fm.plain('%s:%s = ' % (name, subopt))
3813 fm.condwrite(showsubopts, subopt, '%s\n', value)
3815 fm.condwrite(showsubopts, subopt, '%s\n', value)
3814
3816
3815 fm.end()
3817 fm.end()
3816
3818
3817 if search and not pathitems:
3819 if search and not pathitems:
3818 if not ui.quiet:
3820 if not ui.quiet:
3819 ui.warn(_("not found!\n"))
3821 ui.warn(_("not found!\n"))
3820 return 1
3822 return 1
3821 else:
3823 else:
3822 return 0
3824 return 0
3823
3825
3824 @command('phase',
3826 @command('phase',
3825 [('p', 'public', False, _('set changeset phase to public')),
3827 [('p', 'public', False, _('set changeset phase to public')),
3826 ('d', 'draft', False, _('set changeset phase to draft')),
3828 ('d', 'draft', False, _('set changeset phase to draft')),
3827 ('s', 'secret', False, _('set changeset phase to secret')),
3829 ('s', 'secret', False, _('set changeset phase to secret')),
3828 ('f', 'force', False, _('allow to move boundary backward')),
3830 ('f', 'force', False, _('allow to move boundary backward')),
3829 ('r', 'rev', [], _('target revision'), _('REV')),
3831 ('r', 'rev', [], _('target revision'), _('REV')),
3830 ],
3832 ],
3831 _('[-p|-d|-s] [-f] [-r] [REV...]'))
3833 _('[-p|-d|-s] [-f] [-r] [REV...]'))
3832 def phase(ui, repo, *revs, **opts):
3834 def phase(ui, repo, *revs, **opts):
3833 """set or show the current phase name
3835 """set or show the current phase name
3834
3836
3835 With no argument, show the phase name of the current revision(s).
3837 With no argument, show the phase name of the current revision(s).
3836
3838
3837 With one of -p/--public, -d/--draft or -s/--secret, change the
3839 With one of -p/--public, -d/--draft or -s/--secret, change the
3838 phase value of the specified revisions.
3840 phase value of the specified revisions.
3839
3841
3840 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
3842 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
3841 lower phase to a higher phase. Phases are ordered as follows::
3843 lower phase to a higher phase. Phases are ordered as follows::
3842
3844
3843 public < draft < secret
3845 public < draft < secret
3844
3846
3845 Returns 0 on success, 1 if some phases could not be changed.
3847 Returns 0 on success, 1 if some phases could not be changed.
3846
3848
3847 (For more information about the phases concept, see :hg:`help phases`.)
3849 (For more information about the phases concept, see :hg:`help phases`.)
3848 """
3850 """
3849 opts = pycompat.byteskwargs(opts)
3851 opts = pycompat.byteskwargs(opts)
3850 # search for a unique phase argument
3852 # search for a unique phase argument
3851 targetphase = None
3853 targetphase = None
3852 for idx, name in enumerate(phases.phasenames):
3854 for idx, name in enumerate(phases.phasenames):
3853 if opts[name]:
3855 if opts[name]:
3854 if targetphase is not None:
3856 if targetphase is not None:
3855 raise error.Abort(_('only one phase can be specified'))
3857 raise error.Abort(_('only one phase can be specified'))
3856 targetphase = idx
3858 targetphase = idx
3857
3859
3858 # look for specified revision
3860 # look for specified revision
3859 revs = list(revs)
3861 revs = list(revs)
3860 revs.extend(opts['rev'])
3862 revs.extend(opts['rev'])
3861 if not revs:
3863 if not revs:
3862 # display both parents as the second parent phase can influence
3864 # display both parents as the second parent phase can influence
3863 # the phase of a merge commit
3865 # the phase of a merge commit
3864 revs = [c.rev() for c in repo[None].parents()]
3866 revs = [c.rev() for c in repo[None].parents()]
3865
3867
3866 revs = scmutil.revrange(repo, revs)
3868 revs = scmutil.revrange(repo, revs)
3867
3869
3868 ret = 0
3870 ret = 0
3869 if targetphase is None:
3871 if targetphase is None:
3870 # display
3872 # display
3871 for r in revs:
3873 for r in revs:
3872 ctx = repo[r]
3874 ctx = repo[r]
3873 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
3875 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
3874 else:
3876 else:
3875 with repo.lock(), repo.transaction("phase") as tr:
3877 with repo.lock(), repo.transaction("phase") as tr:
3876 # set phase
3878 # set phase
3877 if not revs:
3879 if not revs:
3878 raise error.Abort(_('empty revision set'))
3880 raise error.Abort(_('empty revision set'))
3879 nodes = [repo[r].node() for r in revs]
3881 nodes = [repo[r].node() for r in revs]
3880 # moving revision from public to draft may hide them
3882 # moving revision from public to draft may hide them
3881 # We have to check result on an unfiltered repository
3883 # We have to check result on an unfiltered repository
3882 unfi = repo.unfiltered()
3884 unfi = repo.unfiltered()
3883 getphase = unfi._phasecache.phase
3885 getphase = unfi._phasecache.phase
3884 olddata = [getphase(unfi, r) for r in unfi]
3886 olddata = [getphase(unfi, r) for r in unfi]
3885 phases.advanceboundary(repo, tr, targetphase, nodes)
3887 phases.advanceboundary(repo, tr, targetphase, nodes)
3886 if opts['force']:
3888 if opts['force']:
3887 phases.retractboundary(repo, tr, targetphase, nodes)
3889 phases.retractboundary(repo, tr, targetphase, nodes)
3888 getphase = unfi._phasecache.phase
3890 getphase = unfi._phasecache.phase
3889 newdata = [getphase(unfi, r) for r in unfi]
3891 newdata = [getphase(unfi, r) for r in unfi]
3890 changes = sum(newdata[r] != olddata[r] for r in unfi)
3892 changes = sum(newdata[r] != olddata[r] for r in unfi)
3891 cl = unfi.changelog
3893 cl = unfi.changelog
3892 rejected = [n for n in nodes
3894 rejected = [n for n in nodes
3893 if newdata[cl.rev(n)] < targetphase]
3895 if newdata[cl.rev(n)] < targetphase]
3894 if rejected:
3896 if rejected:
3895 ui.warn(_('cannot move %i changesets to a higher '
3897 ui.warn(_('cannot move %i changesets to a higher '
3896 'phase, use --force\n') % len(rejected))
3898 'phase, use --force\n') % len(rejected))
3897 ret = 1
3899 ret = 1
3898 if changes:
3900 if changes:
3899 msg = _('phase changed for %i changesets\n') % changes
3901 msg = _('phase changed for %i changesets\n') % changes
3900 if ret:
3902 if ret:
3901 ui.status(msg)
3903 ui.status(msg)
3902 else:
3904 else:
3903 ui.note(msg)
3905 ui.note(msg)
3904 else:
3906 else:
3905 ui.warn(_('no phases changed\n'))
3907 ui.warn(_('no phases changed\n'))
3906 return ret
3908 return ret
3907
3909
3908 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
3910 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
3909 """Run after a changegroup has been added via pull/unbundle
3911 """Run after a changegroup has been added via pull/unbundle
3910
3912
3911 This takes arguments below:
3913 This takes arguments below:
3912
3914
3913 :modheads: change of heads by pull/unbundle
3915 :modheads: change of heads by pull/unbundle
3914 :optupdate: updating working directory is needed or not
3916 :optupdate: updating working directory is needed or not
3915 :checkout: update destination revision (or None to default destination)
3917 :checkout: update destination revision (or None to default destination)
3916 :brev: a name, which might be a bookmark to be activated after updating
3918 :brev: a name, which might be a bookmark to be activated after updating
3917 """
3919 """
3918 if modheads == 0:
3920 if modheads == 0:
3919 return
3921 return
3920 if optupdate:
3922 if optupdate:
3921 try:
3923 try:
3922 return hg.updatetotally(ui, repo, checkout, brev)
3924 return hg.updatetotally(ui, repo, checkout, brev)
3923 except error.UpdateAbort as inst:
3925 except error.UpdateAbort as inst:
3924 msg = _("not updating: %s") % stringutil.forcebytestr(inst)
3926 msg = _("not updating: %s") % stringutil.forcebytestr(inst)
3925 hint = inst.hint
3927 hint = inst.hint
3926 raise error.UpdateAbort(msg, hint=hint)
3928 raise error.UpdateAbort(msg, hint=hint)
3927 if modheads > 1:
3929 if modheads > 1:
3928 currentbranchheads = len(repo.branchheads())
3930 currentbranchheads = len(repo.branchheads())
3929 if currentbranchheads == modheads:
3931 if currentbranchheads == modheads:
3930 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3932 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3931 elif currentbranchheads > 1:
3933 elif currentbranchheads > 1:
3932 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
3934 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
3933 "merge)\n"))
3935 "merge)\n"))
3934 else:
3936 else:
3935 ui.status(_("(run 'hg heads' to see heads)\n"))
3937 ui.status(_("(run 'hg heads' to see heads)\n"))
3936 elif not ui.configbool('commands', 'update.requiredest'):
3938 elif not ui.configbool('commands', 'update.requiredest'):
3937 ui.status(_("(run 'hg update' to get a working copy)\n"))
3939 ui.status(_("(run 'hg update' to get a working copy)\n"))
3938
3940
3939 @command('^pull',
3941 @command('^pull',
3940 [('u', 'update', None,
3942 [('u', 'update', None,
3941 _('update to new branch head if new descendants were pulled')),
3943 _('update to new branch head if new descendants were pulled')),
3942 ('f', 'force', None, _('run even when remote repository is unrelated')),
3944 ('f', 'force', None, _('run even when remote repository is unrelated')),
3943 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3945 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3944 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
3946 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
3945 ('b', 'branch', [], _('a specific branch you would like to pull'),
3947 ('b', 'branch', [], _('a specific branch you would like to pull'),
3946 _('BRANCH')),
3948 _('BRANCH')),
3947 ] + remoteopts,
3949 ] + remoteopts,
3948 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
3950 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
3949 def pull(ui, repo, source="default", **opts):
3951 def pull(ui, repo, source="default", **opts):
3950 """pull changes from the specified source
3952 """pull changes from the specified source
3951
3953
3952 Pull changes from a remote repository to a local one.
3954 Pull changes from a remote repository to a local one.
3953
3955
3954 This finds all changes from the repository at the specified path
3956 This finds all changes from the repository at the specified path
3955 or URL and adds them to a local repository (the current one unless
3957 or URL and adds them to a local repository (the current one unless
3956 -R is specified). By default, this does not update the copy of the
3958 -R is specified). By default, this does not update the copy of the
3957 project in the working directory.
3959 project in the working directory.
3958
3960
3959 Use :hg:`incoming` if you want to see what would have been added
3961 Use :hg:`incoming` if you want to see what would have been added
3960 by a pull at the time you issued this command. If you then decide
3962 by a pull at the time you issued this command. If you then decide
3961 to add those changes to the repository, you should use :hg:`pull
3963 to add those changes to the repository, you should use :hg:`pull
3962 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3964 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3963
3965
3964 If SOURCE is omitted, the 'default' path will be used.
3966 If SOURCE is omitted, the 'default' path will be used.
3965 See :hg:`help urls` for more information.
3967 See :hg:`help urls` for more information.
3966
3968
3967 Specifying bookmark as ``.`` is equivalent to specifying the active
3969 Specifying bookmark as ``.`` is equivalent to specifying the active
3968 bookmark's name.
3970 bookmark's name.
3969
3971
3970 Returns 0 on success, 1 if an update had unresolved files.
3972 Returns 0 on success, 1 if an update had unresolved files.
3971 """
3973 """
3972
3974
3973 opts = pycompat.byteskwargs(opts)
3975 opts = pycompat.byteskwargs(opts)
3974 if ui.configbool('commands', 'update.requiredest') and opts.get('update'):
3976 if ui.configbool('commands', 'update.requiredest') and opts.get('update'):
3975 msg = _('update destination required by configuration')
3977 msg = _('update destination required by configuration')
3976 hint = _('use hg pull followed by hg update DEST')
3978 hint = _('use hg pull followed by hg update DEST')
3977 raise error.Abort(msg, hint=hint)
3979 raise error.Abort(msg, hint=hint)
3978
3980
3979 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3981 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3980 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3982 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3981 other = hg.peer(repo, opts, source)
3983 other = hg.peer(repo, opts, source)
3982 try:
3984 try:
3983 revs, checkout = hg.addbranchrevs(repo, other, branches,
3985 revs, checkout = hg.addbranchrevs(repo, other, branches,
3984 opts.get('rev'))
3986 opts.get('rev'))
3985
3987
3986
3988
3987 pullopargs = {}
3989 pullopargs = {}
3988 if opts.get('bookmark'):
3990 if opts.get('bookmark'):
3989 if not revs:
3991 if not revs:
3990 revs = []
3992 revs = []
3991 # The list of bookmark used here is not the one used to actually
3993 # The list of bookmark used here is not the one used to actually
3992 # update the bookmark name. This can result in the revision pulled
3994 # update the bookmark name. This can result in the revision pulled
3993 # not ending up with the name of the bookmark because of a race
3995 # not ending up with the name of the bookmark because of a race
3994 # condition on the server. (See issue 4689 for details)
3996 # condition on the server. (See issue 4689 for details)
3995 remotebookmarks = other.listkeys('bookmarks')
3997 remotebookmarks = other.listkeys('bookmarks')
3996 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
3998 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
3997 pullopargs['remotebookmarks'] = remotebookmarks
3999 pullopargs['remotebookmarks'] = remotebookmarks
3998 for b in opts['bookmark']:
4000 for b in opts['bookmark']:
3999 b = repo._bookmarks.expandname(b)
4001 b = repo._bookmarks.expandname(b)
4000 if b not in remotebookmarks:
4002 if b not in remotebookmarks:
4001 raise error.Abort(_('remote bookmark %s not found!') % b)
4003 raise error.Abort(_('remote bookmark %s not found!') % b)
4002 revs.append(hex(remotebookmarks[b]))
4004 revs.append(hex(remotebookmarks[b]))
4003
4005
4004 if revs:
4006 if revs:
4005 try:
4007 try:
4006 # When 'rev' is a bookmark name, we cannot guarantee that it
4008 # When 'rev' is a bookmark name, we cannot guarantee that it
4007 # will be updated with that name because of a race condition
4009 # will be updated with that name because of a race condition
4008 # server side. (See issue 4689 for details)
4010 # server side. (See issue 4689 for details)
4009 oldrevs = revs
4011 oldrevs = revs
4010 revs = [] # actually, nodes
4012 revs = [] # actually, nodes
4011 for r in oldrevs:
4013 for r in oldrevs:
4012 node = other.lookup(r)
4014 node = other.lookup(r)
4013 revs.append(node)
4015 revs.append(node)
4014 if r == checkout:
4016 if r == checkout:
4015 checkout = node
4017 checkout = node
4016 except error.CapabilityError:
4018 except error.CapabilityError:
4017 err = _("other repository doesn't support revision lookup, "
4019 err = _("other repository doesn't support revision lookup, "
4018 "so a rev cannot be specified.")
4020 "so a rev cannot be specified.")
4019 raise error.Abort(err)
4021 raise error.Abort(err)
4020
4022
4021 wlock = util.nullcontextmanager()
4023 wlock = util.nullcontextmanager()
4022 if opts.get('update'):
4024 if opts.get('update'):
4023 wlock = repo.wlock()
4025 wlock = repo.wlock()
4024 with wlock:
4026 with wlock:
4025 pullopargs.update(opts.get('opargs', {}))
4027 pullopargs.update(opts.get('opargs', {}))
4026 modheads = exchange.pull(repo, other, heads=revs,
4028 modheads = exchange.pull(repo, other, heads=revs,
4027 force=opts.get('force'),
4029 force=opts.get('force'),
4028 bookmarks=opts.get('bookmark', ()),
4030 bookmarks=opts.get('bookmark', ()),
4029 opargs=pullopargs).cgresult
4031 opargs=pullopargs).cgresult
4030
4032
4031 # brev is a name, which might be a bookmark to be activated at
4033 # brev is a name, which might be a bookmark to be activated at
4032 # the end of the update. In other words, it is an explicit
4034 # the end of the update. In other words, it is an explicit
4033 # destination of the update
4035 # destination of the update
4034 brev = None
4036 brev = None
4035
4037
4036 if checkout:
4038 if checkout:
4037 checkout = repo.changelog.rev(checkout)
4039 checkout = repo.changelog.rev(checkout)
4038
4040
4039 # order below depends on implementation of
4041 # order below depends on implementation of
4040 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4042 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4041 # because 'checkout' is determined without it.
4043 # because 'checkout' is determined without it.
4042 if opts.get('rev'):
4044 if opts.get('rev'):
4043 brev = opts['rev'][0]
4045 brev = opts['rev'][0]
4044 elif opts.get('branch'):
4046 elif opts.get('branch'):
4045 brev = opts['branch'][0]
4047 brev = opts['branch'][0]
4046 else:
4048 else:
4047 brev = branches[0]
4049 brev = branches[0]
4048 repo._subtoppath = source
4050 repo._subtoppath = source
4049 try:
4051 try:
4050 ret = postincoming(ui, repo, modheads, opts.get('update'),
4052 ret = postincoming(ui, repo, modheads, opts.get('update'),
4051 checkout, brev)
4053 checkout, brev)
4052
4054
4053 finally:
4055 finally:
4054 del repo._subtoppath
4056 del repo._subtoppath
4055
4057
4056 finally:
4058 finally:
4057 other.close()
4059 other.close()
4058 return ret
4060 return ret
4059
4061
4060 @command('^push',
4062 @command('^push',
4061 [('f', 'force', None, _('force push')),
4063 [('f', 'force', None, _('force push')),
4062 ('r', 'rev', [],
4064 ('r', 'rev', [],
4063 _('a changeset intended to be included in the destination'),
4065 _('a changeset intended to be included in the destination'),
4064 _('REV')),
4066 _('REV')),
4065 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4067 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4066 ('b', 'branch', [],
4068 ('b', 'branch', [],
4067 _('a specific branch you would like to push'), _('BRANCH')),
4069 _('a specific branch you would like to push'), _('BRANCH')),
4068 ('', 'new-branch', False, _('allow pushing a new branch')),
4070 ('', 'new-branch', False, _('allow pushing a new branch')),
4069 ('', 'pushvars', [], _('variables that can be sent to server (ADVANCED)')),
4071 ('', 'pushvars', [], _('variables that can be sent to server (ADVANCED)')),
4070 ] + remoteopts,
4072 ] + remoteopts,
4071 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4073 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4072 def push(ui, repo, dest=None, **opts):
4074 def push(ui, repo, dest=None, **opts):
4073 """push changes to the specified destination
4075 """push changes to the specified destination
4074
4076
4075 Push changesets from the local repository to the specified
4077 Push changesets from the local repository to the specified
4076 destination.
4078 destination.
4077
4079
4078 This operation is symmetrical to pull: it is identical to a pull
4080 This operation is symmetrical to pull: it is identical to a pull
4079 in the destination repository from the current one.
4081 in the destination repository from the current one.
4080
4082
4081 By default, push will not allow creation of new heads at the
4083 By default, push will not allow creation of new heads at the
4082 destination, since multiple heads would make it unclear which head
4084 destination, since multiple heads would make it unclear which head
4083 to use. In this situation, it is recommended to pull and merge
4085 to use. In this situation, it is recommended to pull and merge
4084 before pushing.
4086 before pushing.
4085
4087
4086 Use --new-branch if you want to allow push to create a new named
4088 Use --new-branch if you want to allow push to create a new named
4087 branch that is not present at the destination. This allows you to
4089 branch that is not present at the destination. This allows you to
4088 only create a new branch without forcing other changes.
4090 only create a new branch without forcing other changes.
4089
4091
4090 .. note::
4092 .. note::
4091
4093
4092 Extra care should be taken with the -f/--force option,
4094 Extra care should be taken with the -f/--force option,
4093 which will push all new heads on all branches, an action which will
4095 which will push all new heads on all branches, an action which will
4094 almost always cause confusion for collaborators.
4096 almost always cause confusion for collaborators.
4095
4097
4096 If -r/--rev is used, the specified revision and all its ancestors
4098 If -r/--rev is used, the specified revision and all its ancestors
4097 will be pushed to the remote repository.
4099 will be pushed to the remote repository.
4098
4100
4099 If -B/--bookmark is used, the specified bookmarked revision, its
4101 If -B/--bookmark is used, the specified bookmarked revision, its
4100 ancestors, and the bookmark will be pushed to the remote
4102 ancestors, and the bookmark will be pushed to the remote
4101 repository. Specifying ``.`` is equivalent to specifying the active
4103 repository. Specifying ``.`` is equivalent to specifying the active
4102 bookmark's name.
4104 bookmark's name.
4103
4105
4104 Please see :hg:`help urls` for important details about ``ssh://``
4106 Please see :hg:`help urls` for important details about ``ssh://``
4105 URLs. If DESTINATION is omitted, a default path will be used.
4107 URLs. If DESTINATION is omitted, a default path will be used.
4106
4108
4107 .. container:: verbose
4109 .. container:: verbose
4108
4110
4109 The --pushvars option sends strings to the server that become
4111 The --pushvars option sends strings to the server that become
4110 environment variables prepended with ``HG_USERVAR_``. For example,
4112 environment variables prepended with ``HG_USERVAR_``. For example,
4111 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
4113 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
4112 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
4114 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
4113
4115
4114 pushvars can provide for user-overridable hooks as well as set debug
4116 pushvars can provide for user-overridable hooks as well as set debug
4115 levels. One example is having a hook that blocks commits containing
4117 levels. One example is having a hook that blocks commits containing
4116 conflict markers, but enables the user to override the hook if the file
4118 conflict markers, but enables the user to override the hook if the file
4117 is using conflict markers for testing purposes or the file format has
4119 is using conflict markers for testing purposes or the file format has
4118 strings that look like conflict markers.
4120 strings that look like conflict markers.
4119
4121
4120 By default, servers will ignore `--pushvars`. To enable it add the
4122 By default, servers will ignore `--pushvars`. To enable it add the
4121 following to your configuration file::
4123 following to your configuration file::
4122
4124
4123 [push]
4125 [push]
4124 pushvars.server = true
4126 pushvars.server = true
4125
4127
4126 Returns 0 if push was successful, 1 if nothing to push.
4128 Returns 0 if push was successful, 1 if nothing to push.
4127 """
4129 """
4128
4130
4129 opts = pycompat.byteskwargs(opts)
4131 opts = pycompat.byteskwargs(opts)
4130 if opts.get('bookmark'):
4132 if opts.get('bookmark'):
4131 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4133 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4132 for b in opts['bookmark']:
4134 for b in opts['bookmark']:
4133 # translate -B options to -r so changesets get pushed
4135 # translate -B options to -r so changesets get pushed
4134 b = repo._bookmarks.expandname(b)
4136 b = repo._bookmarks.expandname(b)
4135 if b in repo._bookmarks:
4137 if b in repo._bookmarks:
4136 opts.setdefault('rev', []).append(b)
4138 opts.setdefault('rev', []).append(b)
4137 else:
4139 else:
4138 # if we try to push a deleted bookmark, translate it to null
4140 # if we try to push a deleted bookmark, translate it to null
4139 # this lets simultaneous -r, -b options continue working
4141 # this lets simultaneous -r, -b options continue working
4140 opts.setdefault('rev', []).append("null")
4142 opts.setdefault('rev', []).append("null")
4141
4143
4142 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4144 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4143 if not path:
4145 if not path:
4144 raise error.Abort(_('default repository not configured!'),
4146 raise error.Abort(_('default repository not configured!'),
4145 hint=_("see 'hg help config.paths'"))
4147 hint=_("see 'hg help config.paths'"))
4146 dest = path.pushloc or path.loc
4148 dest = path.pushloc or path.loc
4147 branches = (path.branch, opts.get('branch') or [])
4149 branches = (path.branch, opts.get('branch') or [])
4148 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4150 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4149 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4151 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4150 other = hg.peer(repo, opts, dest)
4152 other = hg.peer(repo, opts, dest)
4151
4153
4152 if revs:
4154 if revs:
4153 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
4155 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
4154 if not revs:
4156 if not revs:
4155 raise error.Abort(_("specified revisions evaluate to an empty set"),
4157 raise error.Abort(_("specified revisions evaluate to an empty set"),
4156 hint=_("use different revision arguments"))
4158 hint=_("use different revision arguments"))
4157 elif path.pushrev:
4159 elif path.pushrev:
4158 # It doesn't make any sense to specify ancestor revisions. So limit
4160 # It doesn't make any sense to specify ancestor revisions. So limit
4159 # to DAG heads to make discovery simpler.
4161 # to DAG heads to make discovery simpler.
4160 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4162 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4161 revs = scmutil.revrange(repo, [expr])
4163 revs = scmutil.revrange(repo, [expr])
4162 revs = [repo[rev].node() for rev in revs]
4164 revs = [repo[rev].node() for rev in revs]
4163 if not revs:
4165 if not revs:
4164 raise error.Abort(_('default push revset for path evaluates to an '
4166 raise error.Abort(_('default push revset for path evaluates to an '
4165 'empty set'))
4167 'empty set'))
4166
4168
4167 repo._subtoppath = dest
4169 repo._subtoppath = dest
4168 try:
4170 try:
4169 # push subrepos depth-first for coherent ordering
4171 # push subrepos depth-first for coherent ordering
4170 c = repo['.']
4172 c = repo['.']
4171 subs = c.substate # only repos that are committed
4173 subs = c.substate # only repos that are committed
4172 for s in sorted(subs):
4174 for s in sorted(subs):
4173 result = c.sub(s).push(opts)
4175 result = c.sub(s).push(opts)
4174 if result == 0:
4176 if result == 0:
4175 return not result
4177 return not result
4176 finally:
4178 finally:
4177 del repo._subtoppath
4179 del repo._subtoppath
4178
4180
4179 opargs = dict(opts.get('opargs', {})) # copy opargs since we may mutate it
4181 opargs = dict(opts.get('opargs', {})) # copy opargs since we may mutate it
4180 opargs.setdefault('pushvars', []).extend(opts.get('pushvars', []))
4182 opargs.setdefault('pushvars', []).extend(opts.get('pushvars', []))
4181
4183
4182 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4184 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4183 newbranch=opts.get('new_branch'),
4185 newbranch=opts.get('new_branch'),
4184 bookmarks=opts.get('bookmark', ()),
4186 bookmarks=opts.get('bookmark', ()),
4185 opargs=opargs)
4187 opargs=opargs)
4186
4188
4187 result = not pushop.cgresult
4189 result = not pushop.cgresult
4188
4190
4189 if pushop.bkresult is not None:
4191 if pushop.bkresult is not None:
4190 if pushop.bkresult == 2:
4192 if pushop.bkresult == 2:
4191 result = 2
4193 result = 2
4192 elif not result and pushop.bkresult:
4194 elif not result and pushop.bkresult:
4193 result = 2
4195 result = 2
4194
4196
4195 return result
4197 return result
4196
4198
4197 @command('recover', [])
4199 @command('recover', [])
4198 def recover(ui, repo):
4200 def recover(ui, repo):
4199 """roll back an interrupted transaction
4201 """roll back an interrupted transaction
4200
4202
4201 Recover from an interrupted commit or pull.
4203 Recover from an interrupted commit or pull.
4202
4204
4203 This command tries to fix the repository status after an
4205 This command tries to fix the repository status after an
4204 interrupted operation. It should only be necessary when Mercurial
4206 interrupted operation. It should only be necessary when Mercurial
4205 suggests it.
4207 suggests it.
4206
4208
4207 Returns 0 if successful, 1 if nothing to recover or verify fails.
4209 Returns 0 if successful, 1 if nothing to recover or verify fails.
4208 """
4210 """
4209 if repo.recover():
4211 if repo.recover():
4210 return hg.verify(repo)
4212 return hg.verify(repo)
4211 return 1
4213 return 1
4212
4214
4213 @command('^remove|rm',
4215 @command('^remove|rm',
4214 [('A', 'after', None, _('record delete for missing files')),
4216 [('A', 'after', None, _('record delete for missing files')),
4215 ('f', 'force', None,
4217 ('f', 'force', None,
4216 _('forget added files, delete modified files')),
4218 _('forget added files, delete modified files')),
4217 ] + subrepoopts + walkopts + dryrunopts,
4219 ] + subrepoopts + walkopts + dryrunopts,
4218 _('[OPTION]... FILE...'),
4220 _('[OPTION]... FILE...'),
4219 inferrepo=True)
4221 inferrepo=True)
4220 def remove(ui, repo, *pats, **opts):
4222 def remove(ui, repo, *pats, **opts):
4221 """remove the specified files on the next commit
4223 """remove the specified files on the next commit
4222
4224
4223 Schedule the indicated files for removal from the current branch.
4225 Schedule the indicated files for removal from the current branch.
4224
4226
4225 This command schedules the files to be removed at the next commit.
4227 This command schedules the files to be removed at the next commit.
4226 To undo a remove before that, see :hg:`revert`. To undo added
4228 To undo a remove before that, see :hg:`revert`. To undo added
4227 files, see :hg:`forget`.
4229 files, see :hg:`forget`.
4228
4230
4229 .. container:: verbose
4231 .. container:: verbose
4230
4232
4231 -A/--after can be used to remove only files that have already
4233 -A/--after can be used to remove only files that have already
4232 been deleted, -f/--force can be used to force deletion, and -Af
4234 been deleted, -f/--force can be used to force deletion, and -Af
4233 can be used to remove files from the next revision without
4235 can be used to remove files from the next revision without
4234 deleting them from the working directory.
4236 deleting them from the working directory.
4235
4237
4236 The following table details the behavior of remove for different
4238 The following table details the behavior of remove for different
4237 file states (columns) and option combinations (rows). The file
4239 file states (columns) and option combinations (rows). The file
4238 states are Added [A], Clean [C], Modified [M] and Missing [!]
4240 states are Added [A], Clean [C], Modified [M] and Missing [!]
4239 (as reported by :hg:`status`). The actions are Warn, Remove
4241 (as reported by :hg:`status`). The actions are Warn, Remove
4240 (from branch) and Delete (from disk):
4242 (from branch) and Delete (from disk):
4241
4243
4242 ========= == == == ==
4244 ========= == == == ==
4243 opt/state A C M !
4245 opt/state A C M !
4244 ========= == == == ==
4246 ========= == == == ==
4245 none W RD W R
4247 none W RD W R
4246 -f R RD RD R
4248 -f R RD RD R
4247 -A W W W R
4249 -A W W W R
4248 -Af R R R R
4250 -Af R R R R
4249 ========= == == == ==
4251 ========= == == == ==
4250
4252
4251 .. note::
4253 .. note::
4252
4254
4253 :hg:`remove` never deletes files in Added [A] state from the
4255 :hg:`remove` never deletes files in Added [A] state from the
4254 working directory, not even if ``--force`` is specified.
4256 working directory, not even if ``--force`` is specified.
4255
4257
4256 Returns 0 on success, 1 if any warnings encountered.
4258 Returns 0 on success, 1 if any warnings encountered.
4257 """
4259 """
4258
4260
4259 opts = pycompat.byteskwargs(opts)
4261 opts = pycompat.byteskwargs(opts)
4260 after, force = opts.get('after'), opts.get('force')
4262 after, force = opts.get('after'), opts.get('force')
4261 dryrun = opts.get('dry_run')
4263 dryrun = opts.get('dry_run')
4262 if not pats and not after:
4264 if not pats and not after:
4263 raise error.Abort(_('no files specified'))
4265 raise error.Abort(_('no files specified'))
4264
4266
4265 m = scmutil.match(repo[None], pats, opts)
4267 m = scmutil.match(repo[None], pats, opts)
4266 subrepos = opts.get('subrepos')
4268 subrepos = opts.get('subrepos')
4267 return cmdutil.remove(ui, repo, m, "", after, force, subrepos,
4269 return cmdutil.remove(ui, repo, m, "", after, force, subrepos,
4268 dryrun=dryrun)
4270 dryrun=dryrun)
4269
4271
4270 @command('rename|move|mv',
4272 @command('rename|move|mv',
4271 [('A', 'after', None, _('record a rename that has already occurred')),
4273 [('A', 'after', None, _('record a rename that has already occurred')),
4272 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4274 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4273 ] + walkopts + dryrunopts,
4275 ] + walkopts + dryrunopts,
4274 _('[OPTION]... SOURCE... DEST'))
4276 _('[OPTION]... SOURCE... DEST'))
4275 def rename(ui, repo, *pats, **opts):
4277 def rename(ui, repo, *pats, **opts):
4276 """rename files; equivalent of copy + remove
4278 """rename files; equivalent of copy + remove
4277
4279
4278 Mark dest as copies of sources; mark sources for deletion. If dest
4280 Mark dest as copies of sources; mark sources for deletion. If dest
4279 is a directory, copies are put in that directory. If dest is a
4281 is a directory, copies are put in that directory. If dest is a
4280 file, there can only be one source.
4282 file, there can only be one source.
4281
4283
4282 By default, this command copies the contents of files as they
4284 By default, this command copies the contents of files as they
4283 exist in the working directory. If invoked with -A/--after, the
4285 exist in the working directory. If invoked with -A/--after, the
4284 operation is recorded, but no copying is performed.
4286 operation is recorded, but no copying is performed.
4285
4287
4286 This command takes effect at the next commit. To undo a rename
4288 This command takes effect at the next commit. To undo a rename
4287 before that, see :hg:`revert`.
4289 before that, see :hg:`revert`.
4288
4290
4289 Returns 0 on success, 1 if errors are encountered.
4291 Returns 0 on success, 1 if errors are encountered.
4290 """
4292 """
4291 opts = pycompat.byteskwargs(opts)
4293 opts = pycompat.byteskwargs(opts)
4292 with repo.wlock(False):
4294 with repo.wlock(False):
4293 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4295 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4294
4296
4295 @command('resolve',
4297 @command('resolve',
4296 [('a', 'all', None, _('select all unresolved files')),
4298 [('a', 'all', None, _('select all unresolved files')),
4297 ('l', 'list', None, _('list state of files needing merge')),
4299 ('l', 'list', None, _('list state of files needing merge')),
4298 ('m', 'mark', None, _('mark files as resolved')),
4300 ('m', 'mark', None, _('mark files as resolved')),
4299 ('u', 'unmark', None, _('mark files as unresolved')),
4301 ('u', 'unmark', None, _('mark files as unresolved')),
4300 ('n', 'no-status', None, _('hide status prefix'))]
4302 ('n', 'no-status', None, _('hide status prefix'))]
4301 + mergetoolopts + walkopts + formatteropts,
4303 + mergetoolopts + walkopts + formatteropts,
4302 _('[OPTION]... [FILE]...'),
4304 _('[OPTION]... [FILE]...'),
4303 inferrepo=True)
4305 inferrepo=True)
4304 def resolve(ui, repo, *pats, **opts):
4306 def resolve(ui, repo, *pats, **opts):
4305 """redo merges or set/view the merge status of files
4307 """redo merges or set/view the merge status of files
4306
4308
4307 Merges with unresolved conflicts are often the result of
4309 Merges with unresolved conflicts are often the result of
4308 non-interactive merging using the ``internal:merge`` configuration
4310 non-interactive merging using the ``internal:merge`` configuration
4309 setting, or a command-line merge tool like ``diff3``. The resolve
4311 setting, or a command-line merge tool like ``diff3``. The resolve
4310 command is used to manage the files involved in a merge, after
4312 command is used to manage the files involved in a merge, after
4311 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4313 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4312 working directory must have two parents). See :hg:`help
4314 working directory must have two parents). See :hg:`help
4313 merge-tools` for information on configuring merge tools.
4315 merge-tools` for information on configuring merge tools.
4314
4316
4315 The resolve command can be used in the following ways:
4317 The resolve command can be used in the following ways:
4316
4318
4317 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4319 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4318 files, discarding any previous merge attempts. Re-merging is not
4320 files, discarding any previous merge attempts. Re-merging is not
4319 performed for files already marked as resolved. Use ``--all/-a``
4321 performed for files already marked as resolved. Use ``--all/-a``
4320 to select all unresolved files. ``--tool`` can be used to specify
4322 to select all unresolved files. ``--tool`` can be used to specify
4321 the merge tool used for the given files. It overrides the HGMERGE
4323 the merge tool used for the given files. It overrides the HGMERGE
4322 environment variable and your configuration files. Previous file
4324 environment variable and your configuration files. Previous file
4323 contents are saved with a ``.orig`` suffix.
4325 contents are saved with a ``.orig`` suffix.
4324
4326
4325 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4327 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4326 (e.g. after having manually fixed-up the files). The default is
4328 (e.g. after having manually fixed-up the files). The default is
4327 to mark all unresolved files.
4329 to mark all unresolved files.
4328
4330
4329 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4331 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4330 default is to mark all resolved files.
4332 default is to mark all resolved files.
4331
4333
4332 - :hg:`resolve -l`: list files which had or still have conflicts.
4334 - :hg:`resolve -l`: list files which had or still have conflicts.
4333 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4335 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4334 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4336 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4335 the list. See :hg:`help filesets` for details.
4337 the list. See :hg:`help filesets` for details.
4336
4338
4337 .. note::
4339 .. note::
4338
4340
4339 Mercurial will not let you commit files with unresolved merge
4341 Mercurial will not let you commit files with unresolved merge
4340 conflicts. You must use :hg:`resolve -m ...` before you can
4342 conflicts. You must use :hg:`resolve -m ...` before you can
4341 commit after a conflicting merge.
4343 commit after a conflicting merge.
4342
4344
4343 Returns 0 on success, 1 if any files fail a resolve attempt.
4345 Returns 0 on success, 1 if any files fail a resolve attempt.
4344 """
4346 """
4345
4347
4346 opts = pycompat.byteskwargs(opts)
4348 opts = pycompat.byteskwargs(opts)
4347 flaglist = 'all mark unmark list no_status'.split()
4349 flaglist = 'all mark unmark list no_status'.split()
4348 all, mark, unmark, show, nostatus = \
4350 all, mark, unmark, show, nostatus = \
4349 [opts.get(o) for o in flaglist]
4351 [opts.get(o) for o in flaglist]
4350
4352
4351 if (show and (mark or unmark)) or (mark and unmark):
4353 if (show and (mark or unmark)) or (mark and unmark):
4352 raise error.Abort(_("too many options specified"))
4354 raise error.Abort(_("too many options specified"))
4353 if pats and all:
4355 if pats and all:
4354 raise error.Abort(_("can't specify --all and patterns"))
4356 raise error.Abort(_("can't specify --all and patterns"))
4355 if not (all or pats or show or mark or unmark):
4357 if not (all or pats or show or mark or unmark):
4356 raise error.Abort(_('no files or directories specified'),
4358 raise error.Abort(_('no files or directories specified'),
4357 hint=('use --all to re-merge all unresolved files'))
4359 hint=('use --all to re-merge all unresolved files'))
4358
4360
4359 if show:
4361 if show:
4360 ui.pager('resolve')
4362 ui.pager('resolve')
4361 fm = ui.formatter('resolve', opts)
4363 fm = ui.formatter('resolve', opts)
4362 ms = mergemod.mergestate.read(repo)
4364 ms = mergemod.mergestate.read(repo)
4363 m = scmutil.match(repo[None], pats, opts)
4365 m = scmutil.match(repo[None], pats, opts)
4364
4366
4365 # Labels and keys based on merge state. Unresolved path conflicts show
4367 # Labels and keys based on merge state. Unresolved path conflicts show
4366 # as 'P'. Resolved path conflicts show as 'R', the same as normal
4368 # as 'P'. Resolved path conflicts show as 'R', the same as normal
4367 # resolved conflicts.
4369 # resolved conflicts.
4368 mergestateinfo = {
4370 mergestateinfo = {
4369 mergemod.MERGE_RECORD_UNRESOLVED: ('resolve.unresolved', 'U'),
4371 mergemod.MERGE_RECORD_UNRESOLVED: ('resolve.unresolved', 'U'),
4370 mergemod.MERGE_RECORD_RESOLVED: ('resolve.resolved', 'R'),
4372 mergemod.MERGE_RECORD_RESOLVED: ('resolve.resolved', 'R'),
4371 mergemod.MERGE_RECORD_UNRESOLVED_PATH: ('resolve.unresolved', 'P'),
4373 mergemod.MERGE_RECORD_UNRESOLVED_PATH: ('resolve.unresolved', 'P'),
4372 mergemod.MERGE_RECORD_RESOLVED_PATH: ('resolve.resolved', 'R'),
4374 mergemod.MERGE_RECORD_RESOLVED_PATH: ('resolve.resolved', 'R'),
4373 mergemod.MERGE_RECORD_DRIVER_RESOLVED: ('resolve.driverresolved',
4375 mergemod.MERGE_RECORD_DRIVER_RESOLVED: ('resolve.driverresolved',
4374 'D'),
4376 'D'),
4375 }
4377 }
4376
4378
4377 for f in ms:
4379 for f in ms:
4378 if not m(f):
4380 if not m(f):
4379 continue
4381 continue
4380
4382
4381 label, key = mergestateinfo[ms[f]]
4383 label, key = mergestateinfo[ms[f]]
4382 fm.startitem()
4384 fm.startitem()
4383 fm.condwrite(not nostatus, 'status', '%s ', key, label=label)
4385 fm.condwrite(not nostatus, 'status', '%s ', key, label=label)
4384 fm.write('path', '%s\n', f, label=label)
4386 fm.write('path', '%s\n', f, label=label)
4385 fm.end()
4387 fm.end()
4386 return 0
4388 return 0
4387
4389
4388 with repo.wlock():
4390 with repo.wlock():
4389 ms = mergemod.mergestate.read(repo)
4391 ms = mergemod.mergestate.read(repo)
4390
4392
4391 if not (ms.active() or repo.dirstate.p2() != nullid):
4393 if not (ms.active() or repo.dirstate.p2() != nullid):
4392 raise error.Abort(
4394 raise error.Abort(
4393 _('resolve command not applicable when not merging'))
4395 _('resolve command not applicable when not merging'))
4394
4396
4395 wctx = repo[None]
4397 wctx = repo[None]
4396
4398
4397 if (ms.mergedriver
4399 if (ms.mergedriver
4398 and ms.mdstate() == mergemod.MERGE_DRIVER_STATE_UNMARKED):
4400 and ms.mdstate() == mergemod.MERGE_DRIVER_STATE_UNMARKED):
4399 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4401 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4400 ms.commit()
4402 ms.commit()
4401 # allow mark and unmark to go through
4403 # allow mark and unmark to go through
4402 if not mark and not unmark and not proceed:
4404 if not mark and not unmark and not proceed:
4403 return 1
4405 return 1
4404
4406
4405 m = scmutil.match(wctx, pats, opts)
4407 m = scmutil.match(wctx, pats, opts)
4406 ret = 0
4408 ret = 0
4407 didwork = False
4409 didwork = False
4408 runconclude = False
4410 runconclude = False
4409
4411
4410 tocomplete = []
4412 tocomplete = []
4411 for f in ms:
4413 for f in ms:
4412 if not m(f):
4414 if not m(f):
4413 continue
4415 continue
4414
4416
4415 didwork = True
4417 didwork = True
4416
4418
4417 # don't let driver-resolved files be marked, and run the conclude
4419 # don't let driver-resolved files be marked, and run the conclude
4418 # step if asked to resolve
4420 # step if asked to resolve
4419 if ms[f] == mergemod.MERGE_RECORD_DRIVER_RESOLVED:
4421 if ms[f] == mergemod.MERGE_RECORD_DRIVER_RESOLVED:
4420 exact = m.exact(f)
4422 exact = m.exact(f)
4421 if mark:
4423 if mark:
4422 if exact:
4424 if exact:
4423 ui.warn(_('not marking %s as it is driver-resolved\n')
4425 ui.warn(_('not marking %s as it is driver-resolved\n')
4424 % f)
4426 % f)
4425 elif unmark:
4427 elif unmark:
4426 if exact:
4428 if exact:
4427 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4429 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4428 % f)
4430 % f)
4429 else:
4431 else:
4430 runconclude = True
4432 runconclude = True
4431 continue
4433 continue
4432
4434
4433 # path conflicts must be resolved manually
4435 # path conflicts must be resolved manually
4434 if ms[f] in (mergemod.MERGE_RECORD_UNRESOLVED_PATH,
4436 if ms[f] in (mergemod.MERGE_RECORD_UNRESOLVED_PATH,
4435 mergemod.MERGE_RECORD_RESOLVED_PATH):
4437 mergemod.MERGE_RECORD_RESOLVED_PATH):
4436 if mark:
4438 if mark:
4437 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED_PATH)
4439 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED_PATH)
4438 elif unmark:
4440 elif unmark:
4439 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED_PATH)
4441 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED_PATH)
4440 elif ms[f] == mergemod.MERGE_RECORD_UNRESOLVED_PATH:
4442 elif ms[f] == mergemod.MERGE_RECORD_UNRESOLVED_PATH:
4441 ui.warn(_('%s: path conflict must be resolved manually\n')
4443 ui.warn(_('%s: path conflict must be resolved manually\n')
4442 % f)
4444 % f)
4443 continue
4445 continue
4444
4446
4445 if mark:
4447 if mark:
4446 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED)
4448 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED)
4447 elif unmark:
4449 elif unmark:
4448 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED)
4450 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED)
4449 else:
4451 else:
4450 # backup pre-resolve (merge uses .orig for its own purposes)
4452 # backup pre-resolve (merge uses .orig for its own purposes)
4451 a = repo.wjoin(f)
4453 a = repo.wjoin(f)
4452 try:
4454 try:
4453 util.copyfile(a, a + ".resolve")
4455 util.copyfile(a, a + ".resolve")
4454 except (IOError, OSError) as inst:
4456 except (IOError, OSError) as inst:
4455 if inst.errno != errno.ENOENT:
4457 if inst.errno != errno.ENOENT:
4456 raise
4458 raise
4457
4459
4458 try:
4460 try:
4459 # preresolve file
4461 # preresolve file
4460 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4462 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4461 'resolve')
4463 'resolve')
4462 complete, r = ms.preresolve(f, wctx)
4464 complete, r = ms.preresolve(f, wctx)
4463 if not complete:
4465 if not complete:
4464 tocomplete.append(f)
4466 tocomplete.append(f)
4465 elif r:
4467 elif r:
4466 ret = 1
4468 ret = 1
4467 finally:
4469 finally:
4468 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4470 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4469 ms.commit()
4471 ms.commit()
4470
4472
4471 # replace filemerge's .orig file with our resolve file, but only
4473 # replace filemerge's .orig file with our resolve file, but only
4472 # for merges that are complete
4474 # for merges that are complete
4473 if complete:
4475 if complete:
4474 try:
4476 try:
4475 util.rename(a + ".resolve",
4477 util.rename(a + ".resolve",
4476 scmutil.origpath(ui, repo, a))
4478 scmutil.origpath(ui, repo, a))
4477 except OSError as inst:
4479 except OSError as inst:
4478 if inst.errno != errno.ENOENT:
4480 if inst.errno != errno.ENOENT:
4479 raise
4481 raise
4480
4482
4481 for f in tocomplete:
4483 for f in tocomplete:
4482 try:
4484 try:
4483 # resolve file
4485 # resolve file
4484 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4486 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4485 'resolve')
4487 'resolve')
4486 r = ms.resolve(f, wctx)
4488 r = ms.resolve(f, wctx)
4487 if r:
4489 if r:
4488 ret = 1
4490 ret = 1
4489 finally:
4491 finally:
4490 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4492 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4491 ms.commit()
4493 ms.commit()
4492
4494
4493 # replace filemerge's .orig file with our resolve file
4495 # replace filemerge's .orig file with our resolve file
4494 a = repo.wjoin(f)
4496 a = repo.wjoin(f)
4495 try:
4497 try:
4496 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4498 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4497 except OSError as inst:
4499 except OSError as inst:
4498 if inst.errno != errno.ENOENT:
4500 if inst.errno != errno.ENOENT:
4499 raise
4501 raise
4500
4502
4501 ms.commit()
4503 ms.commit()
4502 ms.recordactions()
4504 ms.recordactions()
4503
4505
4504 if not didwork and pats:
4506 if not didwork and pats:
4505 hint = None
4507 hint = None
4506 if not any([p for p in pats if p.find(':') >= 0]):
4508 if not any([p for p in pats if p.find(':') >= 0]):
4507 pats = ['path:%s' % p for p in pats]
4509 pats = ['path:%s' % p for p in pats]
4508 m = scmutil.match(wctx, pats, opts)
4510 m = scmutil.match(wctx, pats, opts)
4509 for f in ms:
4511 for f in ms:
4510 if not m(f):
4512 if not m(f):
4511 continue
4513 continue
4512 flags = ''.join(['-%s ' % o[0:1] for o in flaglist
4514 flags = ''.join(['-%s ' % o[0:1] for o in flaglist
4513 if opts.get(o)])
4515 if opts.get(o)])
4514 hint = _("(try: hg resolve %s%s)\n") % (
4516 hint = _("(try: hg resolve %s%s)\n") % (
4515 flags,
4517 flags,
4516 ' '.join(pats))
4518 ' '.join(pats))
4517 break
4519 break
4518 ui.warn(_("arguments do not match paths that need resolving\n"))
4520 ui.warn(_("arguments do not match paths that need resolving\n"))
4519 if hint:
4521 if hint:
4520 ui.warn(hint)
4522 ui.warn(hint)
4521 elif ms.mergedriver and ms.mdstate() != 's':
4523 elif ms.mergedriver and ms.mdstate() != 's':
4522 # run conclude step when either a driver-resolved file is requested
4524 # run conclude step when either a driver-resolved file is requested
4523 # or there are no driver-resolved files
4525 # or there are no driver-resolved files
4524 # we can't use 'ret' to determine whether any files are unresolved
4526 # we can't use 'ret' to determine whether any files are unresolved
4525 # because we might not have tried to resolve some
4527 # because we might not have tried to resolve some
4526 if ((runconclude or not list(ms.driverresolved()))
4528 if ((runconclude or not list(ms.driverresolved()))
4527 and not list(ms.unresolved())):
4529 and not list(ms.unresolved())):
4528 proceed = mergemod.driverconclude(repo, ms, wctx)
4530 proceed = mergemod.driverconclude(repo, ms, wctx)
4529 ms.commit()
4531 ms.commit()
4530 if not proceed:
4532 if not proceed:
4531 return 1
4533 return 1
4532
4534
4533 # Nudge users into finishing an unfinished operation
4535 # Nudge users into finishing an unfinished operation
4534 unresolvedf = list(ms.unresolved())
4536 unresolvedf = list(ms.unresolved())
4535 driverresolvedf = list(ms.driverresolved())
4537 driverresolvedf = list(ms.driverresolved())
4536 if not unresolvedf and not driverresolvedf:
4538 if not unresolvedf and not driverresolvedf:
4537 ui.status(_('(no more unresolved files)\n'))
4539 ui.status(_('(no more unresolved files)\n'))
4538 cmdutil.checkafterresolved(repo)
4540 cmdutil.checkafterresolved(repo)
4539 elif not unresolvedf:
4541 elif not unresolvedf:
4540 ui.status(_('(no more unresolved files -- '
4542 ui.status(_('(no more unresolved files -- '
4541 'run "hg resolve --all" to conclude)\n'))
4543 'run "hg resolve --all" to conclude)\n'))
4542
4544
4543 return ret
4545 return ret
4544
4546
4545 @command('revert',
4547 @command('revert',
4546 [('a', 'all', None, _('revert all changes when no arguments given')),
4548 [('a', 'all', None, _('revert all changes when no arguments given')),
4547 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4549 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4548 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4550 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4549 ('C', 'no-backup', None, _('do not save backup copies of files')),
4551 ('C', 'no-backup', None, _('do not save backup copies of files')),
4550 ('i', 'interactive', None, _('interactively select the changes')),
4552 ('i', 'interactive', None, _('interactively select the changes')),
4551 ] + walkopts + dryrunopts,
4553 ] + walkopts + dryrunopts,
4552 _('[OPTION]... [-r REV] [NAME]...'))
4554 _('[OPTION]... [-r REV] [NAME]...'))
4553 def revert(ui, repo, *pats, **opts):
4555 def revert(ui, repo, *pats, **opts):
4554 """restore files to their checkout state
4556 """restore files to their checkout state
4555
4557
4556 .. note::
4558 .. note::
4557
4559
4558 To check out earlier revisions, you should use :hg:`update REV`.
4560 To check out earlier revisions, you should use :hg:`update REV`.
4559 To cancel an uncommitted merge (and lose your changes),
4561 To cancel an uncommitted merge (and lose your changes),
4560 use :hg:`merge --abort`.
4562 use :hg:`merge --abort`.
4561
4563
4562 With no revision specified, revert the specified files or directories
4564 With no revision specified, revert the specified files or directories
4563 to the contents they had in the parent of the working directory.
4565 to the contents they had in the parent of the working directory.
4564 This restores the contents of files to an unmodified
4566 This restores the contents of files to an unmodified
4565 state and unschedules adds, removes, copies, and renames. If the
4567 state and unschedules adds, removes, copies, and renames. If the
4566 working directory has two parents, you must explicitly specify a
4568 working directory has two parents, you must explicitly specify a
4567 revision.
4569 revision.
4568
4570
4569 Using the -r/--rev or -d/--date options, revert the given files or
4571 Using the -r/--rev or -d/--date options, revert the given files or
4570 directories to their states as of a specific revision. Because
4572 directories to their states as of a specific revision. Because
4571 revert does not change the working directory parents, this will
4573 revert does not change the working directory parents, this will
4572 cause these files to appear modified. This can be helpful to "back
4574 cause these files to appear modified. This can be helpful to "back
4573 out" some or all of an earlier change. See :hg:`backout` for a
4575 out" some or all of an earlier change. See :hg:`backout` for a
4574 related method.
4576 related method.
4575
4577
4576 Modified files are saved with a .orig suffix before reverting.
4578 Modified files are saved with a .orig suffix before reverting.
4577 To disable these backups, use --no-backup. It is possible to store
4579 To disable these backups, use --no-backup. It is possible to store
4578 the backup files in a custom directory relative to the root of the
4580 the backup files in a custom directory relative to the root of the
4579 repository by setting the ``ui.origbackuppath`` configuration
4581 repository by setting the ``ui.origbackuppath`` configuration
4580 option.
4582 option.
4581
4583
4582 See :hg:`help dates` for a list of formats valid for -d/--date.
4584 See :hg:`help dates` for a list of formats valid for -d/--date.
4583
4585
4584 See :hg:`help backout` for a way to reverse the effect of an
4586 See :hg:`help backout` for a way to reverse the effect of an
4585 earlier changeset.
4587 earlier changeset.
4586
4588
4587 Returns 0 on success.
4589 Returns 0 on success.
4588 """
4590 """
4589
4591
4590 opts = pycompat.byteskwargs(opts)
4592 opts = pycompat.byteskwargs(opts)
4591 if opts.get("date"):
4593 if opts.get("date"):
4592 if opts.get("rev"):
4594 if opts.get("rev"):
4593 raise error.Abort(_("you can't specify a revision and a date"))
4595 raise error.Abort(_("you can't specify a revision and a date"))
4594 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4596 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4595
4597
4596 parent, p2 = repo.dirstate.parents()
4598 parent, p2 = repo.dirstate.parents()
4597 if not opts.get('rev') and p2 != nullid:
4599 if not opts.get('rev') and p2 != nullid:
4598 # revert after merge is a trap for new users (issue2915)
4600 # revert after merge is a trap for new users (issue2915)
4599 raise error.Abort(_('uncommitted merge with no revision specified'),
4601 raise error.Abort(_('uncommitted merge with no revision specified'),
4600 hint=_("use 'hg update' or see 'hg help revert'"))
4602 hint=_("use 'hg update' or see 'hg help revert'"))
4601
4603
4602 rev = opts.get('rev')
4604 rev = opts.get('rev')
4603 if rev:
4605 if rev:
4604 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
4606 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
4605 ctx = scmutil.revsingle(repo, rev)
4607 ctx = scmutil.revsingle(repo, rev)
4606
4608
4607 if (not (pats or opts.get('include') or opts.get('exclude') or
4609 if (not (pats or opts.get('include') or opts.get('exclude') or
4608 opts.get('all') or opts.get('interactive'))):
4610 opts.get('all') or opts.get('interactive'))):
4609 msg = _("no files or directories specified")
4611 msg = _("no files or directories specified")
4610 if p2 != nullid:
4612 if p2 != nullid:
4611 hint = _("uncommitted merge, use --all to discard all changes,"
4613 hint = _("uncommitted merge, use --all to discard all changes,"
4612 " or 'hg update -C .' to abort the merge")
4614 " or 'hg update -C .' to abort the merge")
4613 raise error.Abort(msg, hint=hint)
4615 raise error.Abort(msg, hint=hint)
4614 dirty = any(repo.status())
4616 dirty = any(repo.status())
4615 node = ctx.node()
4617 node = ctx.node()
4616 if node != parent:
4618 if node != parent:
4617 if dirty:
4619 if dirty:
4618 hint = _("uncommitted changes, use --all to discard all"
4620 hint = _("uncommitted changes, use --all to discard all"
4619 " changes, or 'hg update %s' to update") % ctx.rev()
4621 " changes, or 'hg update %s' to update") % ctx.rev()
4620 else:
4622 else:
4621 hint = _("use --all to revert all files,"
4623 hint = _("use --all to revert all files,"
4622 " or 'hg update %s' to update") % ctx.rev()
4624 " or 'hg update %s' to update") % ctx.rev()
4623 elif dirty:
4625 elif dirty:
4624 hint = _("uncommitted changes, use --all to discard all changes")
4626 hint = _("uncommitted changes, use --all to discard all changes")
4625 else:
4627 else:
4626 hint = _("use --all to revert all files")
4628 hint = _("use --all to revert all files")
4627 raise error.Abort(msg, hint=hint)
4629 raise error.Abort(msg, hint=hint)
4628
4630
4629 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats,
4631 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats,
4630 **pycompat.strkwargs(opts))
4632 **pycompat.strkwargs(opts))
4631
4633
4632 @command('rollback', dryrunopts +
4634 @command('rollback', dryrunopts +
4633 [('f', 'force', False, _('ignore safety measures'))])
4635 [('f', 'force', False, _('ignore safety measures'))])
4634 def rollback(ui, repo, **opts):
4636 def rollback(ui, repo, **opts):
4635 """roll back the last transaction (DANGEROUS) (DEPRECATED)
4637 """roll back the last transaction (DANGEROUS) (DEPRECATED)
4636
4638
4637 Please use :hg:`commit --amend` instead of rollback to correct
4639 Please use :hg:`commit --amend` instead of rollback to correct
4638 mistakes in the last commit.
4640 mistakes in the last commit.
4639
4641
4640 This command should be used with care. There is only one level of
4642 This command should be used with care. There is only one level of
4641 rollback, and there is no way to undo a rollback. It will also
4643 rollback, and there is no way to undo a rollback. It will also
4642 restore the dirstate at the time of the last transaction, losing
4644 restore the dirstate at the time of the last transaction, losing
4643 any dirstate changes since that time. This command does not alter
4645 any dirstate changes since that time. This command does not alter
4644 the working directory.
4646 the working directory.
4645
4647
4646 Transactions are used to encapsulate the effects of all commands
4648 Transactions are used to encapsulate the effects of all commands
4647 that create new changesets or propagate existing changesets into a
4649 that create new changesets or propagate existing changesets into a
4648 repository.
4650 repository.
4649
4651
4650 .. container:: verbose
4652 .. container:: verbose
4651
4653
4652 For example, the following commands are transactional, and their
4654 For example, the following commands are transactional, and their
4653 effects can be rolled back:
4655 effects can be rolled back:
4654
4656
4655 - commit
4657 - commit
4656 - import
4658 - import
4657 - pull
4659 - pull
4658 - push (with this repository as the destination)
4660 - push (with this repository as the destination)
4659 - unbundle
4661 - unbundle
4660
4662
4661 To avoid permanent data loss, rollback will refuse to rollback a
4663 To avoid permanent data loss, rollback will refuse to rollback a
4662 commit transaction if it isn't checked out. Use --force to
4664 commit transaction if it isn't checked out. Use --force to
4663 override this protection.
4665 override this protection.
4664
4666
4665 The rollback command can be entirely disabled by setting the
4667 The rollback command can be entirely disabled by setting the
4666 ``ui.rollback`` configuration setting to false. If you're here
4668 ``ui.rollback`` configuration setting to false. If you're here
4667 because you want to use rollback and it's disabled, you can
4669 because you want to use rollback and it's disabled, you can
4668 re-enable the command by setting ``ui.rollback`` to true.
4670 re-enable the command by setting ``ui.rollback`` to true.
4669
4671
4670 This command is not intended for use on public repositories. Once
4672 This command is not intended for use on public repositories. Once
4671 changes are visible for pull by other users, rolling a transaction
4673 changes are visible for pull by other users, rolling a transaction
4672 back locally is ineffective (someone else may already have pulled
4674 back locally is ineffective (someone else may already have pulled
4673 the changes). Furthermore, a race is possible with readers of the
4675 the changes). Furthermore, a race is possible with readers of the
4674 repository; for example an in-progress pull from the repository
4676 repository; for example an in-progress pull from the repository
4675 may fail if a rollback is performed.
4677 may fail if a rollback is performed.
4676
4678
4677 Returns 0 on success, 1 if no rollback data is available.
4679 Returns 0 on success, 1 if no rollback data is available.
4678 """
4680 """
4679 if not ui.configbool('ui', 'rollback'):
4681 if not ui.configbool('ui', 'rollback'):
4680 raise error.Abort(_('rollback is disabled because it is unsafe'),
4682 raise error.Abort(_('rollback is disabled because it is unsafe'),
4681 hint=('see `hg help -v rollback` for information'))
4683 hint=('see `hg help -v rollback` for information'))
4682 return repo.rollback(dryrun=opts.get(r'dry_run'),
4684 return repo.rollback(dryrun=opts.get(r'dry_run'),
4683 force=opts.get(r'force'))
4685 force=opts.get(r'force'))
4684
4686
4685 @command('root', [], cmdtype=readonly)
4687 @command('root', [], cmdtype=readonly)
4686 def root(ui, repo):
4688 def root(ui, repo):
4687 """print the root (top) of the current working directory
4689 """print the root (top) of the current working directory
4688
4690
4689 Print the root directory of the current repository.
4691 Print the root directory of the current repository.
4690
4692
4691 Returns 0 on success.
4693 Returns 0 on success.
4692 """
4694 """
4693 ui.write(repo.root + "\n")
4695 ui.write(repo.root + "\n")
4694
4696
4695 @command('^serve',
4697 @command('^serve',
4696 [('A', 'accesslog', '', _('name of access log file to write to'),
4698 [('A', 'accesslog', '', _('name of access log file to write to'),
4697 _('FILE')),
4699 _('FILE')),
4698 ('d', 'daemon', None, _('run server in background')),
4700 ('d', 'daemon', None, _('run server in background')),
4699 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
4701 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
4700 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4702 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4701 # use string type, then we can check if something was passed
4703 # use string type, then we can check if something was passed
4702 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4704 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4703 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4705 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4704 _('ADDR')),
4706 _('ADDR')),
4705 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4707 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4706 _('PREFIX')),
4708 _('PREFIX')),
4707 ('n', 'name', '',
4709 ('n', 'name', '',
4708 _('name to show in web pages (default: working directory)'), _('NAME')),
4710 _('name to show in web pages (default: working directory)'), _('NAME')),
4709 ('', 'web-conf', '',
4711 ('', 'web-conf', '',
4710 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
4712 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
4711 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4713 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4712 _('FILE')),
4714 _('FILE')),
4713 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4715 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4714 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
4716 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
4715 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
4717 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
4716 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4718 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4717 ('', 'style', '', _('template style to use'), _('STYLE')),
4719 ('', 'style', '', _('template style to use'), _('STYLE')),
4718 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4720 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4719 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))]
4721 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))]
4720 + subrepoopts,
4722 + subrepoopts,
4721 _('[OPTION]...'),
4723 _('[OPTION]...'),
4722 optionalrepo=True)
4724 optionalrepo=True)
4723 def serve(ui, repo, **opts):
4725 def serve(ui, repo, **opts):
4724 """start stand-alone webserver
4726 """start stand-alone webserver
4725
4727
4726 Start a local HTTP repository browser and pull server. You can use
4728 Start a local HTTP repository browser and pull server. You can use
4727 this for ad-hoc sharing and browsing of repositories. It is
4729 this for ad-hoc sharing and browsing of repositories. It is
4728 recommended to use a real web server to serve a repository for
4730 recommended to use a real web server to serve a repository for
4729 longer periods of time.
4731 longer periods of time.
4730
4732
4731 Please note that the server does not implement access control.
4733 Please note that the server does not implement access control.
4732 This means that, by default, anybody can read from the server and
4734 This means that, by default, anybody can read from the server and
4733 nobody can write to it by default. Set the ``web.allow-push``
4735 nobody can write to it by default. Set the ``web.allow-push``
4734 option to ``*`` to allow everybody to push to the server. You
4736 option to ``*`` to allow everybody to push to the server. You
4735 should use a real web server if you need to authenticate users.
4737 should use a real web server if you need to authenticate users.
4736
4738
4737 By default, the server logs accesses to stdout and errors to
4739 By default, the server logs accesses to stdout and errors to
4738 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4740 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4739 files.
4741 files.
4740
4742
4741 To have the server choose a free port number to listen on, specify
4743 To have the server choose a free port number to listen on, specify
4742 a port number of 0; in this case, the server will print the port
4744 a port number of 0; in this case, the server will print the port
4743 number it uses.
4745 number it uses.
4744
4746
4745 Returns 0 on success.
4747 Returns 0 on success.
4746 """
4748 """
4747
4749
4748 opts = pycompat.byteskwargs(opts)
4750 opts = pycompat.byteskwargs(opts)
4749 if opts["stdio"] and opts["cmdserver"]:
4751 if opts["stdio"] and opts["cmdserver"]:
4750 raise error.Abort(_("cannot use --stdio with --cmdserver"))
4752 raise error.Abort(_("cannot use --stdio with --cmdserver"))
4751
4753
4752 if opts["stdio"]:
4754 if opts["stdio"]:
4753 if repo is None:
4755 if repo is None:
4754 raise error.RepoError(_("there is no Mercurial repository here"
4756 raise error.RepoError(_("there is no Mercurial repository here"
4755 " (.hg not found)"))
4757 " (.hg not found)"))
4756 s = wireprotoserver.sshserver(ui, repo)
4758 s = wireprotoserver.sshserver(ui, repo)
4757 s.serve_forever()
4759 s.serve_forever()
4758
4760
4759 service = server.createservice(ui, repo, opts)
4761 service = server.createservice(ui, repo, opts)
4760 return server.runservice(opts, initfn=service.init, runfn=service.run)
4762 return server.runservice(opts, initfn=service.init, runfn=service.run)
4761
4763
4762 @command('^status|st',
4764 @command('^status|st',
4763 [('A', 'all', None, _('show status of all files')),
4765 [('A', 'all', None, _('show status of all files')),
4764 ('m', 'modified', None, _('show only modified files')),
4766 ('m', 'modified', None, _('show only modified files')),
4765 ('a', 'added', None, _('show only added files')),
4767 ('a', 'added', None, _('show only added files')),
4766 ('r', 'removed', None, _('show only removed files')),
4768 ('r', 'removed', None, _('show only removed files')),
4767 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4769 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4768 ('c', 'clean', None, _('show only files without changes')),
4770 ('c', 'clean', None, _('show only files without changes')),
4769 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4771 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4770 ('i', 'ignored', None, _('show only ignored files')),
4772 ('i', 'ignored', None, _('show only ignored files')),
4771 ('n', 'no-status', None, _('hide status prefix')),
4773 ('n', 'no-status', None, _('hide status prefix')),
4772 ('t', 'terse', '', _('show the terse output (EXPERIMENTAL)')),
4774 ('t', 'terse', '', _('show the terse output (EXPERIMENTAL)')),
4773 ('C', 'copies', None, _('show source of copied files')),
4775 ('C', 'copies', None, _('show source of copied files')),
4774 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4776 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4775 ('', 'rev', [], _('show difference from revision'), _('REV')),
4777 ('', 'rev', [], _('show difference from revision'), _('REV')),
4776 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4778 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4777 ] + walkopts + subrepoopts + formatteropts,
4779 ] + walkopts + subrepoopts + formatteropts,
4778 _('[OPTION]... [FILE]...'),
4780 _('[OPTION]... [FILE]...'),
4779 inferrepo=True, cmdtype=readonly)
4781 inferrepo=True, cmdtype=readonly)
4780 def status(ui, repo, *pats, **opts):
4782 def status(ui, repo, *pats, **opts):
4781 """show changed files in the working directory
4783 """show changed files in the working directory
4782
4784
4783 Show status of files in the repository. If names are given, only
4785 Show status of files in the repository. If names are given, only
4784 files that match are shown. Files that are clean or ignored or
4786 files that match are shown. Files that are clean or ignored or
4785 the source of a copy/move operation, are not listed unless
4787 the source of a copy/move operation, are not listed unless
4786 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4788 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4787 Unless options described with "show only ..." are given, the
4789 Unless options described with "show only ..." are given, the
4788 options -mardu are used.
4790 options -mardu are used.
4789
4791
4790 Option -q/--quiet hides untracked (unknown and ignored) files
4792 Option -q/--quiet hides untracked (unknown and ignored) files
4791 unless explicitly requested with -u/--unknown or -i/--ignored.
4793 unless explicitly requested with -u/--unknown or -i/--ignored.
4792
4794
4793 .. note::
4795 .. note::
4794
4796
4795 :hg:`status` may appear to disagree with diff if permissions have
4797 :hg:`status` may appear to disagree with diff if permissions have
4796 changed or a merge has occurred. The standard diff format does
4798 changed or a merge has occurred. The standard diff format does
4797 not report permission changes and diff only reports changes
4799 not report permission changes and diff only reports changes
4798 relative to one merge parent.
4800 relative to one merge parent.
4799
4801
4800 If one revision is given, it is used as the base revision.
4802 If one revision is given, it is used as the base revision.
4801 If two revisions are given, the differences between them are
4803 If two revisions are given, the differences between them are
4802 shown. The --change option can also be used as a shortcut to list
4804 shown. The --change option can also be used as a shortcut to list
4803 the changed files of a revision from its first parent.
4805 the changed files of a revision from its first parent.
4804
4806
4805 The codes used to show the status of files are::
4807 The codes used to show the status of files are::
4806
4808
4807 M = modified
4809 M = modified
4808 A = added
4810 A = added
4809 R = removed
4811 R = removed
4810 C = clean
4812 C = clean
4811 ! = missing (deleted by non-hg command, but still tracked)
4813 ! = missing (deleted by non-hg command, but still tracked)
4812 ? = not tracked
4814 ? = not tracked
4813 I = ignored
4815 I = ignored
4814 = origin of the previous file (with --copies)
4816 = origin of the previous file (with --copies)
4815
4817
4816 .. container:: verbose
4818 .. container:: verbose
4817
4819
4818 The -t/--terse option abbreviates the output by showing only the directory
4820 The -t/--terse option abbreviates the output by showing only the directory
4819 name if all the files in it share the same status. The option takes an
4821 name if all the files in it share the same status. The option takes an
4820 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
4822 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
4821 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
4823 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
4822 for 'ignored' and 'c' for clean.
4824 for 'ignored' and 'c' for clean.
4823
4825
4824 It abbreviates only those statuses which are passed. Note that clean and
4826 It abbreviates only those statuses which are passed. Note that clean and
4825 ignored files are not displayed with '--terse ic' unless the -c/--clean
4827 ignored files are not displayed with '--terse ic' unless the -c/--clean
4826 and -i/--ignored options are also used.
4828 and -i/--ignored options are also used.
4827
4829
4828 The -v/--verbose option shows information when the repository is in an
4830 The -v/--verbose option shows information when the repository is in an
4829 unfinished merge, shelve, rebase state etc. You can have this behavior
4831 unfinished merge, shelve, rebase state etc. You can have this behavior
4830 turned on by default by enabling the ``commands.status.verbose`` option.
4832 turned on by default by enabling the ``commands.status.verbose`` option.
4831
4833
4832 You can skip displaying some of these states by setting
4834 You can skip displaying some of these states by setting
4833 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
4835 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
4834 'histedit', 'merge', 'rebase', or 'unshelve'.
4836 'histedit', 'merge', 'rebase', or 'unshelve'.
4835
4837
4836 Examples:
4838 Examples:
4837
4839
4838 - show changes in the working directory relative to a
4840 - show changes in the working directory relative to a
4839 changeset::
4841 changeset::
4840
4842
4841 hg status --rev 9353
4843 hg status --rev 9353
4842
4844
4843 - show changes in the working directory relative to the
4845 - show changes in the working directory relative to the
4844 current directory (see :hg:`help patterns` for more information)::
4846 current directory (see :hg:`help patterns` for more information)::
4845
4847
4846 hg status re:
4848 hg status re:
4847
4849
4848 - show all changes including copies in an existing changeset::
4850 - show all changes including copies in an existing changeset::
4849
4851
4850 hg status --copies --change 9353
4852 hg status --copies --change 9353
4851
4853
4852 - get a NUL separated list of added files, suitable for xargs::
4854 - get a NUL separated list of added files, suitable for xargs::
4853
4855
4854 hg status -an0
4856 hg status -an0
4855
4857
4856 - show more information about the repository status, abbreviating
4858 - show more information about the repository status, abbreviating
4857 added, removed, modified, deleted, and untracked paths::
4859 added, removed, modified, deleted, and untracked paths::
4858
4860
4859 hg status -v -t mardu
4861 hg status -v -t mardu
4860
4862
4861 Returns 0 on success.
4863 Returns 0 on success.
4862
4864
4863 """
4865 """
4864
4866
4865 opts = pycompat.byteskwargs(opts)
4867 opts = pycompat.byteskwargs(opts)
4866 revs = opts.get('rev')
4868 revs = opts.get('rev')
4867 change = opts.get('change')
4869 change = opts.get('change')
4868 terse = opts.get('terse')
4870 terse = opts.get('terse')
4869
4871
4870 if revs and change:
4872 if revs and change:
4871 msg = _('cannot specify --rev and --change at the same time')
4873 msg = _('cannot specify --rev and --change at the same time')
4872 raise error.Abort(msg)
4874 raise error.Abort(msg)
4873 elif revs and terse:
4875 elif revs and terse:
4874 msg = _('cannot use --terse with --rev')
4876 msg = _('cannot use --terse with --rev')
4875 raise error.Abort(msg)
4877 raise error.Abort(msg)
4876 elif change:
4878 elif change:
4877 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
4879 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
4878 ctx2 = scmutil.revsingle(repo, change, None)
4880 ctx2 = scmutil.revsingle(repo, change, None)
4879 ctx1 = ctx2.p1()
4881 ctx1 = ctx2.p1()
4880 else:
4882 else:
4881 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
4883 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
4882 ctx1, ctx2 = scmutil.revpair(repo, revs)
4884 ctx1, ctx2 = scmutil.revpair(repo, revs)
4883
4885
4884 if pats or ui.configbool('commands', 'status.relative'):
4886 if pats or ui.configbool('commands', 'status.relative'):
4885 cwd = repo.getcwd()
4887 cwd = repo.getcwd()
4886 else:
4888 else:
4887 cwd = ''
4889 cwd = ''
4888
4890
4889 if opts.get('print0'):
4891 if opts.get('print0'):
4890 end = '\0'
4892 end = '\0'
4891 else:
4893 else:
4892 end = '\n'
4894 end = '\n'
4893 copy = {}
4895 copy = {}
4894 states = 'modified added removed deleted unknown ignored clean'.split()
4896 states = 'modified added removed deleted unknown ignored clean'.split()
4895 show = [k for k in states if opts.get(k)]
4897 show = [k for k in states if opts.get(k)]
4896 if opts.get('all'):
4898 if opts.get('all'):
4897 show += ui.quiet and (states[:4] + ['clean']) or states
4899 show += ui.quiet and (states[:4] + ['clean']) or states
4898
4900
4899 if not show:
4901 if not show:
4900 if ui.quiet:
4902 if ui.quiet:
4901 show = states[:4]
4903 show = states[:4]
4902 else:
4904 else:
4903 show = states[:5]
4905 show = states[:5]
4904
4906
4905 m = scmutil.match(ctx2, pats, opts)
4907 m = scmutil.match(ctx2, pats, opts)
4906 if terse:
4908 if terse:
4907 # we need to compute clean and unknown to terse
4909 # we need to compute clean and unknown to terse
4908 stat = repo.status(ctx1.node(), ctx2.node(), m,
4910 stat = repo.status(ctx1.node(), ctx2.node(), m,
4909 'ignored' in show or 'i' in terse,
4911 'ignored' in show or 'i' in terse,
4910 True, True, opts.get('subrepos'))
4912 True, True, opts.get('subrepos'))
4911
4913
4912 stat = cmdutil.tersedir(stat, terse)
4914 stat = cmdutil.tersedir(stat, terse)
4913 else:
4915 else:
4914 stat = repo.status(ctx1.node(), ctx2.node(), m,
4916 stat = repo.status(ctx1.node(), ctx2.node(), m,
4915 'ignored' in show, 'clean' in show,
4917 'ignored' in show, 'clean' in show,
4916 'unknown' in show, opts.get('subrepos'))
4918 'unknown' in show, opts.get('subrepos'))
4917
4919
4918 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
4920 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
4919
4921
4920 if (opts.get('all') or opts.get('copies')
4922 if (opts.get('all') or opts.get('copies')
4921 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
4923 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
4922 copy = copies.pathcopies(ctx1, ctx2, m)
4924 copy = copies.pathcopies(ctx1, ctx2, m)
4923
4925
4924 ui.pager('status')
4926 ui.pager('status')
4925 fm = ui.formatter('status', opts)
4927 fm = ui.formatter('status', opts)
4926 fmt = '%s' + end
4928 fmt = '%s' + end
4927 showchar = not opts.get('no_status')
4929 showchar = not opts.get('no_status')
4928
4930
4929 for state, char, files in changestates:
4931 for state, char, files in changestates:
4930 if state in show:
4932 if state in show:
4931 label = 'status.' + state
4933 label = 'status.' + state
4932 for f in files:
4934 for f in files:
4933 fm.startitem()
4935 fm.startitem()
4934 fm.condwrite(showchar, 'status', '%s ', char, label=label)
4936 fm.condwrite(showchar, 'status', '%s ', char, label=label)
4935 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
4937 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
4936 if f in copy:
4938 if f in copy:
4937 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
4939 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
4938 label='status.copied')
4940 label='status.copied')
4939
4941
4940 if ((ui.verbose or ui.configbool('commands', 'status.verbose'))
4942 if ((ui.verbose or ui.configbool('commands', 'status.verbose'))
4941 and not ui.plain()):
4943 and not ui.plain()):
4942 cmdutil.morestatus(repo, fm)
4944 cmdutil.morestatus(repo, fm)
4943 fm.end()
4945 fm.end()
4944
4946
4945 @command('^summary|sum',
4947 @command('^summary|sum',
4946 [('', 'remote', None, _('check for push and pull'))],
4948 [('', 'remote', None, _('check for push and pull'))],
4947 '[--remote]', cmdtype=readonly)
4949 '[--remote]', cmdtype=readonly)
4948 def summary(ui, repo, **opts):
4950 def summary(ui, repo, **opts):
4949 """summarize working directory state
4951 """summarize working directory state
4950
4952
4951 This generates a brief summary of the working directory state,
4953 This generates a brief summary of the working directory state,
4952 including parents, branch, commit status, phase and available updates.
4954 including parents, branch, commit status, phase and available updates.
4953
4955
4954 With the --remote option, this will check the default paths for
4956 With the --remote option, this will check the default paths for
4955 incoming and outgoing changes. This can be time-consuming.
4957 incoming and outgoing changes. This can be time-consuming.
4956
4958
4957 Returns 0 on success.
4959 Returns 0 on success.
4958 """
4960 """
4959
4961
4960 opts = pycompat.byteskwargs(opts)
4962 opts = pycompat.byteskwargs(opts)
4961 ui.pager('summary')
4963 ui.pager('summary')
4962 ctx = repo[None]
4964 ctx = repo[None]
4963 parents = ctx.parents()
4965 parents = ctx.parents()
4964 pnode = parents[0].node()
4966 pnode = parents[0].node()
4965 marks = []
4967 marks = []
4966
4968
4967 ms = None
4969 ms = None
4968 try:
4970 try:
4969 ms = mergemod.mergestate.read(repo)
4971 ms = mergemod.mergestate.read(repo)
4970 except error.UnsupportedMergeRecords as e:
4972 except error.UnsupportedMergeRecords as e:
4971 s = ' '.join(e.recordtypes)
4973 s = ' '.join(e.recordtypes)
4972 ui.warn(
4974 ui.warn(
4973 _('warning: merge state has unsupported record types: %s\n') % s)
4975 _('warning: merge state has unsupported record types: %s\n') % s)
4974 unresolved = []
4976 unresolved = []
4975 else:
4977 else:
4976 unresolved = list(ms.unresolved())
4978 unresolved = list(ms.unresolved())
4977
4979
4978 for p in parents:
4980 for p in parents:
4979 # label with log.changeset (instead of log.parent) since this
4981 # label with log.changeset (instead of log.parent) since this
4980 # shows a working directory parent *changeset*:
4982 # shows a working directory parent *changeset*:
4981 # i18n: column positioning for "hg summary"
4983 # i18n: column positioning for "hg summary"
4982 ui.write(_('parent: %d:%s ') % (p.rev(), p),
4984 ui.write(_('parent: %d:%s ') % (p.rev(), p),
4983 label=logcmdutil.changesetlabels(p))
4985 label=logcmdutil.changesetlabels(p))
4984 ui.write(' '.join(p.tags()), label='log.tag')
4986 ui.write(' '.join(p.tags()), label='log.tag')
4985 if p.bookmarks():
4987 if p.bookmarks():
4986 marks.extend(p.bookmarks())
4988 marks.extend(p.bookmarks())
4987 if p.rev() == -1:
4989 if p.rev() == -1:
4988 if not len(repo):
4990 if not len(repo):
4989 ui.write(_(' (empty repository)'))
4991 ui.write(_(' (empty repository)'))
4990 else:
4992 else:
4991 ui.write(_(' (no revision checked out)'))
4993 ui.write(_(' (no revision checked out)'))
4992 if p.obsolete():
4994 if p.obsolete():
4993 ui.write(_(' (obsolete)'))
4995 ui.write(_(' (obsolete)'))
4994 if p.isunstable():
4996 if p.isunstable():
4995 instabilities = (ui.label(instability, 'trouble.%s' % instability)
4997 instabilities = (ui.label(instability, 'trouble.%s' % instability)
4996 for instability in p.instabilities())
4998 for instability in p.instabilities())
4997 ui.write(' ('
4999 ui.write(' ('
4998 + ', '.join(instabilities)
5000 + ', '.join(instabilities)
4999 + ')')
5001 + ')')
5000 ui.write('\n')
5002 ui.write('\n')
5001 if p.description():
5003 if p.description():
5002 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5004 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5003 label='log.summary')
5005 label='log.summary')
5004
5006
5005 branch = ctx.branch()
5007 branch = ctx.branch()
5006 bheads = repo.branchheads(branch)
5008 bheads = repo.branchheads(branch)
5007 # i18n: column positioning for "hg summary"
5009 # i18n: column positioning for "hg summary"
5008 m = _('branch: %s\n') % branch
5010 m = _('branch: %s\n') % branch
5009 if branch != 'default':
5011 if branch != 'default':
5010 ui.write(m, label='log.branch')
5012 ui.write(m, label='log.branch')
5011 else:
5013 else:
5012 ui.status(m, label='log.branch')
5014 ui.status(m, label='log.branch')
5013
5015
5014 if marks:
5016 if marks:
5015 active = repo._activebookmark
5017 active = repo._activebookmark
5016 # i18n: column positioning for "hg summary"
5018 # i18n: column positioning for "hg summary"
5017 ui.write(_('bookmarks:'), label='log.bookmark')
5019 ui.write(_('bookmarks:'), label='log.bookmark')
5018 if active is not None:
5020 if active is not None:
5019 if active in marks:
5021 if active in marks:
5020 ui.write(' *' + active, label=bookmarks.activebookmarklabel)
5022 ui.write(' *' + active, label=bookmarks.activebookmarklabel)
5021 marks.remove(active)
5023 marks.remove(active)
5022 else:
5024 else:
5023 ui.write(' [%s]' % active, label=bookmarks.activebookmarklabel)
5025 ui.write(' [%s]' % active, label=bookmarks.activebookmarklabel)
5024 for m in marks:
5026 for m in marks:
5025 ui.write(' ' + m, label='log.bookmark')
5027 ui.write(' ' + m, label='log.bookmark')
5026 ui.write('\n', label='log.bookmark')
5028 ui.write('\n', label='log.bookmark')
5027
5029
5028 status = repo.status(unknown=True)
5030 status = repo.status(unknown=True)
5029
5031
5030 c = repo.dirstate.copies()
5032 c = repo.dirstate.copies()
5031 copied, renamed = [], []
5033 copied, renamed = [], []
5032 for d, s in c.iteritems():
5034 for d, s in c.iteritems():
5033 if s in status.removed:
5035 if s in status.removed:
5034 status.removed.remove(s)
5036 status.removed.remove(s)
5035 renamed.append(d)
5037 renamed.append(d)
5036 else:
5038 else:
5037 copied.append(d)
5039 copied.append(d)
5038 if d in status.added:
5040 if d in status.added:
5039 status.added.remove(d)
5041 status.added.remove(d)
5040
5042
5041 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5043 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5042
5044
5043 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5045 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5044 (ui.label(_('%d added'), 'status.added'), status.added),
5046 (ui.label(_('%d added'), 'status.added'), status.added),
5045 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5047 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5046 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5048 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5047 (ui.label(_('%d copied'), 'status.copied'), copied),
5049 (ui.label(_('%d copied'), 'status.copied'), copied),
5048 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5050 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5049 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5051 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5050 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5052 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5051 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5053 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5052 t = []
5054 t = []
5053 for l, s in labels:
5055 for l, s in labels:
5054 if s:
5056 if s:
5055 t.append(l % len(s))
5057 t.append(l % len(s))
5056
5058
5057 t = ', '.join(t)
5059 t = ', '.join(t)
5058 cleanworkdir = False
5060 cleanworkdir = False
5059
5061
5060 if repo.vfs.exists('graftstate'):
5062 if repo.vfs.exists('graftstate'):
5061 t += _(' (graft in progress)')
5063 t += _(' (graft in progress)')
5062 if repo.vfs.exists('updatestate'):
5064 if repo.vfs.exists('updatestate'):
5063 t += _(' (interrupted update)')
5065 t += _(' (interrupted update)')
5064 elif len(parents) > 1:
5066 elif len(parents) > 1:
5065 t += _(' (merge)')
5067 t += _(' (merge)')
5066 elif branch != parents[0].branch():
5068 elif branch != parents[0].branch():
5067 t += _(' (new branch)')
5069 t += _(' (new branch)')
5068 elif (parents[0].closesbranch() and
5070 elif (parents[0].closesbranch() and
5069 pnode in repo.branchheads(branch, closed=True)):
5071 pnode in repo.branchheads(branch, closed=True)):
5070 t += _(' (head closed)')
5072 t += _(' (head closed)')
5071 elif not (status.modified or status.added or status.removed or renamed or
5073 elif not (status.modified or status.added or status.removed or renamed or
5072 copied or subs):
5074 copied or subs):
5073 t += _(' (clean)')
5075 t += _(' (clean)')
5074 cleanworkdir = True
5076 cleanworkdir = True
5075 elif pnode not in bheads:
5077 elif pnode not in bheads:
5076 t += _(' (new branch head)')
5078 t += _(' (new branch head)')
5077
5079
5078 if parents:
5080 if parents:
5079 pendingphase = max(p.phase() for p in parents)
5081 pendingphase = max(p.phase() for p in parents)
5080 else:
5082 else:
5081 pendingphase = phases.public
5083 pendingphase = phases.public
5082
5084
5083 if pendingphase > phases.newcommitphase(ui):
5085 if pendingphase > phases.newcommitphase(ui):
5084 t += ' (%s)' % phases.phasenames[pendingphase]
5086 t += ' (%s)' % phases.phasenames[pendingphase]
5085
5087
5086 if cleanworkdir:
5088 if cleanworkdir:
5087 # i18n: column positioning for "hg summary"
5089 # i18n: column positioning for "hg summary"
5088 ui.status(_('commit: %s\n') % t.strip())
5090 ui.status(_('commit: %s\n') % t.strip())
5089 else:
5091 else:
5090 # i18n: column positioning for "hg summary"
5092 # i18n: column positioning for "hg summary"
5091 ui.write(_('commit: %s\n') % t.strip())
5093 ui.write(_('commit: %s\n') % t.strip())
5092
5094
5093 # all ancestors of branch heads - all ancestors of parent = new csets
5095 # all ancestors of branch heads - all ancestors of parent = new csets
5094 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5096 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5095 bheads))
5097 bheads))
5096
5098
5097 if new == 0:
5099 if new == 0:
5098 # i18n: column positioning for "hg summary"
5100 # i18n: column positioning for "hg summary"
5099 ui.status(_('update: (current)\n'))
5101 ui.status(_('update: (current)\n'))
5100 elif pnode not in bheads:
5102 elif pnode not in bheads:
5101 # i18n: column positioning for "hg summary"
5103 # i18n: column positioning for "hg summary"
5102 ui.write(_('update: %d new changesets (update)\n') % new)
5104 ui.write(_('update: %d new changesets (update)\n') % new)
5103 else:
5105 else:
5104 # i18n: column positioning for "hg summary"
5106 # i18n: column positioning for "hg summary"
5105 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5107 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5106 (new, len(bheads)))
5108 (new, len(bheads)))
5107
5109
5108 t = []
5110 t = []
5109 draft = len(repo.revs('draft()'))
5111 draft = len(repo.revs('draft()'))
5110 if draft:
5112 if draft:
5111 t.append(_('%d draft') % draft)
5113 t.append(_('%d draft') % draft)
5112 secret = len(repo.revs('secret()'))
5114 secret = len(repo.revs('secret()'))
5113 if secret:
5115 if secret:
5114 t.append(_('%d secret') % secret)
5116 t.append(_('%d secret') % secret)
5115
5117
5116 if draft or secret:
5118 if draft or secret:
5117 ui.status(_('phases: %s\n') % ', '.join(t))
5119 ui.status(_('phases: %s\n') % ', '.join(t))
5118
5120
5119 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5121 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5120 for trouble in ("orphan", "contentdivergent", "phasedivergent"):
5122 for trouble in ("orphan", "contentdivergent", "phasedivergent"):
5121 numtrouble = len(repo.revs(trouble + "()"))
5123 numtrouble = len(repo.revs(trouble + "()"))
5122 # We write all the possibilities to ease translation
5124 # We write all the possibilities to ease translation
5123 troublemsg = {
5125 troublemsg = {
5124 "orphan": _("orphan: %d changesets"),
5126 "orphan": _("orphan: %d changesets"),
5125 "contentdivergent": _("content-divergent: %d changesets"),
5127 "contentdivergent": _("content-divergent: %d changesets"),
5126 "phasedivergent": _("phase-divergent: %d changesets"),
5128 "phasedivergent": _("phase-divergent: %d changesets"),
5127 }
5129 }
5128 if numtrouble > 0:
5130 if numtrouble > 0:
5129 ui.status(troublemsg[trouble] % numtrouble + "\n")
5131 ui.status(troublemsg[trouble] % numtrouble + "\n")
5130
5132
5131 cmdutil.summaryhooks(ui, repo)
5133 cmdutil.summaryhooks(ui, repo)
5132
5134
5133 if opts.get('remote'):
5135 if opts.get('remote'):
5134 needsincoming, needsoutgoing = True, True
5136 needsincoming, needsoutgoing = True, True
5135 else:
5137 else:
5136 needsincoming, needsoutgoing = False, False
5138 needsincoming, needsoutgoing = False, False
5137 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5139 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5138 if i:
5140 if i:
5139 needsincoming = True
5141 needsincoming = True
5140 if o:
5142 if o:
5141 needsoutgoing = True
5143 needsoutgoing = True
5142 if not needsincoming and not needsoutgoing:
5144 if not needsincoming and not needsoutgoing:
5143 return
5145 return
5144
5146
5145 def getincoming():
5147 def getincoming():
5146 source, branches = hg.parseurl(ui.expandpath('default'))
5148 source, branches = hg.parseurl(ui.expandpath('default'))
5147 sbranch = branches[0]
5149 sbranch = branches[0]
5148 try:
5150 try:
5149 other = hg.peer(repo, {}, source)
5151 other = hg.peer(repo, {}, source)
5150 except error.RepoError:
5152 except error.RepoError:
5151 if opts.get('remote'):
5153 if opts.get('remote'):
5152 raise
5154 raise
5153 return source, sbranch, None, None, None
5155 return source, sbranch, None, None, None
5154 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5156 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5155 if revs:
5157 if revs:
5156 revs = [other.lookup(rev) for rev in revs]
5158 revs = [other.lookup(rev) for rev in revs]
5157 ui.debug('comparing with %s\n' % util.hidepassword(source))
5159 ui.debug('comparing with %s\n' % util.hidepassword(source))
5158 repo.ui.pushbuffer()
5160 repo.ui.pushbuffer()
5159 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5161 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5160 repo.ui.popbuffer()
5162 repo.ui.popbuffer()
5161 return source, sbranch, other, commoninc, commoninc[1]
5163 return source, sbranch, other, commoninc, commoninc[1]
5162
5164
5163 if needsincoming:
5165 if needsincoming:
5164 source, sbranch, sother, commoninc, incoming = getincoming()
5166 source, sbranch, sother, commoninc, incoming = getincoming()
5165 else:
5167 else:
5166 source = sbranch = sother = commoninc = incoming = None
5168 source = sbranch = sother = commoninc = incoming = None
5167
5169
5168 def getoutgoing():
5170 def getoutgoing():
5169 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5171 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5170 dbranch = branches[0]
5172 dbranch = branches[0]
5171 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5173 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5172 if source != dest:
5174 if source != dest:
5173 try:
5175 try:
5174 dother = hg.peer(repo, {}, dest)
5176 dother = hg.peer(repo, {}, dest)
5175 except error.RepoError:
5177 except error.RepoError:
5176 if opts.get('remote'):
5178 if opts.get('remote'):
5177 raise
5179 raise
5178 return dest, dbranch, None, None
5180 return dest, dbranch, None, None
5179 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5181 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5180 elif sother is None:
5182 elif sother is None:
5181 # there is no explicit destination peer, but source one is invalid
5183 # there is no explicit destination peer, but source one is invalid
5182 return dest, dbranch, None, None
5184 return dest, dbranch, None, None
5183 else:
5185 else:
5184 dother = sother
5186 dother = sother
5185 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5187 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5186 common = None
5188 common = None
5187 else:
5189 else:
5188 common = commoninc
5190 common = commoninc
5189 if revs:
5191 if revs:
5190 revs = [repo.lookup(rev) for rev in revs]
5192 revs = [repo.lookup(rev) for rev in revs]
5191 repo.ui.pushbuffer()
5193 repo.ui.pushbuffer()
5192 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5194 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5193 commoninc=common)
5195 commoninc=common)
5194 repo.ui.popbuffer()
5196 repo.ui.popbuffer()
5195 return dest, dbranch, dother, outgoing
5197 return dest, dbranch, dother, outgoing
5196
5198
5197 if needsoutgoing:
5199 if needsoutgoing:
5198 dest, dbranch, dother, outgoing = getoutgoing()
5200 dest, dbranch, dother, outgoing = getoutgoing()
5199 else:
5201 else:
5200 dest = dbranch = dother = outgoing = None
5202 dest = dbranch = dother = outgoing = None
5201
5203
5202 if opts.get('remote'):
5204 if opts.get('remote'):
5203 t = []
5205 t = []
5204 if incoming:
5206 if incoming:
5205 t.append(_('1 or more incoming'))
5207 t.append(_('1 or more incoming'))
5206 o = outgoing.missing
5208 o = outgoing.missing
5207 if o:
5209 if o:
5208 t.append(_('%d outgoing') % len(o))
5210 t.append(_('%d outgoing') % len(o))
5209 other = dother or sother
5211 other = dother or sother
5210 if 'bookmarks' in other.listkeys('namespaces'):
5212 if 'bookmarks' in other.listkeys('namespaces'):
5211 counts = bookmarks.summary(repo, other)
5213 counts = bookmarks.summary(repo, other)
5212 if counts[0] > 0:
5214 if counts[0] > 0:
5213 t.append(_('%d incoming bookmarks') % counts[0])
5215 t.append(_('%d incoming bookmarks') % counts[0])
5214 if counts[1] > 0:
5216 if counts[1] > 0:
5215 t.append(_('%d outgoing bookmarks') % counts[1])
5217 t.append(_('%d outgoing bookmarks') % counts[1])
5216
5218
5217 if t:
5219 if t:
5218 # i18n: column positioning for "hg summary"
5220 # i18n: column positioning for "hg summary"
5219 ui.write(_('remote: %s\n') % (', '.join(t)))
5221 ui.write(_('remote: %s\n') % (', '.join(t)))
5220 else:
5222 else:
5221 # i18n: column positioning for "hg summary"
5223 # i18n: column positioning for "hg summary"
5222 ui.status(_('remote: (synced)\n'))
5224 ui.status(_('remote: (synced)\n'))
5223
5225
5224 cmdutil.summaryremotehooks(ui, repo, opts,
5226 cmdutil.summaryremotehooks(ui, repo, opts,
5225 ((source, sbranch, sother, commoninc),
5227 ((source, sbranch, sother, commoninc),
5226 (dest, dbranch, dother, outgoing)))
5228 (dest, dbranch, dother, outgoing)))
5227
5229
5228 @command('tag',
5230 @command('tag',
5229 [('f', 'force', None, _('force tag')),
5231 [('f', 'force', None, _('force tag')),
5230 ('l', 'local', None, _('make the tag local')),
5232 ('l', 'local', None, _('make the tag local')),
5231 ('r', 'rev', '', _('revision to tag'), _('REV')),
5233 ('r', 'rev', '', _('revision to tag'), _('REV')),
5232 ('', 'remove', None, _('remove a tag')),
5234 ('', 'remove', None, _('remove a tag')),
5233 # -l/--local is already there, commitopts cannot be used
5235 # -l/--local is already there, commitopts cannot be used
5234 ('e', 'edit', None, _('invoke editor on commit messages')),
5236 ('e', 'edit', None, _('invoke editor on commit messages')),
5235 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5237 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5236 ] + commitopts2,
5238 ] + commitopts2,
5237 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5239 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5238 def tag(ui, repo, name1, *names, **opts):
5240 def tag(ui, repo, name1, *names, **opts):
5239 """add one or more tags for the current or given revision
5241 """add one or more tags for the current or given revision
5240
5242
5241 Name a particular revision using <name>.
5243 Name a particular revision using <name>.
5242
5244
5243 Tags are used to name particular revisions of the repository and are
5245 Tags are used to name particular revisions of the repository and are
5244 very useful to compare different revisions, to go back to significant
5246 very useful to compare different revisions, to go back to significant
5245 earlier versions or to mark branch points as releases, etc. Changing
5247 earlier versions or to mark branch points as releases, etc. Changing
5246 an existing tag is normally disallowed; use -f/--force to override.
5248 an existing tag is normally disallowed; use -f/--force to override.
5247
5249
5248 If no revision is given, the parent of the working directory is
5250 If no revision is given, the parent of the working directory is
5249 used.
5251 used.
5250
5252
5251 To facilitate version control, distribution, and merging of tags,
5253 To facilitate version control, distribution, and merging of tags,
5252 they are stored as a file named ".hgtags" which is managed similarly
5254 they are stored as a file named ".hgtags" which is managed similarly
5253 to other project files and can be hand-edited if necessary. This
5255 to other project files and can be hand-edited if necessary. This
5254 also means that tagging creates a new commit. The file
5256 also means that tagging creates a new commit. The file
5255 ".hg/localtags" is used for local tags (not shared among
5257 ".hg/localtags" is used for local tags (not shared among
5256 repositories).
5258 repositories).
5257
5259
5258 Tag commits are usually made at the head of a branch. If the parent
5260 Tag commits are usually made at the head of a branch. If the parent
5259 of the working directory is not a branch head, :hg:`tag` aborts; use
5261 of the working directory is not a branch head, :hg:`tag` aborts; use
5260 -f/--force to force the tag commit to be based on a non-head
5262 -f/--force to force the tag commit to be based on a non-head
5261 changeset.
5263 changeset.
5262
5264
5263 See :hg:`help dates` for a list of formats valid for -d/--date.
5265 See :hg:`help dates` for a list of formats valid for -d/--date.
5264
5266
5265 Since tag names have priority over branch names during revision
5267 Since tag names have priority over branch names during revision
5266 lookup, using an existing branch name as a tag name is discouraged.
5268 lookup, using an existing branch name as a tag name is discouraged.
5267
5269
5268 Returns 0 on success.
5270 Returns 0 on success.
5269 """
5271 """
5270 opts = pycompat.byteskwargs(opts)
5272 opts = pycompat.byteskwargs(opts)
5271 wlock = lock = None
5273 wlock = lock = None
5272 try:
5274 try:
5273 wlock = repo.wlock()
5275 wlock = repo.wlock()
5274 lock = repo.lock()
5276 lock = repo.lock()
5275 rev_ = "."
5277 rev_ = "."
5276 names = [t.strip() for t in (name1,) + names]
5278 names = [t.strip() for t in (name1,) + names]
5277 if len(names) != len(set(names)):
5279 if len(names) != len(set(names)):
5278 raise error.Abort(_('tag names must be unique'))
5280 raise error.Abort(_('tag names must be unique'))
5279 for n in names:
5281 for n in names:
5280 scmutil.checknewlabel(repo, n, 'tag')
5282 scmutil.checknewlabel(repo, n, 'tag')
5281 if not n:
5283 if not n:
5282 raise error.Abort(_('tag names cannot consist entirely of '
5284 raise error.Abort(_('tag names cannot consist entirely of '
5283 'whitespace'))
5285 'whitespace'))
5284 if opts.get('rev') and opts.get('remove'):
5286 if opts.get('rev') and opts.get('remove'):
5285 raise error.Abort(_("--rev and --remove are incompatible"))
5287 raise error.Abort(_("--rev and --remove are incompatible"))
5286 if opts.get('rev'):
5288 if opts.get('rev'):
5287 rev_ = opts['rev']
5289 rev_ = opts['rev']
5288 message = opts.get('message')
5290 message = opts.get('message')
5289 if opts.get('remove'):
5291 if opts.get('remove'):
5290 if opts.get('local'):
5292 if opts.get('local'):
5291 expectedtype = 'local'
5293 expectedtype = 'local'
5292 else:
5294 else:
5293 expectedtype = 'global'
5295 expectedtype = 'global'
5294
5296
5295 for n in names:
5297 for n in names:
5296 if not repo.tagtype(n):
5298 if not repo.tagtype(n):
5297 raise error.Abort(_("tag '%s' does not exist") % n)
5299 raise error.Abort(_("tag '%s' does not exist") % n)
5298 if repo.tagtype(n) != expectedtype:
5300 if repo.tagtype(n) != expectedtype:
5299 if expectedtype == 'global':
5301 if expectedtype == 'global':
5300 raise error.Abort(_("tag '%s' is not a global tag") % n)
5302 raise error.Abort(_("tag '%s' is not a global tag") % n)
5301 else:
5303 else:
5302 raise error.Abort(_("tag '%s' is not a local tag") % n)
5304 raise error.Abort(_("tag '%s' is not a local tag") % n)
5303 rev_ = 'null'
5305 rev_ = 'null'
5304 if not message:
5306 if not message:
5305 # we don't translate commit messages
5307 # we don't translate commit messages
5306 message = 'Removed tag %s' % ', '.join(names)
5308 message = 'Removed tag %s' % ', '.join(names)
5307 elif not opts.get('force'):
5309 elif not opts.get('force'):
5308 for n in names:
5310 for n in names:
5309 if n in repo.tags():
5311 if n in repo.tags():
5310 raise error.Abort(_("tag '%s' already exists "
5312 raise error.Abort(_("tag '%s' already exists "
5311 "(use -f to force)") % n)
5313 "(use -f to force)") % n)
5312 if not opts.get('local'):
5314 if not opts.get('local'):
5313 p1, p2 = repo.dirstate.parents()
5315 p1, p2 = repo.dirstate.parents()
5314 if p2 != nullid:
5316 if p2 != nullid:
5315 raise error.Abort(_('uncommitted merge'))
5317 raise error.Abort(_('uncommitted merge'))
5316 bheads = repo.branchheads()
5318 bheads = repo.branchheads()
5317 if not opts.get('force') and bheads and p1 not in bheads:
5319 if not opts.get('force') and bheads and p1 not in bheads:
5318 raise error.Abort(_('working directory is not at a branch head '
5320 raise error.Abort(_('working directory is not at a branch head '
5319 '(use -f to force)'))
5321 '(use -f to force)'))
5320 node = scmutil.revsingle(repo, rev_).node()
5322 node = scmutil.revsingle(repo, rev_).node()
5321
5323
5322 if not message:
5324 if not message:
5323 # we don't translate commit messages
5325 # we don't translate commit messages
5324 message = ('Added tag %s for changeset %s' %
5326 message = ('Added tag %s for changeset %s' %
5325 (', '.join(names), short(node)))
5327 (', '.join(names), short(node)))
5326
5328
5327 date = opts.get('date')
5329 date = opts.get('date')
5328 if date:
5330 if date:
5329 date = dateutil.parsedate(date)
5331 date = dateutil.parsedate(date)
5330
5332
5331 if opts.get('remove'):
5333 if opts.get('remove'):
5332 editform = 'tag.remove'
5334 editform = 'tag.remove'
5333 else:
5335 else:
5334 editform = 'tag.add'
5336 editform = 'tag.add'
5335 editor = cmdutil.getcommiteditor(editform=editform,
5337 editor = cmdutil.getcommiteditor(editform=editform,
5336 **pycompat.strkwargs(opts))
5338 **pycompat.strkwargs(opts))
5337
5339
5338 # don't allow tagging the null rev
5340 # don't allow tagging the null rev
5339 if (not opts.get('remove') and
5341 if (not opts.get('remove') and
5340 scmutil.revsingle(repo, rev_).rev() == nullrev):
5342 scmutil.revsingle(repo, rev_).rev() == nullrev):
5341 raise error.Abort(_("cannot tag null revision"))
5343 raise error.Abort(_("cannot tag null revision"))
5342
5344
5343 tagsmod.tag(repo, names, node, message, opts.get('local'),
5345 tagsmod.tag(repo, names, node, message, opts.get('local'),
5344 opts.get('user'), date, editor=editor)
5346 opts.get('user'), date, editor=editor)
5345 finally:
5347 finally:
5346 release(lock, wlock)
5348 release(lock, wlock)
5347
5349
5348 @command('tags', formatteropts, '', cmdtype=readonly)
5350 @command('tags', formatteropts, '', cmdtype=readonly)
5349 def tags(ui, repo, **opts):
5351 def tags(ui, repo, **opts):
5350 """list repository tags
5352 """list repository tags
5351
5353
5352 This lists both regular and local tags. When the -v/--verbose
5354 This lists both regular and local tags. When the -v/--verbose
5353 switch is used, a third column "local" is printed for local tags.
5355 switch is used, a third column "local" is printed for local tags.
5354 When the -q/--quiet switch is used, only the tag name is printed.
5356 When the -q/--quiet switch is used, only the tag name is printed.
5355
5357
5356 Returns 0 on success.
5358 Returns 0 on success.
5357 """
5359 """
5358
5360
5359 opts = pycompat.byteskwargs(opts)
5361 opts = pycompat.byteskwargs(opts)
5360 ui.pager('tags')
5362 ui.pager('tags')
5361 fm = ui.formatter('tags', opts)
5363 fm = ui.formatter('tags', opts)
5362 hexfunc = fm.hexfunc
5364 hexfunc = fm.hexfunc
5363 tagtype = ""
5365 tagtype = ""
5364
5366
5365 for t, n in reversed(repo.tagslist()):
5367 for t, n in reversed(repo.tagslist()):
5366 hn = hexfunc(n)
5368 hn = hexfunc(n)
5367 label = 'tags.normal'
5369 label = 'tags.normal'
5368 tagtype = ''
5370 tagtype = ''
5369 if repo.tagtype(t) == 'local':
5371 if repo.tagtype(t) == 'local':
5370 label = 'tags.local'
5372 label = 'tags.local'
5371 tagtype = 'local'
5373 tagtype = 'local'
5372
5374
5373 fm.startitem()
5375 fm.startitem()
5374 fm.write('tag', '%s', t, label=label)
5376 fm.write('tag', '%s', t, label=label)
5375 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5377 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5376 fm.condwrite(not ui.quiet, 'rev node', fmt,
5378 fm.condwrite(not ui.quiet, 'rev node', fmt,
5377 repo.changelog.rev(n), hn, label=label)
5379 repo.changelog.rev(n), hn, label=label)
5378 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5380 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5379 tagtype, label=label)
5381 tagtype, label=label)
5380 fm.plain('\n')
5382 fm.plain('\n')
5381 fm.end()
5383 fm.end()
5382
5384
5383 @command('tip',
5385 @command('tip',
5384 [('p', 'patch', None, _('show patch')),
5386 [('p', 'patch', None, _('show patch')),
5385 ('g', 'git', None, _('use git extended diff format')),
5387 ('g', 'git', None, _('use git extended diff format')),
5386 ] + templateopts,
5388 ] + templateopts,
5387 _('[-p] [-g]'))
5389 _('[-p] [-g]'))
5388 def tip(ui, repo, **opts):
5390 def tip(ui, repo, **opts):
5389 """show the tip revision (DEPRECATED)
5391 """show the tip revision (DEPRECATED)
5390
5392
5391 The tip revision (usually just called the tip) is the changeset
5393 The tip revision (usually just called the tip) is the changeset
5392 most recently added to the repository (and therefore the most
5394 most recently added to the repository (and therefore the most
5393 recently changed head).
5395 recently changed head).
5394
5396
5395 If you have just made a commit, that commit will be the tip. If
5397 If you have just made a commit, that commit will be the tip. If
5396 you have just pulled changes from another repository, the tip of
5398 you have just pulled changes from another repository, the tip of
5397 that repository becomes the current tip. The "tip" tag is special
5399 that repository becomes the current tip. The "tip" tag is special
5398 and cannot be renamed or assigned to a different changeset.
5400 and cannot be renamed or assigned to a different changeset.
5399
5401
5400 This command is deprecated, please use :hg:`heads` instead.
5402 This command is deprecated, please use :hg:`heads` instead.
5401
5403
5402 Returns 0 on success.
5404 Returns 0 on success.
5403 """
5405 """
5404 opts = pycompat.byteskwargs(opts)
5406 opts = pycompat.byteskwargs(opts)
5405 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5407 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5406 displayer.show(repo['tip'])
5408 displayer.show(repo['tip'])
5407 displayer.close()
5409 displayer.close()
5408
5410
5409 @command('unbundle',
5411 @command('unbundle',
5410 [('u', 'update', None,
5412 [('u', 'update', None,
5411 _('update to new branch head if changesets were unbundled'))],
5413 _('update to new branch head if changesets were unbundled'))],
5412 _('[-u] FILE...'))
5414 _('[-u] FILE...'))
5413 def unbundle(ui, repo, fname1, *fnames, **opts):
5415 def unbundle(ui, repo, fname1, *fnames, **opts):
5414 """apply one or more bundle files
5416 """apply one or more bundle files
5415
5417
5416 Apply one or more bundle files generated by :hg:`bundle`.
5418 Apply one or more bundle files generated by :hg:`bundle`.
5417
5419
5418 Returns 0 on success, 1 if an update has unresolved files.
5420 Returns 0 on success, 1 if an update has unresolved files.
5419 """
5421 """
5420 fnames = (fname1,) + fnames
5422 fnames = (fname1,) + fnames
5421
5423
5422 with repo.lock():
5424 with repo.lock():
5423 for fname in fnames:
5425 for fname in fnames:
5424 f = hg.openpath(ui, fname)
5426 f = hg.openpath(ui, fname)
5425 gen = exchange.readbundle(ui, f, fname)
5427 gen = exchange.readbundle(ui, f, fname)
5426 if isinstance(gen, streamclone.streamcloneapplier):
5428 if isinstance(gen, streamclone.streamcloneapplier):
5427 raise error.Abort(
5429 raise error.Abort(
5428 _('packed bundles cannot be applied with '
5430 _('packed bundles cannot be applied with '
5429 '"hg unbundle"'),
5431 '"hg unbundle"'),
5430 hint=_('use "hg debugapplystreamclonebundle"'))
5432 hint=_('use "hg debugapplystreamclonebundle"'))
5431 url = 'bundle:' + fname
5433 url = 'bundle:' + fname
5432 try:
5434 try:
5433 txnname = 'unbundle'
5435 txnname = 'unbundle'
5434 if not isinstance(gen, bundle2.unbundle20):
5436 if not isinstance(gen, bundle2.unbundle20):
5435 txnname = 'unbundle\n%s' % util.hidepassword(url)
5437 txnname = 'unbundle\n%s' % util.hidepassword(url)
5436 with repo.transaction(txnname) as tr:
5438 with repo.transaction(txnname) as tr:
5437 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5439 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5438 url=url)
5440 url=url)
5439 except error.BundleUnknownFeatureError as exc:
5441 except error.BundleUnknownFeatureError as exc:
5440 raise error.Abort(
5442 raise error.Abort(
5441 _('%s: unknown bundle feature, %s') % (fname, exc),
5443 _('%s: unknown bundle feature, %s') % (fname, exc),
5442 hint=_("see https://mercurial-scm.org/"
5444 hint=_("see https://mercurial-scm.org/"
5443 "wiki/BundleFeature for more "
5445 "wiki/BundleFeature for more "
5444 "information"))
5446 "information"))
5445 modheads = bundle2.combinechangegroupresults(op)
5447 modheads = bundle2.combinechangegroupresults(op)
5446
5448
5447 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
5449 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
5448
5450
5449 @command('^update|up|checkout|co',
5451 @command('^update|up|checkout|co',
5450 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5452 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5451 ('c', 'check', None, _('require clean working directory')),
5453 ('c', 'check', None, _('require clean working directory')),
5452 ('m', 'merge', None, _('merge uncommitted changes')),
5454 ('m', 'merge', None, _('merge uncommitted changes')),
5453 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5455 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5454 ('r', 'rev', '', _('revision'), _('REV'))
5456 ('r', 'rev', '', _('revision'), _('REV'))
5455 ] + mergetoolopts,
5457 ] + mergetoolopts,
5456 _('[-C|-c|-m] [-d DATE] [[-r] REV]'))
5458 _('[-C|-c|-m] [-d DATE] [[-r] REV]'))
5457 def update(ui, repo, node=None, **opts):
5459 def update(ui, repo, node=None, **opts):
5458 """update working directory (or switch revisions)
5460 """update working directory (or switch revisions)
5459
5461
5460 Update the repository's working directory to the specified
5462 Update the repository's working directory to the specified
5461 changeset. If no changeset is specified, update to the tip of the
5463 changeset. If no changeset is specified, update to the tip of the
5462 current named branch and move the active bookmark (see :hg:`help
5464 current named branch and move the active bookmark (see :hg:`help
5463 bookmarks`).
5465 bookmarks`).
5464
5466
5465 Update sets the working directory's parent revision to the specified
5467 Update sets the working directory's parent revision to the specified
5466 changeset (see :hg:`help parents`).
5468 changeset (see :hg:`help parents`).
5467
5469
5468 If the changeset is not a descendant or ancestor of the working
5470 If the changeset is not a descendant or ancestor of the working
5469 directory's parent and there are uncommitted changes, the update is
5471 directory's parent and there are uncommitted changes, the update is
5470 aborted. With the -c/--check option, the working directory is checked
5472 aborted. With the -c/--check option, the working directory is checked
5471 for uncommitted changes; if none are found, the working directory is
5473 for uncommitted changes; if none are found, the working directory is
5472 updated to the specified changeset.
5474 updated to the specified changeset.
5473
5475
5474 .. container:: verbose
5476 .. container:: verbose
5475
5477
5476 The -C/--clean, -c/--check, and -m/--merge options control what
5478 The -C/--clean, -c/--check, and -m/--merge options control what
5477 happens if the working directory contains uncommitted changes.
5479 happens if the working directory contains uncommitted changes.
5478 At most of one of them can be specified.
5480 At most of one of them can be specified.
5479
5481
5480 1. If no option is specified, and if
5482 1. If no option is specified, and if
5481 the requested changeset is an ancestor or descendant of
5483 the requested changeset is an ancestor or descendant of
5482 the working directory's parent, the uncommitted changes
5484 the working directory's parent, the uncommitted changes
5483 are merged into the requested changeset and the merged
5485 are merged into the requested changeset and the merged
5484 result is left uncommitted. If the requested changeset is
5486 result is left uncommitted. If the requested changeset is
5485 not an ancestor or descendant (that is, it is on another
5487 not an ancestor or descendant (that is, it is on another
5486 branch), the update is aborted and the uncommitted changes
5488 branch), the update is aborted and the uncommitted changes
5487 are preserved.
5489 are preserved.
5488
5490
5489 2. With the -m/--merge option, the update is allowed even if the
5491 2. With the -m/--merge option, the update is allowed even if the
5490 requested changeset is not an ancestor or descendant of
5492 requested changeset is not an ancestor or descendant of
5491 the working directory's parent.
5493 the working directory's parent.
5492
5494
5493 3. With the -c/--check option, the update is aborted and the
5495 3. With the -c/--check option, the update is aborted and the
5494 uncommitted changes are preserved.
5496 uncommitted changes are preserved.
5495
5497
5496 4. With the -C/--clean option, uncommitted changes are discarded and
5498 4. With the -C/--clean option, uncommitted changes are discarded and
5497 the working directory is updated to the requested changeset.
5499 the working directory is updated to the requested changeset.
5498
5500
5499 To cancel an uncommitted merge (and lose your changes), use
5501 To cancel an uncommitted merge (and lose your changes), use
5500 :hg:`merge --abort`.
5502 :hg:`merge --abort`.
5501
5503
5502 Use null as the changeset to remove the working directory (like
5504 Use null as the changeset to remove the working directory (like
5503 :hg:`clone -U`).
5505 :hg:`clone -U`).
5504
5506
5505 If you want to revert just one file to an older revision, use
5507 If you want to revert just one file to an older revision, use
5506 :hg:`revert [-r REV] NAME`.
5508 :hg:`revert [-r REV] NAME`.
5507
5509
5508 See :hg:`help dates` for a list of formats valid for -d/--date.
5510 See :hg:`help dates` for a list of formats valid for -d/--date.
5509
5511
5510 Returns 0 on success, 1 if there are unresolved files.
5512 Returns 0 on success, 1 if there are unresolved files.
5511 """
5513 """
5512 rev = opts.get(r'rev')
5514 rev = opts.get(r'rev')
5513 date = opts.get(r'date')
5515 date = opts.get(r'date')
5514 clean = opts.get(r'clean')
5516 clean = opts.get(r'clean')
5515 check = opts.get(r'check')
5517 check = opts.get(r'check')
5516 merge = opts.get(r'merge')
5518 merge = opts.get(r'merge')
5517 if rev and node:
5519 if rev and node:
5518 raise error.Abort(_("please specify just one revision"))
5520 raise error.Abort(_("please specify just one revision"))
5519
5521
5520 if ui.configbool('commands', 'update.requiredest'):
5522 if ui.configbool('commands', 'update.requiredest'):
5521 if not node and not rev and not date:
5523 if not node and not rev and not date:
5522 raise error.Abort(_('you must specify a destination'),
5524 raise error.Abort(_('you must specify a destination'),
5523 hint=_('for example: hg update ".::"'))
5525 hint=_('for example: hg update ".::"'))
5524
5526
5525 if rev is None or rev == '':
5527 if rev is None or rev == '':
5526 rev = node
5528 rev = node
5527
5529
5528 if date and rev is not None:
5530 if date and rev is not None:
5529 raise error.Abort(_("you can't specify a revision and a date"))
5531 raise error.Abort(_("you can't specify a revision and a date"))
5530
5532
5531 if len([x for x in (clean, check, merge) if x]) > 1:
5533 if len([x for x in (clean, check, merge) if x]) > 1:
5532 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
5534 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
5533 "or -m/--merge"))
5535 "or -m/--merge"))
5534
5536
5535 updatecheck = None
5537 updatecheck = None
5536 if check:
5538 if check:
5537 updatecheck = 'abort'
5539 updatecheck = 'abort'
5538 elif merge:
5540 elif merge:
5539 updatecheck = 'none'
5541 updatecheck = 'none'
5540
5542
5541 with repo.wlock():
5543 with repo.wlock():
5542 cmdutil.clearunfinished(repo)
5544 cmdutil.clearunfinished(repo)
5543
5545
5544 if date:
5546 if date:
5545 rev = cmdutil.finddate(ui, repo, date)
5547 rev = cmdutil.finddate(ui, repo, date)
5546
5548
5547 # if we defined a bookmark, we have to remember the original name
5549 # if we defined a bookmark, we have to remember the original name
5548 brev = rev
5550 brev = rev
5549 if rev:
5551 if rev:
5550 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
5552 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
5551 ctx = scmutil.revsingle(repo, rev, rev)
5553 ctx = scmutil.revsingle(repo, rev, rev)
5552 rev = ctx.rev()
5554 rev = ctx.rev()
5553 if ctx.hidden():
5555 if ctx.hidden():
5554 ctxstr = ctx.hex()[:12]
5556 ctxstr = ctx.hex()[:12]
5555 ui.warn(_("updating to a hidden changeset %s\n") % ctxstr)
5557 ui.warn(_("updating to a hidden changeset %s\n") % ctxstr)
5556
5558
5557 if ctx.obsolete():
5559 if ctx.obsolete():
5558 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
5560 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
5559 ui.warn("(%s)\n" % obsfatemsg)
5561 ui.warn("(%s)\n" % obsfatemsg)
5560
5562
5561 repo.ui.setconfig('ui', 'forcemerge', opts.get(r'tool'), 'update')
5563 repo.ui.setconfig('ui', 'forcemerge', opts.get(r'tool'), 'update')
5562
5564
5563 return hg.updatetotally(ui, repo, rev, brev, clean=clean,
5565 return hg.updatetotally(ui, repo, rev, brev, clean=clean,
5564 updatecheck=updatecheck)
5566 updatecheck=updatecheck)
5565
5567
5566 @command('verify', [])
5568 @command('verify', [])
5567 def verify(ui, repo):
5569 def verify(ui, repo):
5568 """verify the integrity of the repository
5570 """verify the integrity of the repository
5569
5571
5570 Verify the integrity of the current repository.
5572 Verify the integrity of the current repository.
5571
5573
5572 This will perform an extensive check of the repository's
5574 This will perform an extensive check of the repository's
5573 integrity, validating the hashes and checksums of each entry in
5575 integrity, validating the hashes and checksums of each entry in
5574 the changelog, manifest, and tracked files, as well as the
5576 the changelog, manifest, and tracked files, as well as the
5575 integrity of their crosslinks and indices.
5577 integrity of their crosslinks and indices.
5576
5578
5577 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
5579 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
5578 for more information about recovery from corruption of the
5580 for more information about recovery from corruption of the
5579 repository.
5581 repository.
5580
5582
5581 Returns 0 on success, 1 if errors are encountered.
5583 Returns 0 on success, 1 if errors are encountered.
5582 """
5584 """
5583 return hg.verify(repo)
5585 return hg.verify(repo)
5584
5586
5585 @command('version', [] + formatteropts, norepo=True, cmdtype=readonly)
5587 @command('version', [] + formatteropts, norepo=True, cmdtype=readonly)
5586 def version_(ui, **opts):
5588 def version_(ui, **opts):
5587 """output version and copyright information"""
5589 """output version and copyright information"""
5588 opts = pycompat.byteskwargs(opts)
5590 opts = pycompat.byteskwargs(opts)
5589 if ui.verbose:
5591 if ui.verbose:
5590 ui.pager('version')
5592 ui.pager('version')
5591 fm = ui.formatter("version", opts)
5593 fm = ui.formatter("version", opts)
5592 fm.startitem()
5594 fm.startitem()
5593 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
5595 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
5594 util.version())
5596 util.version())
5595 license = _(
5597 license = _(
5596 "(see https://mercurial-scm.org for more information)\n"
5598 "(see https://mercurial-scm.org for more information)\n"
5597 "\nCopyright (C) 2005-2018 Matt Mackall and others\n"
5599 "\nCopyright (C) 2005-2018 Matt Mackall and others\n"
5598 "This is free software; see the source for copying conditions. "
5600 "This is free software; see the source for copying conditions. "
5599 "There is NO\nwarranty; "
5601 "There is NO\nwarranty; "
5600 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5602 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5601 )
5603 )
5602 if not ui.quiet:
5604 if not ui.quiet:
5603 fm.plain(license)
5605 fm.plain(license)
5604
5606
5605 if ui.verbose:
5607 if ui.verbose:
5606 fm.plain(_("\nEnabled extensions:\n\n"))
5608 fm.plain(_("\nEnabled extensions:\n\n"))
5607 # format names and versions into columns
5609 # format names and versions into columns
5608 names = []
5610 names = []
5609 vers = []
5611 vers = []
5610 isinternals = []
5612 isinternals = []
5611 for name, module in extensions.extensions():
5613 for name, module in extensions.extensions():
5612 names.append(name)
5614 names.append(name)
5613 vers.append(extensions.moduleversion(module) or None)
5615 vers.append(extensions.moduleversion(module) or None)
5614 isinternals.append(extensions.ismoduleinternal(module))
5616 isinternals.append(extensions.ismoduleinternal(module))
5615 fn = fm.nested("extensions")
5617 fn = fm.nested("extensions")
5616 if names:
5618 if names:
5617 namefmt = " %%-%ds " % max(len(n) for n in names)
5619 namefmt = " %%-%ds " % max(len(n) for n in names)
5618 places = [_("external"), _("internal")]
5620 places = [_("external"), _("internal")]
5619 for n, v, p in zip(names, vers, isinternals):
5621 for n, v, p in zip(names, vers, isinternals):
5620 fn.startitem()
5622 fn.startitem()
5621 fn.condwrite(ui.verbose, "name", namefmt, n)
5623 fn.condwrite(ui.verbose, "name", namefmt, n)
5622 if ui.verbose:
5624 if ui.verbose:
5623 fn.plain("%s " % places[p])
5625 fn.plain("%s " % places[p])
5624 fn.data(bundled=p)
5626 fn.data(bundled=p)
5625 fn.condwrite(ui.verbose and v, "ver", "%s", v)
5627 fn.condwrite(ui.verbose and v, "ver", "%s", v)
5626 if ui.verbose:
5628 if ui.verbose:
5627 fn.plain("\n")
5629 fn.plain("\n")
5628 fn.end()
5630 fn.end()
5629 fm.end()
5631 fm.end()
5630
5632
5631 def loadcmdtable(ui, name, cmdtable):
5633 def loadcmdtable(ui, name, cmdtable):
5632 """Load command functions from specified cmdtable
5634 """Load command functions from specified cmdtable
5633 """
5635 """
5634 overrides = [cmd for cmd in cmdtable if cmd in table]
5636 overrides = [cmd for cmd in cmdtable if cmd in table]
5635 if overrides:
5637 if overrides:
5636 ui.warn(_("extension '%s' overrides commands: %s\n")
5638 ui.warn(_("extension '%s' overrides commands: %s\n")
5637 % (name, " ".join(overrides)))
5639 % (name, " ".join(overrides)))
5638 table.update(cmdtable)
5640 table.update(cmdtable)
@@ -1,1171 +1,1171 b''
1 #require git
1 #require git
2
2
3 $ echo "[core]" >> $HOME/.gitconfig
3 $ echo "[core]" >> $HOME/.gitconfig
4 $ echo "autocrlf = false" >> $HOME/.gitconfig
4 $ echo "autocrlf = false" >> $HOME/.gitconfig
5 $ echo "[core]" >> $HOME/.gitconfig
5 $ echo "[core]" >> $HOME/.gitconfig
6 $ echo "autocrlf = false" >> $HOME/.gitconfig
6 $ echo "autocrlf = false" >> $HOME/.gitconfig
7 $ echo "[extensions]" >> $HGRCPATH
7 $ echo "[extensions]" >> $HGRCPATH
8 $ echo "convert=" >> $HGRCPATH
8 $ echo "convert=" >> $HGRCPATH
9 $ cat >> $HGRCPATH <<EOF
9 $ cat >> $HGRCPATH <<EOF
10 > [subrepos]
10 > [subrepos]
11 > git:allowed = true
11 > git:allowed = true
12 > EOF
12 > EOF
13 $ GIT_AUTHOR_NAME='test'; export GIT_AUTHOR_NAME
13 $ GIT_AUTHOR_NAME='test'; export GIT_AUTHOR_NAME
14 $ GIT_AUTHOR_EMAIL='test@example.org'; export GIT_AUTHOR_EMAIL
14 $ GIT_AUTHOR_EMAIL='test@example.org'; export GIT_AUTHOR_EMAIL
15 $ GIT_AUTHOR_DATE="2007-01-01 00:00:00 +0000"; export GIT_AUTHOR_DATE
15 $ GIT_AUTHOR_DATE="2007-01-01 00:00:00 +0000"; export GIT_AUTHOR_DATE
16 $ GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME"; export GIT_COMMITTER_NAME
16 $ GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME"; export GIT_COMMITTER_NAME
17 $ GIT_COMMITTER_EMAIL="$GIT_AUTHOR_EMAIL"; export GIT_COMMITTER_EMAIL
17 $ GIT_COMMITTER_EMAIL="$GIT_AUTHOR_EMAIL"; export GIT_COMMITTER_EMAIL
18 $ GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"; export GIT_COMMITTER_DATE
18 $ GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"; export GIT_COMMITTER_DATE
19 $ INVALIDID1=afd12345af
19 $ INVALIDID1=afd12345af
20 $ INVALIDID2=28173x36ddd1e67bf7098d541130558ef5534a86
20 $ INVALIDID2=28173x36ddd1e67bf7098d541130558ef5534a86
21 $ VALIDID1=39b3d83f9a69a9ba4ebb111461071a0af0027357
21 $ VALIDID1=39b3d83f9a69a9ba4ebb111461071a0af0027357
22 $ VALIDID2=8dd6476bd09d9c7776355dc454dafe38efaec5da
22 $ VALIDID2=8dd6476bd09d9c7776355dc454dafe38efaec5da
23 $ count=10
23 $ count=10
24 $ commit()
24 $ commit()
25 > {
25 > {
26 > GIT_AUTHOR_DATE="2007-01-01 00:00:$count +0000"
26 > GIT_AUTHOR_DATE="2007-01-01 00:00:$count +0000"
27 > GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"
27 > GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"
28 > git commit "$@" >/dev/null 2>/dev/null || echo "git commit error"
28 > git commit "$@" >/dev/null 2>/dev/null || echo "git commit error"
29 > count=`expr $count + 1`
29 > count=`expr $count + 1`
30 > }
30 > }
31 $ mkdir git-repo
31 $ mkdir git-repo
32 $ cd git-repo
32 $ cd git-repo
33 $ git init-db >/dev/null 2>/dev/null
33 $ git init-db >/dev/null 2>/dev/null
34 $ echo a > a
34 $ echo a > a
35 $ mkdir d
35 $ mkdir d
36 $ echo b > d/b
36 $ echo b > d/b
37 $ git add a d
37 $ git add a d
38 $ commit -a -m t1
38 $ commit -a -m t1
39
39
40 Remove the directory, then try to replace it with a file (issue754)
40 Remove the directory, then try to replace it with a file (issue754)
41
41
42 $ git rm -f d/b
42 $ git rm -f d/b
43 rm 'd/b'
43 rm 'd/b'
44 $ commit -m t2
44 $ commit -m t2
45 $ echo d > d
45 $ echo d > d
46 $ git add d
46 $ git add d
47 $ commit -m t3
47 $ commit -m t3
48 $ echo b >> a
48 $ echo b >> a
49 $ commit -a -m t4.1
49 $ commit -a -m t4.1
50 $ git checkout -b other HEAD~ >/dev/null 2>/dev/null
50 $ git checkout -b other HEAD~ >/dev/null 2>/dev/null
51 $ echo c > a
51 $ echo c > a
52 $ echo a >> a
52 $ echo a >> a
53 $ commit -a -m t4.2
53 $ commit -a -m t4.2
54 $ git checkout master >/dev/null 2>/dev/null
54 $ git checkout master >/dev/null 2>/dev/null
55 $ git pull --no-commit . other > /dev/null 2>/dev/null
55 $ git pull --no-commit . other > /dev/null 2>/dev/null
56 $ commit -m 'Merge branch other'
56 $ commit -m 'Merge branch other'
57 $ cd ..
57 $ cd ..
58 $ hg convert --config extensions.progress= --config progress.assume-tty=1 \
58 $ hg convert --config extensions.progress= --config progress.assume-tty=1 \
59 > --config progress.delay=0 --config progress.changedelay=0 \
59 > --config progress.delay=0 --config progress.changedelay=0 \
60 > --config progress.refresh=0 --config progress.width=60 \
60 > --config progress.refresh=0 --config progress.width=60 \
61 > --config progress.format='topic, bar, number' --datesort git-repo
61 > --config progress.format='topic, bar, number' --datesort git-repo
62 \r (no-eol) (esc)
62 \r (no-eol) (esc)
63 scanning [======> ] 1/6\r (no-eol) (esc)
63 scanning [======> ] 1/6\r (no-eol) (esc)
64 scanning [=============> ] 2/6\r (no-eol) (esc)
64 scanning [=============> ] 2/6\r (no-eol) (esc)
65 scanning [=====================> ] 3/6\r (no-eol) (esc)
65 scanning [=====================> ] 3/6\r (no-eol) (esc)
66 scanning [============================> ] 4/6\r (no-eol) (esc)
66 scanning [============================> ] 4/6\r (no-eol) (esc)
67 scanning [===================================> ] 5/6\r (no-eol) (esc)
67 scanning [===================================> ] 5/6\r (no-eol) (esc)
68 scanning [===========================================>] 6/6\r (no-eol) (esc)
68 scanning [===========================================>] 6/6\r (no-eol) (esc)
69 \r (no-eol) (esc)
69 \r (no-eol) (esc)
70 \r (no-eol) (esc)
70 \r (no-eol) (esc)
71 converting [ ] 0/6\r (no-eol) (esc)
71 converting [ ] 0/6\r (no-eol) (esc)
72 getting files [==================> ] 1/2\r (no-eol) (esc)
72 getting files [==================> ] 1/2\r (no-eol) (esc)
73 getting files [======================================>] 2/2\r (no-eol) (esc)
73 getting files [======================================>] 2/2\r (no-eol) (esc)
74 \r (no-eol) (esc)
74 \r (no-eol) (esc)
75 \r (no-eol) (esc)
75 \r (no-eol) (esc)
76 converting [======> ] 1/6\r (no-eol) (esc)
76 converting [======> ] 1/6\r (no-eol) (esc)
77 getting files [======================================>] 1/1\r (no-eol) (esc)
77 getting files [======================================>] 1/1\r (no-eol) (esc)
78 \r (no-eol) (esc)
78 \r (no-eol) (esc)
79 \r (no-eol) (esc)
79 \r (no-eol) (esc)
80 converting [=============> ] 2/6\r (no-eol) (esc)
80 converting [=============> ] 2/6\r (no-eol) (esc)
81 getting files [======================================>] 1/1\r (no-eol) (esc)
81 getting files [======================================>] 1/1\r (no-eol) (esc)
82 \r (no-eol) (esc)
82 \r (no-eol) (esc)
83 \r (no-eol) (esc)
83 \r (no-eol) (esc)
84 converting [====================> ] 3/6\r (no-eol) (esc)
84 converting [====================> ] 3/6\r (no-eol) (esc)
85 getting files [======================================>] 1/1\r (no-eol) (esc)
85 getting files [======================================>] 1/1\r (no-eol) (esc)
86 \r (no-eol) (esc)
86 \r (no-eol) (esc)
87 \r (no-eol) (esc)
87 \r (no-eol) (esc)
88 converting [===========================> ] 4/6\r (no-eol) (esc)
88 converting [===========================> ] 4/6\r (no-eol) (esc)
89 getting files [======================================>] 1/1\r (no-eol) (esc)
89 getting files [======================================>] 1/1\r (no-eol) (esc)
90 \r (no-eol) (esc)
90 \r (no-eol) (esc)
91 \r (no-eol) (esc)
91 \r (no-eol) (esc)
92 converting [==================================> ] 5/6\r (no-eol) (esc)
92 converting [==================================> ] 5/6\r (no-eol) (esc)
93 getting files [======================================>] 1/1\r (no-eol) (esc)
93 getting files [======================================>] 1/1\r (no-eol) (esc)
94 \r (no-eol) (esc)
94 \r (no-eol) (esc)
95 assuming destination git-repo-hg
95 assuming destination git-repo-hg
96 initializing destination git-repo-hg repository
96 initializing destination git-repo-hg repository
97 scanning source...
97 scanning source...
98 sorting...
98 sorting...
99 converting...
99 converting...
100 5 t1
100 5 t1
101 4 t2
101 4 t2
102 3 t3
102 3 t3
103 2 t4.1
103 2 t4.1
104 1 t4.2
104 1 t4.2
105 0 Merge branch other
105 0 Merge branch other
106 updating bookmarks
106 updating bookmarks
107 $ hg up -q -R git-repo-hg
107 $ hg up -q -R git-repo-hg
108 $ hg -R git-repo-hg tip -v
108 $ hg -R git-repo-hg tip -v
109 changeset: 5:c78094926be2
109 changeset: 5:c78094926be2
110 bookmark: master
110 bookmark: master
111 tag: tip
111 tag: tip
112 parent: 3:f5f5cb45432b
112 parent: 3:f5f5cb45432b
113 parent: 4:4e174f80c67c
113 parent: 4:4e174f80c67c
114 user: test <test@example.org>
114 user: test <test@example.org>
115 date: Mon Jan 01 00:00:15 2007 +0000
115 date: Mon Jan 01 00:00:15 2007 +0000
116 files: a
116 files: a
117 description:
117 description:
118 Merge branch other
118 Merge branch other
119
119
120
120
121 $ count=10
121 $ count=10
122 $ mkdir git-repo2
122 $ mkdir git-repo2
123 $ cd git-repo2
123 $ cd git-repo2
124 $ git init-db >/dev/null 2>/dev/null
124 $ git init-db >/dev/null 2>/dev/null
125 $ echo foo > foo
125 $ echo foo > foo
126 $ git add foo
126 $ git add foo
127 $ commit -a -m 'add foo'
127 $ commit -a -m 'add foo'
128 $ echo >> foo
128 $ echo >> foo
129 $ commit -a -m 'change foo'
129 $ commit -a -m 'change foo'
130 $ git checkout -b Bar HEAD~ >/dev/null 2>/dev/null
130 $ git checkout -b Bar HEAD~ >/dev/null 2>/dev/null
131 $ echo quux >> quux
131 $ echo quux >> quux
132 $ git add quux
132 $ git add quux
133 $ commit -a -m 'add quux'
133 $ commit -a -m 'add quux'
134 $ echo bar > bar
134 $ echo bar > bar
135 $ git add bar
135 $ git add bar
136 $ commit -a -m 'add bar'
136 $ commit -a -m 'add bar'
137 $ git checkout -b Baz HEAD~ >/dev/null 2>/dev/null
137 $ git checkout -b Baz HEAD~ >/dev/null 2>/dev/null
138 $ echo baz > baz
138 $ echo baz > baz
139 $ git add baz
139 $ git add baz
140 $ commit -a -m 'add baz'
140 $ commit -a -m 'add baz'
141 $ git checkout master >/dev/null 2>/dev/null
141 $ git checkout master >/dev/null 2>/dev/null
142 $ git pull --no-commit . Bar Baz > /dev/null 2>/dev/null
142 $ git pull --no-commit . Bar Baz > /dev/null 2>/dev/null
143 $ commit -m 'Octopus merge'
143 $ commit -m 'Octopus merge'
144 $ echo bar >> bar
144 $ echo bar >> bar
145 $ commit -a -m 'change bar'
145 $ commit -a -m 'change bar'
146 $ git checkout -b Foo HEAD~ >/dev/null 2>/dev/null
146 $ git checkout -b Foo HEAD~ >/dev/null 2>/dev/null
147 $ echo >> foo
147 $ echo >> foo
148 $ commit -a -m 'change foo'
148 $ commit -a -m 'change foo'
149 $ git checkout master >/dev/null 2>/dev/null
149 $ git checkout master >/dev/null 2>/dev/null
150 $ git pull --no-commit -s ours . Foo > /dev/null 2>/dev/null
150 $ git pull --no-commit -s ours . Foo > /dev/null 2>/dev/null
151 $ commit -m 'Discard change to foo'
151 $ commit -m 'Discard change to foo'
152 $ cd ..
152 $ cd ..
153 $ glog()
153 $ glog()
154 > {
154 > {
155 > hg log -G --template '{rev} "{desc|firstline}" files: {files}\n' "$@"
155 > hg log -G --template '{rev} "{desc|firstline}" files: {files}\n' "$@"
156 > }
156 > }
157 $ splitrepo()
157 $ splitrepo()
158 > {
158 > {
159 > msg="$1"
159 > msg="$1"
160 > files="$2"
160 > files="$2"
161 > opts=$3
161 > opts=$3
162 > echo "% $files: $msg"
162 > echo "% $files: $msg"
163 > prefix=`echo "$files" | sed -e 's/ /-/g'`
163 > prefix=`echo "$files" | sed -e 's/ /-/g'`
164 > fmap="$prefix.fmap"
164 > fmap="$prefix.fmap"
165 > repo="$prefix.repo"
165 > repo="$prefix.repo"
166 > for i in $files; do
166 > for i in $files; do
167 > echo "include $i" >> "$fmap"
167 > echo "include $i" >> "$fmap"
168 > done
168 > done
169 > hg -q convert $opts --filemap "$fmap" --datesort git-repo2 "$repo"
169 > hg -q convert $opts --filemap "$fmap" --datesort git-repo2 "$repo"
170 > hg up -q -R "$repo"
170 > hg up -q -R "$repo"
171 > glog -R "$repo"
171 > glog -R "$repo"
172 > hg -R "$repo" manifest --debug
172 > hg -R "$repo" manifest --debug
173 > }
173 > }
174
174
175 full conversion
175 full conversion
176
176
177 $ hg convert --datesort git-repo2 fullrepo \
177 $ hg convert --datesort git-repo2 fullrepo \
178 > --config extensions.progress= --config progress.assume-tty=1 \
178 > --config extensions.progress= --config progress.assume-tty=1 \
179 > --config progress.delay=0 --config progress.changedelay=0 \
179 > --config progress.delay=0 --config progress.changedelay=0 \
180 > --config progress.refresh=0 --config progress.width=60 \
180 > --config progress.refresh=0 --config progress.width=60 \
181 > --config progress.format='topic, bar, number'
181 > --config progress.format='topic, bar, number'
182 \r (no-eol) (esc)
182 \r (no-eol) (esc)
183 scanning [===> ] 1/9\r (no-eol) (esc)
183 scanning [===> ] 1/9\r (no-eol) (esc)
184 scanning [========> ] 2/9\r (no-eol) (esc)
184 scanning [========> ] 2/9\r (no-eol) (esc)
185 scanning [=============> ] 3/9\r (no-eol) (esc)
185 scanning [=============> ] 3/9\r (no-eol) (esc)
186 scanning [==================> ] 4/9\r (no-eol) (esc)
186 scanning [==================> ] 4/9\r (no-eol) (esc)
187 scanning [=======================> ] 5/9\r (no-eol) (esc)
187 scanning [=======================> ] 5/9\r (no-eol) (esc)
188 scanning [============================> ] 6/9\r (no-eol) (esc)
188 scanning [============================> ] 6/9\r (no-eol) (esc)
189 scanning [=================================> ] 7/9\r (no-eol) (esc)
189 scanning [=================================> ] 7/9\r (no-eol) (esc)
190 scanning [======================================> ] 8/9\r (no-eol) (esc)
190 scanning [======================================> ] 8/9\r (no-eol) (esc)
191 scanning [===========================================>] 9/9\r (no-eol) (esc)
191 scanning [===========================================>] 9/9\r (no-eol) (esc)
192 \r (no-eol) (esc)
192 \r (no-eol) (esc)
193 \r (no-eol) (esc)
193 \r (no-eol) (esc)
194 converting [ ] 0/9\r (no-eol) (esc)
194 converting [ ] 0/9\r (no-eol) (esc)
195 getting files [======================================>] 1/1\r (no-eol) (esc)
195 getting files [======================================>] 1/1\r (no-eol) (esc)
196 \r (no-eol) (esc)
196 \r (no-eol) (esc)
197 \r (no-eol) (esc)
197 \r (no-eol) (esc)
198 converting [===> ] 1/9\r (no-eol) (esc)
198 converting [===> ] 1/9\r (no-eol) (esc)
199 getting files [======================================>] 1/1\r (no-eol) (esc)
199 getting files [======================================>] 1/1\r (no-eol) (esc)
200 \r (no-eol) (esc)
200 \r (no-eol) (esc)
201 \r (no-eol) (esc)
201 \r (no-eol) (esc)
202 converting [========> ] 2/9\r (no-eol) (esc)
202 converting [========> ] 2/9\r (no-eol) (esc)
203 getting files [======================================>] 1/1\r (no-eol) (esc)
203 getting files [======================================>] 1/1\r (no-eol) (esc)
204 \r (no-eol) (esc)
204 \r (no-eol) (esc)
205 \r (no-eol) (esc)
205 \r (no-eol) (esc)
206 converting [=============> ] 3/9\r (no-eol) (esc)
206 converting [=============> ] 3/9\r (no-eol) (esc)
207 getting files [======================================>] 1/1\r (no-eol) (esc)
207 getting files [======================================>] 1/1\r (no-eol) (esc)
208 \r (no-eol) (esc)
208 \r (no-eol) (esc)
209 \r (no-eol) (esc)
209 \r (no-eol) (esc)
210 converting [=================> ] 4/9\r (no-eol) (esc)
210 converting [=================> ] 4/9\r (no-eol) (esc)
211 getting files [======================================>] 1/1\r (no-eol) (esc)
211 getting files [======================================>] 1/1\r (no-eol) (esc)
212 \r (no-eol) (esc)
212 \r (no-eol) (esc)
213 \r (no-eol) (esc)
213 \r (no-eol) (esc)
214 converting [======================> ] 5/9\r (no-eol) (esc)
214 converting [======================> ] 5/9\r (no-eol) (esc)
215 getting files [===> ] 1/8\r (no-eol) (esc)
215 getting files [===> ] 1/8\r (no-eol) (esc)
216 getting files [========> ] 2/8\r (no-eol) (esc)
216 getting files [========> ] 2/8\r (no-eol) (esc)
217 getting files [=============> ] 3/8\r (no-eol) (esc)
217 getting files [=============> ] 3/8\r (no-eol) (esc)
218 getting files [==================> ] 4/8\r (no-eol) (esc)
218 getting files [==================> ] 4/8\r (no-eol) (esc)
219 getting files [=======================> ] 5/8\r (no-eol) (esc)
219 getting files [=======================> ] 5/8\r (no-eol) (esc)
220 getting files [============================> ] 6/8\r (no-eol) (esc)
220 getting files [============================> ] 6/8\r (no-eol) (esc)
221 getting files [=================================> ] 7/8\r (no-eol) (esc)
221 getting files [=================================> ] 7/8\r (no-eol) (esc)
222 getting files [======================================>] 8/8\r (no-eol) (esc)
222 getting files [======================================>] 8/8\r (no-eol) (esc)
223 \r (no-eol) (esc)
223 \r (no-eol) (esc)
224 \r (no-eol) (esc)
224 \r (no-eol) (esc)
225 converting [===========================> ] 6/9\r (no-eol) (esc)
225 converting [===========================> ] 6/9\r (no-eol) (esc)
226 getting files [======================================>] 1/1\r (no-eol) (esc)
226 getting files [======================================>] 1/1\r (no-eol) (esc)
227 \r (no-eol) (esc)
227 \r (no-eol) (esc)
228 \r (no-eol) (esc)
228 \r (no-eol) (esc)
229 converting [===============================> ] 7/9\r (no-eol) (esc)
229 converting [===============================> ] 7/9\r (no-eol) (esc)
230 getting files [======================================>] 1/1\r (no-eol) (esc)
230 getting files [======================================>] 1/1\r (no-eol) (esc)
231 \r (no-eol) (esc)
231 \r (no-eol) (esc)
232 \r (no-eol) (esc)
232 \r (no-eol) (esc)
233 converting [====================================> ] 8/9\r (no-eol) (esc)
233 converting [====================================> ] 8/9\r (no-eol) (esc)
234 getting files [==================> ] 1/2\r (no-eol) (esc)
234 getting files [==================> ] 1/2\r (no-eol) (esc)
235 getting files [======================================>] 2/2\r (no-eol) (esc)
235 getting files [======================================>] 2/2\r (no-eol) (esc)
236 \r (no-eol) (esc)
236 \r (no-eol) (esc)
237 initializing destination fullrepo repository
237 initializing destination fullrepo repository
238 scanning source...
238 scanning source...
239 sorting...
239 sorting...
240 converting...
240 converting...
241 8 add foo
241 8 add foo
242 7 change foo
242 7 change foo
243 6 add quux
243 6 add quux
244 5 add bar
244 5 add bar
245 4 add baz
245 4 add baz
246 3 Octopus merge
246 3 Octopus merge
247 2 change bar
247 2 change bar
248 1 change foo
248 1 change foo
249 0 Discard change to foo
249 0 Discard change to foo
250 updating bookmarks
250 updating bookmarks
251 $ hg up -q -R fullrepo
251 $ hg up -q -R fullrepo
252 $ glog -R fullrepo
252 $ glog -R fullrepo
253 @ 9 "Discard change to foo" files: foo
253 @ 9 "Discard change to foo" files: foo
254 |\
254 |\
255 | o 8 "change foo" files: foo
255 | o 8 "change foo" files: foo
256 | |
256 | |
257 o | 7 "change bar" files: bar
257 o | 7 "change bar" files: bar
258 |/
258 |/
259 o 6 "(octopus merge fixup)" files:
259 o 6 "(octopus merge fixup)" files:
260 |\
260 |\
261 | o 5 "Octopus merge" files: baz
261 | o 5 "Octopus merge" files: baz
262 | |\
262 | |\
263 o | | 4 "add baz" files: baz
263 o | | 4 "add baz" files: baz
264 | | |
264 | | |
265 +---o 3 "add bar" files: bar
265 +---o 3 "add bar" files: bar
266 | |
266 | |
267 o | 2 "add quux" files: quux
267 o | 2 "add quux" files: quux
268 | |
268 | |
269 | o 1 "change foo" files: foo
269 | o 1 "change foo" files: foo
270 |/
270 |/
271 o 0 "add foo" files: foo
271 o 0 "add foo" files: foo
272
272
273 $ hg -R fullrepo manifest --debug
273 $ hg -R fullrepo manifest --debug
274 245a3b8bc653999c2b22cdabd517ccb47aecafdf 644 bar
274 245a3b8bc653999c2b22cdabd517ccb47aecafdf 644 bar
275 354ae8da6e890359ef49ade27b68bbc361f3ca88 644 baz
275 354ae8da6e890359ef49ade27b68bbc361f3ca88 644 baz
276 9277c9cc8dd4576fc01a17939b4351e5ada93466 644 foo
276 9277c9cc8dd4576fc01a17939b4351e5ada93466 644 foo
277 88dfeab657e8cf2cef3dec67b914f49791ae76b1 644 quux
277 88dfeab657e8cf2cef3dec67b914f49791ae76b1 644 quux
278 $ splitrepo 'octopus merge' 'foo bar baz'
278 $ splitrepo 'octopus merge' 'foo bar baz'
279 % foo bar baz: octopus merge
279 % foo bar baz: octopus merge
280 @ 8 "Discard change to foo" files: foo
280 @ 8 "Discard change to foo" files: foo
281 |\
281 |\
282 | o 7 "change foo" files: foo
282 | o 7 "change foo" files: foo
283 | |
283 | |
284 o | 6 "change bar" files: bar
284 o | 6 "change bar" files: bar
285 |/
285 |/
286 o 5 "(octopus merge fixup)" files:
286 o 5 "(octopus merge fixup)" files:
287 |\
287 |\
288 | o 4 "Octopus merge" files: baz
288 | o 4 "Octopus merge" files: baz
289 | |\
289 | |\
290 o | | 3 "add baz" files: baz
290 o | | 3 "add baz" files: baz
291 | | |
291 | | |
292 +---o 2 "add bar" files: bar
292 +---o 2 "add bar" files: bar
293 | |
293 | |
294 | o 1 "change foo" files: foo
294 | o 1 "change foo" files: foo
295 |/
295 |/
296 o 0 "add foo" files: foo
296 o 0 "add foo" files: foo
297
297
298 245a3b8bc653999c2b22cdabd517ccb47aecafdf 644 bar
298 245a3b8bc653999c2b22cdabd517ccb47aecafdf 644 bar
299 354ae8da6e890359ef49ade27b68bbc361f3ca88 644 baz
299 354ae8da6e890359ef49ade27b68bbc361f3ca88 644 baz
300 9277c9cc8dd4576fc01a17939b4351e5ada93466 644 foo
300 9277c9cc8dd4576fc01a17939b4351e5ada93466 644 foo
301 $ splitrepo 'only some parents of an octopus merge; "discard" a head' 'foo baz quux'
301 $ splitrepo 'only some parents of an octopus merge; "discard" a head' 'foo baz quux'
302 % foo baz quux: only some parents of an octopus merge; "discard" a head
302 % foo baz quux: only some parents of an octopus merge; "discard" a head
303 @ 6 "Discard change to foo" files: foo
303 @ 6 "Discard change to foo" files: foo
304 |
304 |
305 o 5 "change foo" files: foo
305 o 5 "change foo" files: foo
306 |
306 |
307 o 4 "Octopus merge" files:
307 o 4 "Octopus merge" files:
308 |\
308 |\
309 | o 3 "add baz" files: baz
309 | o 3 "add baz" files: baz
310 | |
310 | |
311 | o 2 "add quux" files: quux
311 | o 2 "add quux" files: quux
312 | |
312 | |
313 o | 1 "change foo" files: foo
313 o | 1 "change foo" files: foo
314 |/
314 |/
315 o 0 "add foo" files: foo
315 o 0 "add foo" files: foo
316
316
317 354ae8da6e890359ef49ade27b68bbc361f3ca88 644 baz
317 354ae8da6e890359ef49ade27b68bbc361f3ca88 644 baz
318 9277c9cc8dd4576fc01a17939b4351e5ada93466 644 foo
318 9277c9cc8dd4576fc01a17939b4351e5ada93466 644 foo
319 88dfeab657e8cf2cef3dec67b914f49791ae76b1 644 quux
319 88dfeab657e8cf2cef3dec67b914f49791ae76b1 644 quux
320
320
321 test importing git renames and copies
321 test importing git renames and copies
322
322
323 $ cd git-repo2
323 $ cd git-repo2
324 $ git mv foo foo-renamed
324 $ git mv foo foo-renamed
325 since bar is not touched in this commit, this copy will not be detected
325 since bar is not touched in this commit, this copy will not be detected
326 $ cp bar bar-copied
326 $ cp bar bar-copied
327 $ cp baz baz-copied
327 $ cp baz baz-copied
328 $ cp baz baz-copied2
328 $ cp baz baz-copied2
329 $ cp baz ba-copy
329 $ cp baz ba-copy
330 $ echo baz2 >> baz
330 $ echo baz2 >> baz
331 $ git add bar-copied baz-copied baz-copied2 ba-copy
331 $ git add bar-copied baz-copied baz-copied2 ba-copy
332 $ commit -a -m 'rename and copy'
332 $ commit -a -m 'rename and copy'
333 $ cd ..
333 $ cd ..
334
334
335 input validation
335 input validation
336 $ hg convert --config convert.git.similarity=foo --datesort git-repo2 fullrepo
336 $ hg convert --config convert.git.similarity=foo --datesort git-repo2 fullrepo
337 abort: convert.git.similarity is not a valid integer ('foo')
337 abort: convert.git.similarity is not a valid integer ('foo')
338 [255]
338 [255]
339 $ hg convert --config convert.git.similarity=-1 --datesort git-repo2 fullrepo
339 $ hg convert --config convert.git.similarity=-1 --datesort git-repo2 fullrepo
340 abort: similarity must be between 0 and 100
340 abort: similarity must be between 0 and 100
341 [255]
341 [255]
342 $ hg convert --config convert.git.similarity=101 --datesort git-repo2 fullrepo
342 $ hg convert --config convert.git.similarity=101 --datesort git-repo2 fullrepo
343 abort: similarity must be between 0 and 100
343 abort: similarity must be between 0 and 100
344 [255]
344 [255]
345
345
346 $ hg -q convert --config convert.git.similarity=100 --datesort git-repo2 fullrepo
346 $ hg -q convert --config convert.git.similarity=100 --datesort git-repo2 fullrepo
347 $ hg -R fullrepo status -C --change master
347 $ hg -R fullrepo status -C --change master
348 M baz
348 M baz
349 A ba-copy
349 A ba-copy
350 baz
350 baz
351 A bar-copied
351 A bar-copied
352 A baz-copied
352 A baz-copied
353 baz
353 baz
354 A baz-copied2
354 A baz-copied2
355 baz
355 baz
356 A foo-renamed
356 A foo-renamed
357 foo
357 foo
358 R foo
358 R foo
359
359
360 Ensure that the modification to the copy source was preserved
360 Ensure that the modification to the copy source was preserved
361 (there was a bug where if the copy dest was alphabetically prior to the copy
361 (there was a bug where if the copy dest was alphabetically prior to the copy
362 source, the copy source took the contents of the copy dest)
362 source, the copy source took the contents of the copy dest)
363 $ hg cat -r tip fullrepo/baz
363 $ hg cat -r tip fullrepo/baz
364 baz
364 baz
365 baz2
365 baz2
366
366
367 $ cd git-repo2
367 $ cd git-repo2
368 $ echo bar2 >> bar
368 $ echo bar2 >> bar
369 $ commit -a -m 'change bar'
369 $ commit -a -m 'change bar'
370 $ cp bar bar-copied2
370 $ cp bar bar-copied2
371 $ git add bar-copied2
371 $ git add bar-copied2
372 $ commit -a -m 'copy with no changes'
372 $ commit -a -m 'copy with no changes'
373 $ cd ..
373 $ cd ..
374
374
375 $ hg -q convert --config convert.git.similarity=100 \
375 $ hg -q convert --config convert.git.similarity=100 \
376 > --config convert.git.findcopiesharder=1 --datesort git-repo2 fullrepo
376 > --config convert.git.findcopiesharder=1 --datesort git-repo2 fullrepo
377 $ hg -R fullrepo status -C --change master
377 $ hg -R fullrepo status -C --change master
378 A bar-copied2
378 A bar-copied2
379 bar
379 bar
380
380
381 renamelimit config option works
381 renamelimit config option works
382
382
383 $ cd git-repo2
383 $ cd git-repo2
384 $ cat >> copy-source << EOF
384 $ cat >> copy-source << EOF
385 > sc0
385 > sc0
386 > sc1
386 > sc1
387 > sc2
387 > sc2
388 > sc3
388 > sc3
389 > sc4
389 > sc4
390 > sc5
390 > sc5
391 > sc6
391 > sc6
392 > EOF
392 > EOF
393 $ git add copy-source
393 $ git add copy-source
394 $ commit -m 'add copy-source'
394 $ commit -m 'add copy-source'
395 $ cp copy-source source-copy0
395 $ cp copy-source source-copy0
396 $ echo 0 >> source-copy0
396 $ echo 0 >> source-copy0
397 $ cp copy-source source-copy1
397 $ cp copy-source source-copy1
398 $ echo 1 >> source-copy1
398 $ echo 1 >> source-copy1
399 $ git add source-copy0 source-copy1
399 $ git add source-copy0 source-copy1
400 $ commit -a -m 'copy copy-source 2 times'
400 $ commit -a -m 'copy copy-source 2 times'
401 $ cd ..
401 $ cd ..
402
402
403 $ hg -q convert --config convert.git.renamelimit=1 \
403 $ hg -q convert --config convert.git.renamelimit=1 \
404 > --config convert.git.findcopiesharder=true --datesort git-repo2 fullrepo2
404 > --config convert.git.findcopiesharder=true --datesort git-repo2 fullrepo2
405 $ hg -R fullrepo2 status -C --change master
405 $ hg -R fullrepo2 status -C --change master
406 A source-copy0
406 A source-copy0
407 A source-copy1
407 A source-copy1
408
408
409 $ hg -q convert --config convert.git.renamelimit=100 \
409 $ hg -q convert --config convert.git.renamelimit=100 \
410 > --config convert.git.findcopiesharder=true --datesort git-repo2 fullrepo3
410 > --config convert.git.findcopiesharder=true --datesort git-repo2 fullrepo3
411 $ hg -R fullrepo3 status -C --change master
411 $ hg -R fullrepo3 status -C --change master
412 A source-copy0
412 A source-copy0
413 copy-source
413 copy-source
414 A source-copy1
414 A source-copy1
415 copy-source
415 copy-source
416
416
417 test binary conversion (issue1359)
417 test binary conversion (issue1359)
418
418
419 $ count=19
419 $ count=19
420 $ mkdir git-repo3
420 $ mkdir git-repo3
421 $ cd git-repo3
421 $ cd git-repo3
422 $ git init-db >/dev/null 2>/dev/null
422 $ git init-db >/dev/null 2>/dev/null
423 $ $PYTHON -c 'import struct; open("b", "wb").write(b"".join([struct.Struct(">B").pack(i) for i in range(256)])*16)'
423 $ $PYTHON -c 'import struct; open("b", "wb").write(b"".join([struct.Struct(">B").pack(i) for i in range(256)])*16)'
424 $ git add b
424 $ git add b
425 $ commit -a -m addbinary
425 $ commit -a -m addbinary
426 $ cd ..
426 $ cd ..
427
427
428 convert binary file
428 convert binary file
429
429
430 $ hg convert git-repo3 git-repo3-hg
430 $ hg convert git-repo3 git-repo3-hg
431 initializing destination git-repo3-hg repository
431 initializing destination git-repo3-hg repository
432 scanning source...
432 scanning source...
433 sorting...
433 sorting...
434 converting...
434 converting...
435 0 addbinary
435 0 addbinary
436 updating bookmarks
436 updating bookmarks
437 $ cd git-repo3-hg
437 $ cd git-repo3-hg
438 $ hg up -C
438 $ hg up -C
439 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
439 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
440 $ $PYTHON -c 'print len(open("b", "rb").read())'
440 $ $PYTHON -c 'print len(open("b", "rb").read())'
441 4096
441 4096
442 $ cd ..
442 $ cd ..
443
443
444 test author vs committer
444 test author vs committer
445
445
446 $ mkdir git-repo4
446 $ mkdir git-repo4
447 $ cd git-repo4
447 $ cd git-repo4
448 $ git init-db >/dev/null 2>/dev/null
448 $ git init-db >/dev/null 2>/dev/null
449 $ echo >> foo
449 $ echo >> foo
450 $ git add foo
450 $ git add foo
451 $ commit -a -m addfoo
451 $ commit -a -m addfoo
452 $ echo >> foo
452 $ echo >> foo
453 $ GIT_AUTHOR_NAME="nottest"
453 $ GIT_AUTHOR_NAME="nottest"
454 $ commit -a -m addfoo2
454 $ commit -a -m addfoo2
455 $ cd ..
455 $ cd ..
456
456
457 convert author committer
457 convert author committer
458
458
459 $ hg convert git-repo4 git-repo4-hg
459 $ hg convert git-repo4 git-repo4-hg
460 initializing destination git-repo4-hg repository
460 initializing destination git-repo4-hg repository
461 scanning source...
461 scanning source...
462 sorting...
462 sorting...
463 converting...
463 converting...
464 1 addfoo
464 1 addfoo
465 0 addfoo2
465 0 addfoo2
466 updating bookmarks
466 updating bookmarks
467 $ hg -R git-repo4-hg log -v
467 $ hg -R git-repo4-hg log -v
468 changeset: 1:d63e967f93da
468 changeset: 1:d63e967f93da
469 bookmark: master
469 bookmark: master
470 tag: tip
470 tag: tip
471 user: nottest <test@example.org>
471 user: nottest <test@example.org>
472 date: Mon Jan 01 00:00:21 2007 +0000
472 date: Mon Jan 01 00:00:21 2007 +0000
473 files: foo
473 files: foo
474 description:
474 description:
475 addfoo2
475 addfoo2
476
476
477 committer: test <test@example.org>
477 committer: test <test@example.org>
478
478
479
479
480 changeset: 0:0735477b0224
480 changeset: 0:0735477b0224
481 user: test <test@example.org>
481 user: test <test@example.org>
482 date: Mon Jan 01 00:00:20 2007 +0000
482 date: Mon Jan 01 00:00:20 2007 +0000
483 files: foo
483 files: foo
484 description:
484 description:
485 addfoo
485 addfoo
486
486
487
487
488
488
489 Various combinations of committeractions fail
489 Various combinations of committeractions fail
490
490
491 $ hg --config convert.git.committeractions=messagedifferent,messagealways convert git-repo4 bad-committer
491 $ hg --config convert.git.committeractions=messagedifferent,messagealways convert git-repo4 bad-committer
492 initializing destination bad-committer repository
492 initializing destination bad-committer repository
493 abort: committeractions cannot define both messagedifferent and messagealways
493 abort: committeractions cannot define both messagedifferent and messagealways
494 [255]
494 [255]
495
495
496 $ hg --config convert.git.committeractions=dropcommitter,replaceauthor convert git-repo4 bad-committer
496 $ hg --config convert.git.committeractions=dropcommitter,replaceauthor convert git-repo4 bad-committer
497 initializing destination bad-committer repository
497 initializing destination bad-committer repository
498 abort: committeractions cannot define both dropcommitter and replaceauthor
498 abort: committeractions cannot define both dropcommitter and replaceauthor
499 [255]
499 [255]
500
500
501 $ hg --config convert.git.committeractions=dropcommitter,messagealways convert git-repo4 bad-committer
501 $ hg --config convert.git.committeractions=dropcommitter,messagealways convert git-repo4 bad-committer
502 initializing destination bad-committer repository
502 initializing destination bad-committer repository
503 abort: committeractions cannot define both dropcommitter and messagealways
503 abort: committeractions cannot define both dropcommitter and messagealways
504 [255]
504 [255]
505
505
506 custom prefix on messagedifferent works
506 custom prefix on messagedifferent works
507
507
508 $ hg --config convert.git.committeractions=messagedifferent=different: convert git-repo4 git-repo4-hg-messagedifferentprefix
508 $ hg --config convert.git.committeractions=messagedifferent=different: convert git-repo4 git-repo4-hg-messagedifferentprefix
509 initializing destination git-repo4-hg-messagedifferentprefix repository
509 initializing destination git-repo4-hg-messagedifferentprefix repository
510 scanning source...
510 scanning source...
511 sorting...
511 sorting...
512 converting...
512 converting...
513 1 addfoo
513 1 addfoo
514 0 addfoo2
514 0 addfoo2
515 updating bookmarks
515 updating bookmarks
516
516
517 $ hg -R git-repo4-hg-messagedifferentprefix log -v
517 $ hg -R git-repo4-hg-messagedifferentprefix log -v
518 changeset: 1:2fe0c98a109d
518 changeset: 1:2fe0c98a109d
519 bookmark: master
519 bookmark: master
520 tag: tip
520 tag: tip
521 user: nottest <test@example.org>
521 user: nottest <test@example.org>
522 date: Mon Jan 01 00:00:21 2007 +0000
522 date: Mon Jan 01 00:00:21 2007 +0000
523 files: foo
523 files: foo
524 description:
524 description:
525 addfoo2
525 addfoo2
526
526
527 different: test <test@example.org>
527 different: test <test@example.org>
528
528
529
529
530 changeset: 0:0735477b0224
530 changeset: 0:0735477b0224
531 user: test <test@example.org>
531 user: test <test@example.org>
532 date: Mon Jan 01 00:00:20 2007 +0000
532 date: Mon Jan 01 00:00:20 2007 +0000
533 files: foo
533 files: foo
534 description:
534 description:
535 addfoo
535 addfoo
536
536
537
537
538
538
539 messagealways will always add the "committer: " line even if committer identical
539 messagealways will always add the "committer: " line even if committer identical
540
540
541 $ hg --config convert.git.committeractions=messagealways convert git-repo4 git-repo4-hg-messagealways
541 $ hg --config convert.git.committeractions=messagealways convert git-repo4 git-repo4-hg-messagealways
542 initializing destination git-repo4-hg-messagealways repository
542 initializing destination git-repo4-hg-messagealways repository
543 scanning source...
543 scanning source...
544 sorting...
544 sorting...
545 converting...
545 converting...
546 1 addfoo
546 1 addfoo
547 0 addfoo2
547 0 addfoo2
548 updating bookmarks
548 updating bookmarks
549
549
550 $ hg -R git-repo4-hg-messagealways log -v
550 $ hg -R git-repo4-hg-messagealways log -v
551 changeset: 1:8db057d8cd37
551 changeset: 1:8db057d8cd37
552 bookmark: master
552 bookmark: master
553 tag: tip
553 tag: tip
554 user: nottest <test@example.org>
554 user: nottest <test@example.org>
555 date: Mon Jan 01 00:00:21 2007 +0000
555 date: Mon Jan 01 00:00:21 2007 +0000
556 files: foo
556 files: foo
557 description:
557 description:
558 addfoo2
558 addfoo2
559
559
560 committer: test <test@example.org>
560 committer: test <test@example.org>
561
561
562
562
563 changeset: 0:8f71fe9c98be
563 changeset: 0:8f71fe9c98be
564 user: test <test@example.org>
564 user: test <test@example.org>
565 date: Mon Jan 01 00:00:20 2007 +0000
565 date: Mon Jan 01 00:00:20 2007 +0000
566 files: foo
566 files: foo
567 description:
567 description:
568 addfoo
568 addfoo
569
569
570 committer: test <test@example.org>
570 committer: test <test@example.org>
571
571
572
572
573
573
574 custom prefix on messagealways works
574 custom prefix on messagealways works
575
575
576 $ hg --config convert.git.committeractions=messagealways=always: convert git-repo4 git-repo4-hg-messagealwaysprefix
576 $ hg --config convert.git.committeractions=messagealways=always: convert git-repo4 git-repo4-hg-messagealwaysprefix
577 initializing destination git-repo4-hg-messagealwaysprefix repository
577 initializing destination git-repo4-hg-messagealwaysprefix repository
578 scanning source...
578 scanning source...
579 sorting...
579 sorting...
580 converting...
580 converting...
581 1 addfoo
581 1 addfoo
582 0 addfoo2
582 0 addfoo2
583 updating bookmarks
583 updating bookmarks
584
584
585 $ hg -R git-repo4-hg-messagealwaysprefix log -v
585 $ hg -R git-repo4-hg-messagealwaysprefix log -v
586 changeset: 1:83c17174de79
586 changeset: 1:83c17174de79
587 bookmark: master
587 bookmark: master
588 tag: tip
588 tag: tip
589 user: nottest <test@example.org>
589 user: nottest <test@example.org>
590 date: Mon Jan 01 00:00:21 2007 +0000
590 date: Mon Jan 01 00:00:21 2007 +0000
591 files: foo
591 files: foo
592 description:
592 description:
593 addfoo2
593 addfoo2
594
594
595 always: test <test@example.org>
595 always: test <test@example.org>
596
596
597
597
598 changeset: 0:2ac9bcb3534a
598 changeset: 0:2ac9bcb3534a
599 user: test <test@example.org>
599 user: test <test@example.org>
600 date: Mon Jan 01 00:00:20 2007 +0000
600 date: Mon Jan 01 00:00:20 2007 +0000
601 files: foo
601 files: foo
602 description:
602 description:
603 addfoo
603 addfoo
604
604
605 always: test <test@example.org>
605 always: test <test@example.org>
606
606
607
607
608
608
609 replaceauthor replaces author with committer
609 replaceauthor replaces author with committer
610
610
611 $ hg --config convert.git.committeractions=replaceauthor convert git-repo4 git-repo4-hg-replaceauthor
611 $ hg --config convert.git.committeractions=replaceauthor convert git-repo4 git-repo4-hg-replaceauthor
612 initializing destination git-repo4-hg-replaceauthor repository
612 initializing destination git-repo4-hg-replaceauthor repository
613 scanning source...
613 scanning source...
614 sorting...
614 sorting...
615 converting...
615 converting...
616 1 addfoo
616 1 addfoo
617 0 addfoo2
617 0 addfoo2
618 updating bookmarks
618 updating bookmarks
619
619
620 $ hg -R git-repo4-hg-replaceauthor log -v
620 $ hg -R git-repo4-hg-replaceauthor log -v
621 changeset: 1:122c1d8999ea
621 changeset: 1:122c1d8999ea
622 bookmark: master
622 bookmark: master
623 tag: tip
623 tag: tip
624 user: test <test@example.org>
624 user: test <test@example.org>
625 date: Mon Jan 01 00:00:21 2007 +0000
625 date: Mon Jan 01 00:00:21 2007 +0000
626 files: foo
626 files: foo
627 description:
627 description:
628 addfoo2
628 addfoo2
629
629
630
630
631 changeset: 0:0735477b0224
631 changeset: 0:0735477b0224
632 user: test <test@example.org>
632 user: test <test@example.org>
633 date: Mon Jan 01 00:00:20 2007 +0000
633 date: Mon Jan 01 00:00:20 2007 +0000
634 files: foo
634 files: foo
635 description:
635 description:
636 addfoo
636 addfoo
637
637
638
638
639
639
640 dropcommitter removes the committer
640 dropcommitter removes the committer
641
641
642 $ hg --config convert.git.committeractions=dropcommitter convert git-repo4 git-repo4-hg-dropcommitter
642 $ hg --config convert.git.committeractions=dropcommitter convert git-repo4 git-repo4-hg-dropcommitter
643 initializing destination git-repo4-hg-dropcommitter repository
643 initializing destination git-repo4-hg-dropcommitter repository
644 scanning source...
644 scanning source...
645 sorting...
645 sorting...
646 converting...
646 converting...
647 1 addfoo
647 1 addfoo
648 0 addfoo2
648 0 addfoo2
649 updating bookmarks
649 updating bookmarks
650
650
651 $ hg -R git-repo4-hg-dropcommitter log -v
651 $ hg -R git-repo4-hg-dropcommitter log -v
652 changeset: 1:190b2da396cc
652 changeset: 1:190b2da396cc
653 bookmark: master
653 bookmark: master
654 tag: tip
654 tag: tip
655 user: nottest <test@example.org>
655 user: nottest <test@example.org>
656 date: Mon Jan 01 00:00:21 2007 +0000
656 date: Mon Jan 01 00:00:21 2007 +0000
657 files: foo
657 files: foo
658 description:
658 description:
659 addfoo2
659 addfoo2
660
660
661
661
662 changeset: 0:0735477b0224
662 changeset: 0:0735477b0224
663 user: test <test@example.org>
663 user: test <test@example.org>
664 date: Mon Jan 01 00:00:20 2007 +0000
664 date: Mon Jan 01 00:00:20 2007 +0000
665 files: foo
665 files: foo
666 description:
666 description:
667 addfoo
667 addfoo
668
668
669
669
670
670
671 --sourceorder should fail
671 --sourceorder should fail
672
672
673 $ hg convert --sourcesort git-repo4 git-repo4-sourcesort-hg
673 $ hg convert --sourcesort git-repo4 git-repo4-sourcesort-hg
674 initializing destination git-repo4-sourcesort-hg repository
674 initializing destination git-repo4-sourcesort-hg repository
675 abort: --sourcesort is not supported by this data source
675 abort: --sourcesort is not supported by this data source
676 [255]
676 [255]
677
677
678 test converting certain branches
678 test converting certain branches
679
679
680 $ mkdir git-testrevs
680 $ mkdir git-testrevs
681 $ cd git-testrevs
681 $ cd git-testrevs
682 $ git init
682 $ git init
683 Initialized empty Git repository in $TESTTMP/git-testrevs/.git/
683 Initialized empty Git repository in $TESTTMP/git-testrevs/.git/
684 $ echo a >> a ; git add a > /dev/null; git commit -m 'first' > /dev/null
684 $ echo a >> a ; git add a > /dev/null; git commit -m 'first' > /dev/null
685 $ echo a >> a ; git add a > /dev/null; git commit -m 'master commit' > /dev/null
685 $ echo a >> a ; git add a > /dev/null; git commit -m 'master commit' > /dev/null
686 $ git checkout -b goodbranch 'HEAD^'
686 $ git checkout -b goodbranch 'HEAD^'
687 Switched to a new branch 'goodbranch'
687 Switched to a new branch 'goodbranch'
688 $ echo a >> b ; git add b > /dev/null; git commit -m 'good branch commit' > /dev/null
688 $ echo a >> b ; git add b > /dev/null; git commit -m 'good branch commit' > /dev/null
689 $ git checkout -b badbranch 'HEAD^'
689 $ git checkout -b badbranch 'HEAD^'
690 Switched to a new branch 'badbranch'
690 Switched to a new branch 'badbranch'
691 $ echo a >> c ; git add c > /dev/null; git commit -m 'bad branch commit' > /dev/null
691 $ echo a >> c ; git add c > /dev/null; git commit -m 'bad branch commit' > /dev/null
692 $ cd ..
692 $ cd ..
693 $ hg convert git-testrevs hg-testrevs --rev master --rev goodbranch
693 $ hg convert git-testrevs hg-testrevs --rev master --rev goodbranch
694 initializing destination hg-testrevs repository
694 initializing destination hg-testrevs repository
695 scanning source...
695 scanning source...
696 sorting...
696 sorting...
697 converting...
697 converting...
698 2 first
698 2 first
699 1 good branch commit
699 1 good branch commit
700 0 master commit
700 0 master commit
701 updating bookmarks
701 updating bookmarks
702 $ cd hg-testrevs
702 $ cd hg-testrevs
703 $ hg log -G -T '{rev} {bookmarks}'
703 $ hg log -G -T '{rev} {bookmarks}'
704 o 2 master
704 o 2 master
705 |
705 |
706 | o 1 goodbranch
706 | o 1 goodbranch
707 |/
707 |/
708 o 0
708 o 0
709
709
710 $ cd ..
710 $ cd ..
711
711
712 test sub modules
712 test sub modules
713
713
714 $ mkdir git-repo5
714 $ mkdir git-repo5
715 $ cd git-repo5
715 $ cd git-repo5
716 $ git init-db >/dev/null 2>/dev/null
716 $ git init-db >/dev/null 2>/dev/null
717 $ echo 'sub' >> foo
717 $ echo 'sub' >> foo
718 $ git add foo
718 $ git add foo
719 $ commit -a -m 'addfoo'
719 $ commit -a -m 'addfoo'
720 $ BASE=`pwd`
720 $ BASE=`pwd`
721 $ cd ..
721 $ cd ..
722 $ mkdir git-repo6
722 $ mkdir git-repo6
723 $ cd git-repo6
723 $ cd git-repo6
724 $ git init-db >/dev/null 2>/dev/null
724 $ git init-db >/dev/null 2>/dev/null
725 $ git submodule add ${BASE} >/dev/null 2>/dev/null
725 $ git submodule add ${BASE} >/dev/null 2>/dev/null
726 $ commit -a -m 'addsubmodule' >/dev/null 2>/dev/null
726 $ commit -a -m 'addsubmodule' >/dev/null 2>/dev/null
727
727
728 test non-tab whitespace .gitmodules
728 test non-tab whitespace .gitmodules
729
729
730 $ cat >> .gitmodules <<EOF
730 $ cat >> .gitmodules <<EOF
731 > [submodule "git-repo5"]
731 > [submodule "git-repo5"]
732 > path = git-repo5
732 > path = git-repo5
733 > url = git-repo5
733 > url = git-repo5
734 > EOF
734 > EOF
735 $ git commit -q -a -m "weird white space submodule"
735 $ git commit -q -a -m "weird white space submodule"
736 $ cd ..
736 $ cd ..
737 $ hg convert git-repo6 hg-repo6
737 $ hg convert git-repo6 hg-repo6
738 initializing destination hg-repo6 repository
738 initializing destination hg-repo6 repository
739 scanning source...
739 scanning source...
740 sorting...
740 sorting...
741 converting...
741 converting...
742 1 addsubmodule
742 1 addsubmodule
743 0 weird white space submodule
743 0 weird white space submodule
744 updating bookmarks
744 updating bookmarks
745
745
746 $ rm -rf hg-repo6
746 $ rm -rf hg-repo6
747 $ cd git-repo6
747 $ cd git-repo6
748 $ git reset --hard 'HEAD^' > /dev/null
748 $ git reset --hard 'HEAD^' > /dev/null
749
749
750 test missing .gitmodules
750 test missing .gitmodules
751
751
752 $ git submodule add ../git-repo4 >/dev/null 2>/dev/null
752 $ git submodule add ../git-repo4 >/dev/null 2>/dev/null
753 $ git checkout HEAD .gitmodules
753 $ git checkout HEAD .gitmodules
754 $ git rm .gitmodules
754 $ git rm .gitmodules
755 rm '.gitmodules'
755 rm '.gitmodules'
756 $ git commit -q -m "remove .gitmodules" .gitmodules
756 $ git commit -q -m "remove .gitmodules" .gitmodules
757 $ git commit -q -m "missing .gitmodules"
757 $ git commit -q -m "missing .gitmodules"
758 $ cd ..
758 $ cd ..
759 $ hg convert git-repo6 hg-repo6 --traceback 2>&1 | grep -v "fatal: Path '.gitmodules' does not exist"
759 $ hg convert git-repo6 hg-repo6 --traceback 2>&1 | grep -v "fatal: Path '.gitmodules' does not exist"
760 initializing destination hg-repo6 repository
760 initializing destination hg-repo6 repository
761 scanning source...
761 scanning source...
762 sorting...
762 sorting...
763 converting...
763 converting...
764 2 addsubmodule
764 2 addsubmodule
765 1 remove .gitmodules
765 1 remove .gitmodules
766 0 missing .gitmodules
766 0 missing .gitmodules
767 warning: cannot read submodules config file in * (glob)
767 warning: cannot read submodules config file in * (glob)
768 updating bookmarks
768 updating bookmarks
769 $ rm -rf hg-repo6
769 $ rm -rf hg-repo6
770 $ cd git-repo6
770 $ cd git-repo6
771 $ rm -rf git-repo4
771 $ rm -rf git-repo4
772 $ git reset --hard 'HEAD^^' > /dev/null
772 $ git reset --hard 'HEAD^^' > /dev/null
773 $ cd ..
773 $ cd ..
774
774
775 test invalid splicemap1
775 test invalid splicemap1
776
776
777 $ cat > splicemap <<EOF
777 $ cat > splicemap <<EOF
778 > $VALIDID1
778 > $VALIDID1
779 > EOF
779 > EOF
780 $ hg convert --splicemap splicemap git-repo2 git-repo2-splicemap1-hg
780 $ hg convert --splicemap splicemap git-repo2 git-repo2-splicemap1-hg
781 initializing destination git-repo2-splicemap1-hg repository
781 initializing destination git-repo2-splicemap1-hg repository
782 abort: syntax error in splicemap(1): child parent1[,parent2] expected
782 abort: syntax error in splicemap(1): child parent1[,parent2] expected
783 [255]
783 [255]
784
784
785 test invalid splicemap2
785 test invalid splicemap2
786
786
787 $ cat > splicemap <<EOF
787 $ cat > splicemap <<EOF
788 > $VALIDID1 $VALIDID2, $VALIDID2, $VALIDID2
788 > $VALIDID1 $VALIDID2, $VALIDID2, $VALIDID2
789 > EOF
789 > EOF
790 $ hg convert --splicemap splicemap git-repo2 git-repo2-splicemap2-hg
790 $ hg convert --splicemap splicemap git-repo2 git-repo2-splicemap2-hg
791 initializing destination git-repo2-splicemap2-hg repository
791 initializing destination git-repo2-splicemap2-hg repository
792 abort: syntax error in splicemap(1): child parent1[,parent2] expected
792 abort: syntax error in splicemap(1): child parent1[,parent2] expected
793 [255]
793 [255]
794
794
795 test invalid splicemap3
795 test invalid splicemap3
796
796
797 $ cat > splicemap <<EOF
797 $ cat > splicemap <<EOF
798 > $INVALIDID1 $INVALIDID2
798 > $INVALIDID1 $INVALIDID2
799 > EOF
799 > EOF
800 $ hg convert --splicemap splicemap git-repo2 git-repo2-splicemap3-hg
800 $ hg convert --splicemap splicemap git-repo2 git-repo2-splicemap3-hg
801 initializing destination git-repo2-splicemap3-hg repository
801 initializing destination git-repo2-splicemap3-hg repository
802 abort: splicemap entry afd12345af is not a valid revision identifier
802 abort: splicemap entry afd12345af is not a valid revision identifier
803 [255]
803 [255]
804
804
805 convert sub modules
805 convert sub modules
806 $ hg convert git-repo6 git-repo6-hg
806 $ hg convert git-repo6 git-repo6-hg
807 initializing destination git-repo6-hg repository
807 initializing destination git-repo6-hg repository
808 scanning source...
808 scanning source...
809 sorting...
809 sorting...
810 converting...
810 converting...
811 0 addsubmodule
811 0 addsubmodule
812 updating bookmarks
812 updating bookmarks
813 $ hg -R git-repo6-hg log -v
813 $ hg -R git-repo6-hg log -v
814 changeset: 0:* (glob)
814 changeset: 0:* (glob)
815 bookmark: master
815 bookmark: master
816 tag: tip
816 tag: tip
817 user: nottest <test@example.org>
817 user: nottest <test@example.org>
818 date: Mon Jan 01 00:00:23 2007 +0000
818 date: Mon Jan 01 00:00:23 2007 +0000
819 files: .hgsub .hgsubstate
819 files: .hgsub .hgsubstate
820 description:
820 description:
821 addsubmodule
821 addsubmodule
822
822
823 committer: test <test@example.org>
823 committer: test <test@example.org>
824
824
825
825
826
826
827 $ cd git-repo6-hg
827 $ cd git-repo6-hg
828 $ hg up >/dev/null 2>/dev/null
828 $ hg up >/dev/null 2>/dev/null
829 $ cat .hgsubstate
829 $ cat .hgsubstate
830 * git-repo5 (glob)
830 * git-repo5 (glob)
831 $ cd git-repo5
831 $ cd git-repo5
832 $ cat foo
832 $ cat foo
833 sub
833 sub
834
834
835 $ cd ../..
835 $ cd ../..
836
836
837 make sure rename detection doesn't break removing and adding gitmodules
837 make sure rename detection doesn't break removing and adding gitmodules
838
838
839 $ cd git-repo6
839 $ cd git-repo6
840 $ git mv .gitmodules .gitmodules-renamed
840 $ git mv .gitmodules .gitmodules-renamed
841 $ commit -a -m 'rename .gitmodules'
841 $ commit -a -m 'rename .gitmodules'
842 $ git mv .gitmodules-renamed .gitmodules
842 $ git mv .gitmodules-renamed .gitmodules
843 $ commit -a -m 'rename .gitmodules back'
843 $ commit -a -m 'rename .gitmodules back'
844 $ cd ..
844 $ cd ..
845
845
846 $ hg --config convert.git.similarity=100 convert -q git-repo6 git-repo6-hg
846 $ hg --config convert.git.similarity=100 convert -q git-repo6 git-repo6-hg
847 $ hg -R git-repo6-hg log -r 'tip^' -T "{desc|firstline}\n"
847 $ hg -R git-repo6-hg log -r 'tip^' -T "{desc|firstline}\n"
848 rename .gitmodules
848 rename .gitmodules
849 $ hg -R git-repo6-hg status -C --change 'tip^'
849 $ hg -R git-repo6-hg status -C --change 'tip^'
850 A .gitmodules-renamed
850 A .gitmodules-renamed
851 R .hgsub
851 R .hgsub
852 R .hgsubstate
852 R .hgsubstate
853 $ hg -R git-repo6-hg log -r tip -T "{desc|firstline}\n"
853 $ hg -R git-repo6-hg log -r tip -T "{desc|firstline}\n"
854 rename .gitmodules back
854 rename .gitmodules back
855 $ hg -R git-repo6-hg status -C --change tip
855 $ hg -R git-repo6-hg status -C --change tip
856 A .hgsub
856 A .hgsub
857 A .hgsubstate
857 A .hgsubstate
858 R .gitmodules-renamed
858 R .gitmodules-renamed
859
859
860 convert the revision removing '.gitmodules' itself (and related
860 convert the revision removing '.gitmodules' itself (and related
861 submodules)
861 submodules)
862
862
863 $ cd git-repo6
863 $ cd git-repo6
864 $ git rm .gitmodules
864 $ git rm .gitmodules
865 rm '.gitmodules'
865 rm '.gitmodules'
866 $ git rm --cached git-repo5
866 $ git rm --cached git-repo5
867 rm 'git-repo5'
867 rm 'git-repo5'
868 $ commit -a -m 'remove .gitmodules and submodule git-repo5'
868 $ commit -a -m 'remove .gitmodules and submodule git-repo5'
869 $ cd ..
869 $ cd ..
870
870
871 $ hg convert -q git-repo6 git-repo6-hg
871 $ hg convert -q git-repo6 git-repo6-hg
872 $ hg -R git-repo6-hg tip -T "{desc|firstline}\n"
872 $ hg -R git-repo6-hg tip -T "{desc|firstline}\n"
873 remove .gitmodules and submodule git-repo5
873 remove .gitmodules and submodule git-repo5
874 $ hg -R git-repo6-hg tip -T "{file_dels}\n"
874 $ hg -R git-repo6-hg tip -T "{file_dels}\n"
875 .hgsub .hgsubstate
875 .hgsub .hgsubstate
876
876
877 skip submodules in the conversion
877 skip submodules in the conversion
878
878
879 $ hg convert -q git-repo6 no-submodules --config convert.git.skipsubmodules=True
879 $ hg convert -q git-repo6 no-submodules --config convert.git.skipsubmodules=True
880 $ hg -R no-submodules manifest --all
880 $ hg -R no-submodules manifest --all
881 .gitmodules-renamed
881 .gitmodules-renamed (no-reposimplestore !)
882
882
883 convert using a different remote prefix
883 convert using a different remote prefix
884 $ git init git-repo7
884 $ git init git-repo7
885 Initialized empty Git repository in $TESTTMP/git-repo7/.git/
885 Initialized empty Git repository in $TESTTMP/git-repo7/.git/
886 $ cd git-repo7
886 $ cd git-repo7
887 TODO: it'd be nice to use (?) lines instead of grep -v to handle the
887 TODO: it'd be nice to use (?) lines instead of grep -v to handle the
888 git output variance, but that doesn't currently work in the middle of
888 git output variance, but that doesn't currently work in the middle of
889 a block, so do this for now.
889 a block, so do this for now.
890 $ touch a && git add a && git commit -am "commit a" | grep -v changed
890 $ touch a && git add a && git commit -am "commit a" | grep -v changed
891 [master (root-commit) 8ae5f69] commit a
891 [master (root-commit) 8ae5f69] commit a
892 Author: nottest <test@example.org>
892 Author: nottest <test@example.org>
893 create mode 100644 a
893 create mode 100644 a
894 $ cd ..
894 $ cd ..
895 $ git clone git-repo7 git-repo7-client
895 $ git clone git-repo7 git-repo7-client
896 Cloning into 'git-repo7-client'...
896 Cloning into 'git-repo7-client'...
897 done.
897 done.
898 $ hg convert --config convert.git.remoteprefix=origin git-repo7-client hg-repo7
898 $ hg convert --config convert.git.remoteprefix=origin git-repo7-client hg-repo7
899 initializing destination hg-repo7 repository
899 initializing destination hg-repo7 repository
900 scanning source...
900 scanning source...
901 sorting...
901 sorting...
902 converting...
902 converting...
903 0 commit a
903 0 commit a
904 updating bookmarks
904 updating bookmarks
905 $ hg -R hg-repo7 bookmarks
905 $ hg -R hg-repo7 bookmarks
906 master 0:03bf38caa4c6
906 master 0:03bf38caa4c6
907 origin/master 0:03bf38caa4c6
907 origin/master 0:03bf38caa4c6
908
908
909 Run convert when the remote branches have changed
909 Run convert when the remote branches have changed
910 (there was an old bug where the local convert read branches from the server)
910 (there was an old bug where the local convert read branches from the server)
911
911
912 $ cd git-repo7
912 $ cd git-repo7
913 $ echo a >> a
913 $ echo a >> a
914 $ git commit -q -am "move master forward"
914 $ git commit -q -am "move master forward"
915 $ cd ..
915 $ cd ..
916 $ rm -rf hg-repo7
916 $ rm -rf hg-repo7
917 $ hg convert --config convert.git.remoteprefix=origin git-repo7-client hg-repo7
917 $ hg convert --config convert.git.remoteprefix=origin git-repo7-client hg-repo7
918 initializing destination hg-repo7 repository
918 initializing destination hg-repo7 repository
919 scanning source...
919 scanning source...
920 sorting...
920 sorting...
921 converting...
921 converting...
922 0 commit a
922 0 commit a
923 updating bookmarks
923 updating bookmarks
924 $ hg -R hg-repo7 bookmarks
924 $ hg -R hg-repo7 bookmarks
925 master 0:03bf38caa4c6
925 master 0:03bf38caa4c6
926 origin/master 0:03bf38caa4c6
926 origin/master 0:03bf38caa4c6
927
927
928 damaged git repository tests:
928 damaged git repository tests:
929 In case the hard-coded hashes change, the following commands can be used to
929 In case the hard-coded hashes change, the following commands can be used to
930 list the hashes and their corresponding types in the repository:
930 list the hashes and their corresponding types in the repository:
931 cd git-repo4/.git/objects
931 cd git-repo4/.git/objects
932 find . -type f | cut -c 3- | sed 's_/__' | xargs -n 1 -t git cat-file -t
932 find . -type f | cut -c 3- | sed 's_/__' | xargs -n 1 -t git cat-file -t
933 cd ../../..
933 cd ../../..
934
934
935 damage git repository by renaming a commit object
935 damage git repository by renaming a commit object
936 $ COMMIT_OBJ=1c/0ce3c5886f83a1d78a7b517cdff5cf9ca17bdd
936 $ COMMIT_OBJ=1c/0ce3c5886f83a1d78a7b517cdff5cf9ca17bdd
937 $ mv git-repo4/.git/objects/$COMMIT_OBJ git-repo4/.git/objects/$COMMIT_OBJ.tmp
937 $ mv git-repo4/.git/objects/$COMMIT_OBJ git-repo4/.git/objects/$COMMIT_OBJ.tmp
938 $ hg convert git-repo4 git-repo4-broken-hg 2>&1 | grep 'abort:'
938 $ hg convert git-repo4 git-repo4-broken-hg 2>&1 | grep 'abort:'
939 abort: cannot retrieve number of commits in $TESTTMP/git-repo4/.git
939 abort: cannot retrieve number of commits in $TESTTMP/git-repo4/.git
940 $ mv git-repo4/.git/objects/$COMMIT_OBJ.tmp git-repo4/.git/objects/$COMMIT_OBJ
940 $ mv git-repo4/.git/objects/$COMMIT_OBJ.tmp git-repo4/.git/objects/$COMMIT_OBJ
941 damage git repository by renaming a blob object
941 damage git repository by renaming a blob object
942
942
943 $ BLOB_OBJ=8b/137891791fe96927ad78e64b0aad7bded08bdc
943 $ BLOB_OBJ=8b/137891791fe96927ad78e64b0aad7bded08bdc
944 $ mv git-repo4/.git/objects/$BLOB_OBJ git-repo4/.git/objects/$BLOB_OBJ.tmp
944 $ mv git-repo4/.git/objects/$BLOB_OBJ git-repo4/.git/objects/$BLOB_OBJ.tmp
945 $ hg convert git-repo4 git-repo4-broken-hg 2>&1 | grep 'abort:'
945 $ hg convert git-repo4 git-repo4-broken-hg 2>&1 | grep 'abort:'
946 abort: cannot read 'blob' object at 8b137891791fe96927ad78e64b0aad7bded08bdc
946 abort: cannot read 'blob' object at 8b137891791fe96927ad78e64b0aad7bded08bdc
947 $ mv git-repo4/.git/objects/$BLOB_OBJ.tmp git-repo4/.git/objects/$BLOB_OBJ
947 $ mv git-repo4/.git/objects/$BLOB_OBJ.tmp git-repo4/.git/objects/$BLOB_OBJ
948 damage git repository by renaming a tree object
948 damage git repository by renaming a tree object
949
949
950 $ TREE_OBJ=72/49f083d2a63a41cc737764a86981eb5f3e4635
950 $ TREE_OBJ=72/49f083d2a63a41cc737764a86981eb5f3e4635
951 $ mv git-repo4/.git/objects/$TREE_OBJ git-repo4/.git/objects/$TREE_OBJ.tmp
951 $ mv git-repo4/.git/objects/$TREE_OBJ git-repo4/.git/objects/$TREE_OBJ.tmp
952 $ hg convert git-repo4 git-repo4-broken-hg 2>&1 | grep 'abort:'
952 $ hg convert git-repo4 git-repo4-broken-hg 2>&1 | grep 'abort:'
953 abort: cannot read changes in 1c0ce3c5886f83a1d78a7b517cdff5cf9ca17bdd
953 abort: cannot read changes in 1c0ce3c5886f83a1d78a7b517cdff5cf9ca17bdd
954
954
955 #if no-windows git19
955 #if no-windows git19
956
956
957 test for escaping the repo name (CVE-2016-3069)
957 test for escaping the repo name (CVE-2016-3069)
958
958
959 $ git init '`echo pwned >COMMAND-INJECTION`'
959 $ git init '`echo pwned >COMMAND-INJECTION`'
960 Initialized empty Git repository in $TESTTMP/`echo pwned >COMMAND-INJECTION`/.git/
960 Initialized empty Git repository in $TESTTMP/`echo pwned >COMMAND-INJECTION`/.git/
961 $ cd '`echo pwned >COMMAND-INJECTION`'
961 $ cd '`echo pwned >COMMAND-INJECTION`'
962 $ git commit -q --allow-empty -m 'empty'
962 $ git commit -q --allow-empty -m 'empty'
963 $ cd ..
963 $ cd ..
964 $ hg convert '`echo pwned >COMMAND-INJECTION`' 'converted'
964 $ hg convert '`echo pwned >COMMAND-INJECTION`' 'converted'
965 initializing destination converted repository
965 initializing destination converted repository
966 scanning source...
966 scanning source...
967 sorting...
967 sorting...
968 converting...
968 converting...
969 0 empty
969 0 empty
970 updating bookmarks
970 updating bookmarks
971 $ test -f COMMAND-INJECTION
971 $ test -f COMMAND-INJECTION
972 [1]
972 [1]
973
973
974 test for safely passing paths to git (CVE-2016-3105)
974 test for safely passing paths to git (CVE-2016-3105)
975
975
976 $ git init 'ext::sh -c echo% pwned% >GIT-EXT-COMMAND-INJECTION% #'
976 $ git init 'ext::sh -c echo% pwned% >GIT-EXT-COMMAND-INJECTION% #'
977 Initialized empty Git repository in $TESTTMP/ext::sh -c echo% pwned% >GIT-EXT-COMMAND-INJECTION% #/.git/
977 Initialized empty Git repository in $TESTTMP/ext::sh -c echo% pwned% >GIT-EXT-COMMAND-INJECTION% #/.git/
978 $ cd 'ext::sh -c echo% pwned% >GIT-EXT-COMMAND-INJECTION% #'
978 $ cd 'ext::sh -c echo% pwned% >GIT-EXT-COMMAND-INJECTION% #'
979 $ git commit -q --allow-empty -m 'empty'
979 $ git commit -q --allow-empty -m 'empty'
980 $ cd ..
980 $ cd ..
981 $ hg convert 'ext::sh -c echo% pwned% >GIT-EXT-COMMAND-INJECTION% #' 'converted-git-ext'
981 $ hg convert 'ext::sh -c echo% pwned% >GIT-EXT-COMMAND-INJECTION% #' 'converted-git-ext'
982 initializing destination converted-git-ext repository
982 initializing destination converted-git-ext repository
983 scanning source...
983 scanning source...
984 sorting...
984 sorting...
985 converting...
985 converting...
986 0 empty
986 0 empty
987 updating bookmarks
987 updating bookmarks
988 $ test -f GIT-EXT-COMMAND-INJECTION
988 $ test -f GIT-EXT-COMMAND-INJECTION
989 [1]
989 [1]
990
990
991 #endif
991 #endif
992
992
993 Conversion of extra commit metadata to extras works
993 Conversion of extra commit metadata to extras works
994
994
995 $ git init gitextras >/dev/null 2>/dev/null
995 $ git init gitextras >/dev/null 2>/dev/null
996 $ cd gitextras
996 $ cd gitextras
997 $ touch foo
997 $ touch foo
998 $ git add foo
998 $ git add foo
999 $ commit -m initial
999 $ commit -m initial
1000 $ echo 1 > foo
1000 $ echo 1 > foo
1001 $ tree=`git write-tree`
1001 $ tree=`git write-tree`
1002
1002
1003 Git doesn't provider a user-facing API to write extra metadata into the
1003 Git doesn't provider a user-facing API to write extra metadata into the
1004 commit, so create the commit object by hand
1004 commit, so create the commit object by hand
1005
1005
1006 $ git hash-object -t commit -w --stdin << EOF
1006 $ git hash-object -t commit -w --stdin << EOF
1007 > tree ${tree}
1007 > tree ${tree}
1008 > parent ba6b1344e977ece9e00958dbbf17f1f09384b2c1
1008 > parent ba6b1344e977ece9e00958dbbf17f1f09384b2c1
1009 > author test <test@example.com> 1000000000 +0000
1009 > author test <test@example.com> 1000000000 +0000
1010 > committer test <test@example.com> 1000000000 +0000
1010 > committer test <test@example.com> 1000000000 +0000
1011 > extra-1 extra-1
1011 > extra-1 extra-1
1012 > extra-2 extra-2 with space
1012 > extra-2 extra-2 with space
1013 > convert_revision 0000aaaabbbbccccddddeeee
1013 > convert_revision 0000aaaabbbbccccddddeeee
1014 >
1014 >
1015 > message with extras
1015 > message with extras
1016 > EOF
1016 > EOF
1017 8123727c8361a4117d1a2d80e0c4e7d70c757f18
1017 8123727c8361a4117d1a2d80e0c4e7d70c757f18
1018
1018
1019 $ git reset --hard 8123727c8361a4117d1a2d80e0c4e7d70c757f18 > /dev/null
1019 $ git reset --hard 8123727c8361a4117d1a2d80e0c4e7d70c757f18 > /dev/null
1020
1020
1021 $ cd ..
1021 $ cd ..
1022
1022
1023 convert will not retain custom metadata keys by default
1023 convert will not retain custom metadata keys by default
1024
1024
1025 $ hg convert gitextras hgextras1
1025 $ hg convert gitextras hgextras1
1026 initializing destination hgextras1 repository
1026 initializing destination hgextras1 repository
1027 scanning source...
1027 scanning source...
1028 sorting...
1028 sorting...
1029 converting...
1029 converting...
1030 1 initial
1030 1 initial
1031 0 message with extras
1031 0 message with extras
1032 updating bookmarks
1032 updating bookmarks
1033
1033
1034 $ hg -R hgextras1 log --debug -r 1
1034 $ hg -R hgextras1 log --debug -r 1
1035 changeset: 1:e13a39880f68479127b2a80fa0b448cc8524aa09
1035 changeset: 1:e13a39880f68479127b2a80fa0b448cc8524aa09
1036 bookmark: master
1036 bookmark: master
1037 tag: tip
1037 tag: tip
1038 phase: draft
1038 phase: draft
1039 parent: 0:dcb68977c55cd02cbd13b901df65c4b6e7b9c4b9
1039 parent: 0:dcb68977c55cd02cbd13b901df65c4b6e7b9c4b9
1040 parent: -1:0000000000000000000000000000000000000000
1040 parent: -1:0000000000000000000000000000000000000000
1041 manifest: 0:6a3df4de388f3c4f8e28f4f9a814299a3cbb5f50
1041 manifest: 0:6a3df4de388f3c4f8e28f4f9a814299a3cbb5f50
1042 user: test <test@example.com>
1042 user: test <test@example.com>
1043 date: Sun Sep 09 01:46:40 2001 +0000
1043 date: Sun Sep 09 01:46:40 2001 +0000
1044 extra: branch=default
1044 extra: branch=default
1045 extra: convert_revision=8123727c8361a4117d1a2d80e0c4e7d70c757f18
1045 extra: convert_revision=8123727c8361a4117d1a2d80e0c4e7d70c757f18
1046 description:
1046 description:
1047 message with extras
1047 message with extras
1048
1048
1049
1049
1050
1050
1051 Attempting to convert a banned extra is disallowed
1051 Attempting to convert a banned extra is disallowed
1052
1052
1053 $ hg convert --config convert.git.extrakeys=tree,parent gitextras hgextras-banned
1053 $ hg convert --config convert.git.extrakeys=tree,parent gitextras hgextras-banned
1054 initializing destination hgextras-banned repository
1054 initializing destination hgextras-banned repository
1055 abort: copying of extra key is forbidden: parent, tree
1055 abort: copying of extra key is forbidden: parent, tree
1056 [255]
1056 [255]
1057
1057
1058 Converting a specific extra works
1058 Converting a specific extra works
1059
1059
1060 $ hg convert --config convert.git.extrakeys=extra-1 gitextras hgextras2
1060 $ hg convert --config convert.git.extrakeys=extra-1 gitextras hgextras2
1061 initializing destination hgextras2 repository
1061 initializing destination hgextras2 repository
1062 scanning source...
1062 scanning source...
1063 sorting...
1063 sorting...
1064 converting...
1064 converting...
1065 1 initial
1065 1 initial
1066 0 message with extras
1066 0 message with extras
1067 updating bookmarks
1067 updating bookmarks
1068
1068
1069 $ hg -R hgextras2 log --debug -r 1
1069 $ hg -R hgextras2 log --debug -r 1
1070 changeset: 1:d40fb205d58597e6ecfd55b16f198be5bf436391
1070 changeset: 1:d40fb205d58597e6ecfd55b16f198be5bf436391
1071 bookmark: master
1071 bookmark: master
1072 tag: tip
1072 tag: tip
1073 phase: draft
1073 phase: draft
1074 parent: 0:dcb68977c55cd02cbd13b901df65c4b6e7b9c4b9
1074 parent: 0:dcb68977c55cd02cbd13b901df65c4b6e7b9c4b9
1075 parent: -1:0000000000000000000000000000000000000000
1075 parent: -1:0000000000000000000000000000000000000000
1076 manifest: 0:6a3df4de388f3c4f8e28f4f9a814299a3cbb5f50
1076 manifest: 0:6a3df4de388f3c4f8e28f4f9a814299a3cbb5f50
1077 user: test <test@example.com>
1077 user: test <test@example.com>
1078 date: Sun Sep 09 01:46:40 2001 +0000
1078 date: Sun Sep 09 01:46:40 2001 +0000
1079 extra: branch=default
1079 extra: branch=default
1080 extra: convert_revision=8123727c8361a4117d1a2d80e0c4e7d70c757f18
1080 extra: convert_revision=8123727c8361a4117d1a2d80e0c4e7d70c757f18
1081 extra: extra-1=extra-1
1081 extra: extra-1=extra-1
1082 description:
1082 description:
1083 message with extras
1083 message with extras
1084
1084
1085
1085
1086
1086
1087 Converting multiple extras works
1087 Converting multiple extras works
1088
1088
1089 $ hg convert --config convert.git.extrakeys=extra-1,extra-2 gitextras hgextras3
1089 $ hg convert --config convert.git.extrakeys=extra-1,extra-2 gitextras hgextras3
1090 initializing destination hgextras3 repository
1090 initializing destination hgextras3 repository
1091 scanning source...
1091 scanning source...
1092 sorting...
1092 sorting...
1093 converting...
1093 converting...
1094 1 initial
1094 1 initial
1095 0 message with extras
1095 0 message with extras
1096 updating bookmarks
1096 updating bookmarks
1097
1097
1098 $ hg -R hgextras3 log --debug -r 1
1098 $ hg -R hgextras3 log --debug -r 1
1099 changeset: 1:0105af33379e7b6491501fd34141b7af700fe125
1099 changeset: 1:0105af33379e7b6491501fd34141b7af700fe125
1100 bookmark: master
1100 bookmark: master
1101 tag: tip
1101 tag: tip
1102 phase: draft
1102 phase: draft
1103 parent: 0:dcb68977c55cd02cbd13b901df65c4b6e7b9c4b9
1103 parent: 0:dcb68977c55cd02cbd13b901df65c4b6e7b9c4b9
1104 parent: -1:0000000000000000000000000000000000000000
1104 parent: -1:0000000000000000000000000000000000000000
1105 manifest: 0:6a3df4de388f3c4f8e28f4f9a814299a3cbb5f50
1105 manifest: 0:6a3df4de388f3c4f8e28f4f9a814299a3cbb5f50
1106 user: test <test@example.com>
1106 user: test <test@example.com>
1107 date: Sun Sep 09 01:46:40 2001 +0000
1107 date: Sun Sep 09 01:46:40 2001 +0000
1108 extra: branch=default
1108 extra: branch=default
1109 extra: convert_revision=8123727c8361a4117d1a2d80e0c4e7d70c757f18
1109 extra: convert_revision=8123727c8361a4117d1a2d80e0c4e7d70c757f18
1110 extra: extra-1=extra-1
1110 extra: extra-1=extra-1
1111 extra: extra-2=extra-2 with space
1111 extra: extra-2=extra-2 with space
1112 description:
1112 description:
1113 message with extras
1113 message with extras
1114
1114
1115
1115
1116
1116
1117 convert.git.saverev can be disabled to prevent convert_revision from being written
1117 convert.git.saverev can be disabled to prevent convert_revision from being written
1118
1118
1119 $ hg convert --config convert.git.saverev=false gitextras hgextras4
1119 $ hg convert --config convert.git.saverev=false gitextras hgextras4
1120 initializing destination hgextras4 repository
1120 initializing destination hgextras4 repository
1121 scanning source...
1121 scanning source...
1122 sorting...
1122 sorting...
1123 converting...
1123 converting...
1124 1 initial
1124 1 initial
1125 0 message with extras
1125 0 message with extras
1126 updating bookmarks
1126 updating bookmarks
1127
1127
1128 $ hg -R hgextras4 log --debug -r 1
1128 $ hg -R hgextras4 log --debug -r 1
1129 changeset: 1:1dcaf4ffe5bee43fa86db2800821f6f0af212c5c
1129 changeset: 1:1dcaf4ffe5bee43fa86db2800821f6f0af212c5c
1130 bookmark: master
1130 bookmark: master
1131 tag: tip
1131 tag: tip
1132 phase: draft
1132 phase: draft
1133 parent: 0:a13935fec4daf06a5a87a7307ccb0fc94f98d06d
1133 parent: 0:a13935fec4daf06a5a87a7307ccb0fc94f98d06d
1134 parent: -1:0000000000000000000000000000000000000000
1134 parent: -1:0000000000000000000000000000000000000000
1135 manifest: 0:6a3df4de388f3c4f8e28f4f9a814299a3cbb5f50
1135 manifest: 0:6a3df4de388f3c4f8e28f4f9a814299a3cbb5f50
1136 user: test <test@example.com>
1136 user: test <test@example.com>
1137 date: Sun Sep 09 01:46:40 2001 +0000
1137 date: Sun Sep 09 01:46:40 2001 +0000
1138 extra: branch=default
1138 extra: branch=default
1139 description:
1139 description:
1140 message with extras
1140 message with extras
1141
1141
1142
1142
1143
1143
1144 convert.git.saverev and convert.git.extrakeys can be combined to preserve
1144 convert.git.saverev and convert.git.extrakeys can be combined to preserve
1145 convert_revision from source
1145 convert_revision from source
1146
1146
1147 $ hg convert --config convert.git.saverev=false --config convert.git.extrakeys=convert_revision gitextras hgextras5
1147 $ hg convert --config convert.git.saverev=false --config convert.git.extrakeys=convert_revision gitextras hgextras5
1148 initializing destination hgextras5 repository
1148 initializing destination hgextras5 repository
1149 scanning source...
1149 scanning source...
1150 sorting...
1150 sorting...
1151 converting...
1151 converting...
1152 1 initial
1152 1 initial
1153 0 message with extras
1153 0 message with extras
1154 updating bookmarks
1154 updating bookmarks
1155
1155
1156 $ hg -R hgextras5 log --debug -r 1
1156 $ hg -R hgextras5 log --debug -r 1
1157 changeset: 1:574d85931544d4542007664fee3747360e85ee28
1157 changeset: 1:574d85931544d4542007664fee3747360e85ee28
1158 bookmark: master
1158 bookmark: master
1159 tag: tip
1159 tag: tip
1160 phase: draft
1160 phase: draft
1161 parent: 0:a13935fec4daf06a5a87a7307ccb0fc94f98d06d
1161 parent: 0:a13935fec4daf06a5a87a7307ccb0fc94f98d06d
1162 parent: -1:0000000000000000000000000000000000000000
1162 parent: -1:0000000000000000000000000000000000000000
1163 manifest: 0:6a3df4de388f3c4f8e28f4f9a814299a3cbb5f50
1163 manifest: 0:6a3df4de388f3c4f8e28f4f9a814299a3cbb5f50
1164 user: test <test@example.com>
1164 user: test <test@example.com>
1165 date: Sun Sep 09 01:46:40 2001 +0000
1165 date: Sun Sep 09 01:46:40 2001 +0000
1166 extra: branch=default
1166 extra: branch=default
1167 extra: convert_revision=0000aaaabbbbccccddddeeee
1167 extra: convert_revision=0000aaaabbbbccccddddeeee
1168 description:
1168 description:
1169 message with extras
1169 message with extras
1170
1170
1171
1171
@@ -1,79 +1,83 b''
1 #require repobundlerepo
2
3 Source bundle was generated with the following script:
1 Source bundle was generated with the following script:
4
2
5 # hg init
3 # hg init
6 # echo a > a
4 # echo a > a
7 # ln -s a l
5 # ln -s a l
8 # hg ci -Ama -d'0 0'
6 # hg ci -Ama -d'0 0'
9 # mkdir b
7 # mkdir b
10 # echo a > b/a
8 # echo a > b/a
11 # chmod +x b/a
9 # chmod +x b/a
12 # hg ci -Amb -d'1 0'
10 # hg ci -Amb -d'1 0'
13
11
14 $ hg init
12 $ hg init
15 $ hg -q pull "$TESTDIR/bundles/test-manifest.hg"
13 $ hg unbundle "$TESTDIR/bundles/test-manifest.hg"
14 adding changesets
15 adding manifests
16 adding file changes
17 added 2 changesets with 3 changes to 3 files
18 new changesets b73562a03cfe:5bdc995175ba
19 (run 'hg update' to get a working copy)
16
20
17 The next call is expected to return nothing:
21 The next call is expected to return nothing:
18
22
19 $ hg manifest
23 $ hg manifest
20
24
21 $ hg co
25 $ hg co
22 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
26 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
23
27
24 $ hg manifest
28 $ hg manifest
25 a
29 a
26 b/a
30 b/a
27 l
31 l
28
32
29 $ hg files -vr .
33 $ hg files -vr .
30 2 a
34 2 a
31 2 x b/a
35 2 x b/a
32 1 l l
36 1 l l
33 $ hg files -r . -X b
37 $ hg files -r . -X b
34 a
38 a
35 l
39 l
36
40
37 $ hg manifest -v
41 $ hg manifest -v
38 644 a
42 644 a
39 755 * b/a
43 755 * b/a
40 644 @ l
44 644 @ l
41
45
42 $ hg manifest --debug
46 $ hg manifest --debug
43 b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3 644 a
47 b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3 644 a
44 b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3 755 * b/a
48 b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3 755 * b/a
45 047b75c6d7a3ef6a2243bd0e99f94f6ea6683597 644 @ l
49 047b75c6d7a3ef6a2243bd0e99f94f6ea6683597 644 @ l
46
50
47 $ hg manifest -r 0
51 $ hg manifest -r 0
48 a
52 a
49 l
53 l
50
54
51 $ hg manifest -r 1
55 $ hg manifest -r 1
52 a
56 a
53 b/a
57 b/a
54 l
58 l
55
59
56 $ hg manifest -r tip
60 $ hg manifest -r tip
57 a
61 a
58 b/a
62 b/a
59 l
63 l
60
64
61 $ hg manifest tip
65 $ hg manifest tip
62 a
66 a
63 b/a
67 b/a
64 l
68 l
65
69
66 $ hg manifest --all
70 $ hg manifest --all
67 a
71 a (no-reposimplestore !)
68 b/a
72 b/a (no-reposimplestore !)
69 l
73 l (no-reposimplestore !)
70
74
71 The next two calls are expected to abort:
75 The next two calls are expected to abort:
72
76
73 $ hg manifest -r 2
77 $ hg manifest -r 2
74 abort: unknown revision '2'!
78 abort: unknown revision '2'!
75 [255]
79 [255]
76
80
77 $ hg manifest -r tip tip
81 $ hg manifest -r tip tip
78 abort: please specify just one revision
82 abort: please specify just one revision
79 [255]
83 [255]
General Comments 0
You need to be logged in to leave comments. Login now