##// END OF EJS Templates
copies: rewrite copy detection for non-merge users...
Matt Mackall -
r15775:91eb4512 default
parent child Browse files
Show More
@@ -1,5710 +1,5700 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 node import hex, bin, nullid, nullrev, short
8 from node import hex, bin, nullid, nullrev, short
9 from lock import release
9 from lock import release
10 from i18n import _, gettext
10 from i18n import _, gettext
11 import os, re, difflib, time, tempfile, errno
11 import os, re, difflib, time, tempfile, errno
12 import hg, scmutil, util, revlog, extensions, copies, error, bookmarks
12 import hg, scmutil, util, revlog, extensions, copies, error, bookmarks
13 import patch, help, url, encoding, templatekw, discovery
13 import patch, help, url, encoding, templatekw, discovery
14 import archival, changegroup, cmdutil, hbisect
14 import archival, changegroup, cmdutil, hbisect
15 import sshserver, hgweb, hgweb.server, commandserver
15 import sshserver, hgweb, hgweb.server, commandserver
16 import match as matchmod
16 import match as matchmod
17 import merge as mergemod
17 import merge as mergemod
18 import minirst, revset, fileset
18 import minirst, revset, fileset
19 import dagparser, context, simplemerge
19 import dagparser, context, simplemerge
20 import random, setdiscovery, treediscovery, dagutil
20 import random, setdiscovery, treediscovery, dagutil
21
21
22 table = {}
22 table = {}
23
23
24 command = cmdutil.command(table)
24 command = cmdutil.command(table)
25
25
26 # common command options
26 # common command options
27
27
28 globalopts = [
28 globalopts = [
29 ('R', 'repository', '',
29 ('R', 'repository', '',
30 _('repository root directory or name of overlay bundle file'),
30 _('repository root directory or name of overlay bundle file'),
31 _('REPO')),
31 _('REPO')),
32 ('', 'cwd', '',
32 ('', 'cwd', '',
33 _('change working directory'), _('DIR')),
33 _('change working directory'), _('DIR')),
34 ('y', 'noninteractive', None,
34 ('y', 'noninteractive', None,
35 _('do not prompt, automatically pick the first choice for all prompts')),
35 _('do not prompt, automatically pick the first choice for all prompts')),
36 ('q', 'quiet', None, _('suppress output')),
36 ('q', 'quiet', None, _('suppress output')),
37 ('v', 'verbose', None, _('enable additional output')),
37 ('v', 'verbose', None, _('enable additional output')),
38 ('', 'config', [],
38 ('', 'config', [],
39 _('set/override config option (use \'section.name=value\')'),
39 _('set/override config option (use \'section.name=value\')'),
40 _('CONFIG')),
40 _('CONFIG')),
41 ('', 'debug', None, _('enable debugging output')),
41 ('', 'debug', None, _('enable debugging output')),
42 ('', 'debugger', None, _('start debugger')),
42 ('', 'debugger', None, _('start debugger')),
43 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
43 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
44 _('ENCODE')),
44 _('ENCODE')),
45 ('', 'encodingmode', encoding.encodingmode,
45 ('', 'encodingmode', encoding.encodingmode,
46 _('set the charset encoding mode'), _('MODE')),
46 _('set the charset encoding mode'), _('MODE')),
47 ('', 'traceback', None, _('always print a traceback on exception')),
47 ('', 'traceback', None, _('always print a traceback on exception')),
48 ('', 'time', None, _('time how long the command takes')),
48 ('', 'time', None, _('time how long the command takes')),
49 ('', 'profile', None, _('print command execution profile')),
49 ('', 'profile', None, _('print command execution profile')),
50 ('', 'version', None, _('output version information and exit')),
50 ('', 'version', None, _('output version information and exit')),
51 ('h', 'help', None, _('display help and exit')),
51 ('h', 'help', None, _('display help and exit')),
52 ]
52 ]
53
53
54 dryrunopts = [('n', 'dry-run', None,
54 dryrunopts = [('n', 'dry-run', None,
55 _('do not perform actions, just print output'))]
55 _('do not perform actions, just print output'))]
56
56
57 remoteopts = [
57 remoteopts = [
58 ('e', 'ssh', '',
58 ('e', 'ssh', '',
59 _('specify ssh command to use'), _('CMD')),
59 _('specify ssh command to use'), _('CMD')),
60 ('', 'remotecmd', '',
60 ('', 'remotecmd', '',
61 _('specify hg command to run on the remote side'), _('CMD')),
61 _('specify hg command to run on the remote side'), _('CMD')),
62 ('', 'insecure', None,
62 ('', 'insecure', None,
63 _('do not verify server certificate (ignoring web.cacerts config)')),
63 _('do not verify server certificate (ignoring web.cacerts config)')),
64 ]
64 ]
65
65
66 walkopts = [
66 walkopts = [
67 ('I', 'include', [],
67 ('I', 'include', [],
68 _('include names matching the given patterns'), _('PATTERN')),
68 _('include names matching the given patterns'), _('PATTERN')),
69 ('X', 'exclude', [],
69 ('X', 'exclude', [],
70 _('exclude names matching the given patterns'), _('PATTERN')),
70 _('exclude names matching the given patterns'), _('PATTERN')),
71 ]
71 ]
72
72
73 commitopts = [
73 commitopts = [
74 ('m', 'message', '',
74 ('m', 'message', '',
75 _('use text as commit message'), _('TEXT')),
75 _('use text as commit message'), _('TEXT')),
76 ('l', 'logfile', '',
76 ('l', 'logfile', '',
77 _('read commit message from file'), _('FILE')),
77 _('read commit message from file'), _('FILE')),
78 ]
78 ]
79
79
80 commitopts2 = [
80 commitopts2 = [
81 ('d', 'date', '',
81 ('d', 'date', '',
82 _('record the specified date as commit date'), _('DATE')),
82 _('record the specified date as commit date'), _('DATE')),
83 ('u', 'user', '',
83 ('u', 'user', '',
84 _('record the specified user as committer'), _('USER')),
84 _('record the specified user as committer'), _('USER')),
85 ]
85 ]
86
86
87 templateopts = [
87 templateopts = [
88 ('', 'style', '',
88 ('', 'style', '',
89 _('display using template map file'), _('STYLE')),
89 _('display using template map file'), _('STYLE')),
90 ('', 'template', '',
90 ('', 'template', '',
91 _('display with template'), _('TEMPLATE')),
91 _('display with template'), _('TEMPLATE')),
92 ]
92 ]
93
93
94 logopts = [
94 logopts = [
95 ('p', 'patch', None, _('show patch')),
95 ('p', 'patch', None, _('show patch')),
96 ('g', 'git', None, _('use git extended diff format')),
96 ('g', 'git', None, _('use git extended diff format')),
97 ('l', 'limit', '',
97 ('l', 'limit', '',
98 _('limit number of changes displayed'), _('NUM')),
98 _('limit number of changes displayed'), _('NUM')),
99 ('M', 'no-merges', None, _('do not show merges')),
99 ('M', 'no-merges', None, _('do not show merges')),
100 ('', 'stat', None, _('output diffstat-style summary of changes')),
100 ('', 'stat', None, _('output diffstat-style summary of changes')),
101 ] + templateopts
101 ] + templateopts
102
102
103 diffopts = [
103 diffopts = [
104 ('a', 'text', None, _('treat all files as text')),
104 ('a', 'text', None, _('treat all files as text')),
105 ('g', 'git', None, _('use git extended diff format')),
105 ('g', 'git', None, _('use git extended diff format')),
106 ('', 'nodates', None, _('omit dates from diff headers'))
106 ('', 'nodates', None, _('omit dates from diff headers'))
107 ]
107 ]
108
108
109 diffwsopts = [
109 diffwsopts = [
110 ('w', 'ignore-all-space', None,
110 ('w', 'ignore-all-space', None,
111 _('ignore white space when comparing lines')),
111 _('ignore white space when comparing lines')),
112 ('b', 'ignore-space-change', None,
112 ('b', 'ignore-space-change', None,
113 _('ignore changes in the amount of white space')),
113 _('ignore changes in the amount of white space')),
114 ('B', 'ignore-blank-lines', None,
114 ('B', 'ignore-blank-lines', None,
115 _('ignore changes whose lines are all blank')),
115 _('ignore changes whose lines are all blank')),
116 ]
116 ]
117
117
118 diffopts2 = [
118 diffopts2 = [
119 ('p', 'show-function', None, _('show which function each change is in')),
119 ('p', 'show-function', None, _('show which function each change is in')),
120 ('', 'reverse', None, _('produce a diff that undoes the changes')),
120 ('', 'reverse', None, _('produce a diff that undoes the changes')),
121 ] + diffwsopts + [
121 ] + diffwsopts + [
122 ('U', 'unified', '',
122 ('U', 'unified', '',
123 _('number of lines of context to show'), _('NUM')),
123 _('number of lines of context to show'), _('NUM')),
124 ('', 'stat', None, _('output diffstat-style summary of changes')),
124 ('', 'stat', None, _('output diffstat-style summary of changes')),
125 ]
125 ]
126
126
127 mergetoolopts = [
127 mergetoolopts = [
128 ('t', 'tool', '', _('specify merge tool')),
128 ('t', 'tool', '', _('specify merge tool')),
129 ]
129 ]
130
130
131 similarityopts = [
131 similarityopts = [
132 ('s', 'similarity', '',
132 ('s', 'similarity', '',
133 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
133 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
134 ]
134 ]
135
135
136 subrepoopts = [
136 subrepoopts = [
137 ('S', 'subrepos', None,
137 ('S', 'subrepos', None,
138 _('recurse into subrepositories'))
138 _('recurse into subrepositories'))
139 ]
139 ]
140
140
141 # Commands start here, listed alphabetically
141 # Commands start here, listed alphabetically
142
142
143 @command('^add',
143 @command('^add',
144 walkopts + subrepoopts + dryrunopts,
144 walkopts + subrepoopts + dryrunopts,
145 _('[OPTION]... [FILE]...'))
145 _('[OPTION]... [FILE]...'))
146 def add(ui, repo, *pats, **opts):
146 def add(ui, repo, *pats, **opts):
147 """add the specified files on the next commit
147 """add the specified files on the next commit
148
148
149 Schedule files to be version controlled and added to the
149 Schedule files to be version controlled and added to the
150 repository.
150 repository.
151
151
152 The files will be added to the repository at the next commit. To
152 The files will be added to the repository at the next commit. To
153 undo an add before that, see :hg:`forget`.
153 undo an add before that, see :hg:`forget`.
154
154
155 If no names are given, add all files to the repository.
155 If no names are given, add all files to the repository.
156
156
157 .. container:: verbose
157 .. container:: verbose
158
158
159 An example showing how new (unknown) files are added
159 An example showing how new (unknown) files are added
160 automatically by :hg:`add`::
160 automatically by :hg:`add`::
161
161
162 $ ls
162 $ ls
163 foo.c
163 foo.c
164 $ hg status
164 $ hg status
165 ? foo.c
165 ? foo.c
166 $ hg add
166 $ hg add
167 adding foo.c
167 adding foo.c
168 $ hg status
168 $ hg status
169 A foo.c
169 A foo.c
170
170
171 Returns 0 if all files are successfully added.
171 Returns 0 if all files are successfully added.
172 """
172 """
173
173
174 m = scmutil.match(repo[None], pats, opts)
174 m = scmutil.match(repo[None], pats, opts)
175 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
175 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
176 opts.get('subrepos'), prefix="")
176 opts.get('subrepos'), prefix="")
177 return rejected and 1 or 0
177 return rejected and 1 or 0
178
178
179 @command('addremove',
179 @command('addremove',
180 similarityopts + walkopts + dryrunopts,
180 similarityopts + walkopts + dryrunopts,
181 _('[OPTION]... [FILE]...'))
181 _('[OPTION]... [FILE]...'))
182 def addremove(ui, repo, *pats, **opts):
182 def addremove(ui, repo, *pats, **opts):
183 """add all new files, delete all missing files
183 """add all new files, delete all missing files
184
184
185 Add all new files and remove all missing files from the
185 Add all new files and remove all missing files from the
186 repository.
186 repository.
187
187
188 New files are ignored if they match any of the patterns in
188 New files are ignored if they match any of the patterns in
189 ``.hgignore``. As with add, these changes take effect at the next
189 ``.hgignore``. As with add, these changes take effect at the next
190 commit.
190 commit.
191
191
192 Use the -s/--similarity option to detect renamed files. With a
192 Use the -s/--similarity option to detect renamed files. With a
193 parameter greater than 0, this compares every removed file with
193 parameter greater than 0, this compares every removed file with
194 every added file and records those similar enough as renames. This
194 every added file and records those similar enough as renames. This
195 option takes a percentage between 0 (disabled) and 100 (files must
195 option takes a percentage between 0 (disabled) and 100 (files must
196 be identical) as its parameter. Detecting renamed files this way
196 be identical) as its parameter. Detecting renamed files this way
197 can be expensive. After using this option, :hg:`status -C` can be
197 can be expensive. After using this option, :hg:`status -C` can be
198 used to check which files were identified as moved or renamed.
198 used to check which files were identified as moved or renamed.
199
199
200 Returns 0 if all files are successfully added.
200 Returns 0 if all files are successfully added.
201 """
201 """
202 try:
202 try:
203 sim = float(opts.get('similarity') or 100)
203 sim = float(opts.get('similarity') or 100)
204 except ValueError:
204 except ValueError:
205 raise util.Abort(_('similarity must be a number'))
205 raise util.Abort(_('similarity must be a number'))
206 if sim < 0 or sim > 100:
206 if sim < 0 or sim > 100:
207 raise util.Abort(_('similarity must be between 0 and 100'))
207 raise util.Abort(_('similarity must be between 0 and 100'))
208 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
208 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
209
209
210 @command('^annotate|blame',
210 @command('^annotate|blame',
211 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
211 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
212 ('', 'follow', None,
212 ('', 'follow', None,
213 _('follow copies/renames and list the filename (DEPRECATED)')),
213 _('follow copies/renames and list the filename (DEPRECATED)')),
214 ('', 'no-follow', None, _("don't follow copies and renames")),
214 ('', 'no-follow', None, _("don't follow copies and renames")),
215 ('a', 'text', None, _('treat all files as text')),
215 ('a', 'text', None, _('treat all files as text')),
216 ('u', 'user', None, _('list the author (long with -v)')),
216 ('u', 'user', None, _('list the author (long with -v)')),
217 ('f', 'file', None, _('list the filename')),
217 ('f', 'file', None, _('list the filename')),
218 ('d', 'date', None, _('list the date (short with -q)')),
218 ('d', 'date', None, _('list the date (short with -q)')),
219 ('n', 'number', None, _('list the revision number (default)')),
219 ('n', 'number', None, _('list the revision number (default)')),
220 ('c', 'changeset', None, _('list the changeset')),
220 ('c', 'changeset', None, _('list the changeset')),
221 ('l', 'line-number', None, _('show line number at the first appearance'))
221 ('l', 'line-number', None, _('show line number at the first appearance'))
222 ] + diffwsopts + walkopts,
222 ] + diffwsopts + walkopts,
223 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
223 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
224 def annotate(ui, repo, *pats, **opts):
224 def annotate(ui, repo, *pats, **opts):
225 """show changeset information by line for each file
225 """show changeset information by line for each file
226
226
227 List changes in files, showing the revision id responsible for
227 List changes in files, showing the revision id responsible for
228 each line
228 each line
229
229
230 This command is useful for discovering when a change was made and
230 This command is useful for discovering when a change was made and
231 by whom.
231 by whom.
232
232
233 Without the -a/--text option, annotate will avoid processing files
233 Without the -a/--text option, annotate will avoid processing files
234 it detects as binary. With -a, annotate will annotate the file
234 it detects as binary. With -a, annotate will annotate the file
235 anyway, although the results will probably be neither useful
235 anyway, although the results will probably be neither useful
236 nor desirable.
236 nor desirable.
237
237
238 Returns 0 on success.
238 Returns 0 on success.
239 """
239 """
240 if opts.get('follow'):
240 if opts.get('follow'):
241 # --follow is deprecated and now just an alias for -f/--file
241 # --follow is deprecated and now just an alias for -f/--file
242 # to mimic the behavior of Mercurial before version 1.5
242 # to mimic the behavior of Mercurial before version 1.5
243 opts['file'] = True
243 opts['file'] = True
244
244
245 datefunc = ui.quiet and util.shortdate or util.datestr
245 datefunc = ui.quiet and util.shortdate or util.datestr
246 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
246 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
247
247
248 if not pats:
248 if not pats:
249 raise util.Abort(_('at least one filename or pattern is required'))
249 raise util.Abort(_('at least one filename or pattern is required'))
250
250
251 hexfn = ui.debugflag and hex or short
251 hexfn = ui.debugflag and hex or short
252
252
253 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
253 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
254 ('number', ' ', lambda x: str(x[0].rev())),
254 ('number', ' ', lambda x: str(x[0].rev())),
255 ('changeset', ' ', lambda x: hexfn(x[0].node())),
255 ('changeset', ' ', lambda x: hexfn(x[0].node())),
256 ('date', ' ', getdate),
256 ('date', ' ', getdate),
257 ('file', ' ', lambda x: x[0].path()),
257 ('file', ' ', lambda x: x[0].path()),
258 ('line_number', ':', lambda x: str(x[1])),
258 ('line_number', ':', lambda x: str(x[1])),
259 ]
259 ]
260
260
261 if (not opts.get('user') and not opts.get('changeset')
261 if (not opts.get('user') and not opts.get('changeset')
262 and not opts.get('date') and not opts.get('file')):
262 and not opts.get('date') and not opts.get('file')):
263 opts['number'] = True
263 opts['number'] = True
264
264
265 linenumber = opts.get('line_number') is not None
265 linenumber = opts.get('line_number') is not None
266 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
266 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
267 raise util.Abort(_('at least one of -n/-c is required for -l'))
267 raise util.Abort(_('at least one of -n/-c is required for -l'))
268
268
269 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
269 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
270 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
270 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
271
271
272 def bad(x, y):
272 def bad(x, y):
273 raise util.Abort("%s: %s" % (x, y))
273 raise util.Abort("%s: %s" % (x, y))
274
274
275 ctx = scmutil.revsingle(repo, opts.get('rev'))
275 ctx = scmutil.revsingle(repo, opts.get('rev'))
276 m = scmutil.match(ctx, pats, opts)
276 m = scmutil.match(ctx, pats, opts)
277 m.bad = bad
277 m.bad = bad
278 follow = not opts.get('no_follow')
278 follow = not opts.get('no_follow')
279 diffopts = patch.diffopts(ui, opts, section='annotate')
279 diffopts = patch.diffopts(ui, opts, section='annotate')
280 for abs in ctx.walk(m):
280 for abs in ctx.walk(m):
281 fctx = ctx[abs]
281 fctx = ctx[abs]
282 if not opts.get('text') and util.binary(fctx.data()):
282 if not opts.get('text') and util.binary(fctx.data()):
283 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
283 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
284 continue
284 continue
285
285
286 lines = fctx.annotate(follow=follow, linenumber=linenumber,
286 lines = fctx.annotate(follow=follow, linenumber=linenumber,
287 diffopts=diffopts)
287 diffopts=diffopts)
288 pieces = []
288 pieces = []
289
289
290 for f, sep in funcmap:
290 for f, sep in funcmap:
291 l = [f(n) for n, dummy in lines]
291 l = [f(n) for n, dummy in lines]
292 if l:
292 if l:
293 sized = [(x, encoding.colwidth(x)) for x in l]
293 sized = [(x, encoding.colwidth(x)) for x in l]
294 ml = max([w for x, w in sized])
294 ml = max([w for x, w in sized])
295 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
295 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
296 for x, w in sized])
296 for x, w in sized])
297
297
298 if pieces:
298 if pieces:
299 for p, l in zip(zip(*pieces), lines):
299 for p, l in zip(zip(*pieces), lines):
300 ui.write("%s: %s" % ("".join(p), l[1]))
300 ui.write("%s: %s" % ("".join(p), l[1]))
301
301
302 @command('archive',
302 @command('archive',
303 [('', 'no-decode', None, _('do not pass files through decoders')),
303 [('', 'no-decode', None, _('do not pass files through decoders')),
304 ('p', 'prefix', '', _('directory prefix for files in archive'),
304 ('p', 'prefix', '', _('directory prefix for files in archive'),
305 _('PREFIX')),
305 _('PREFIX')),
306 ('r', 'rev', '', _('revision to distribute'), _('REV')),
306 ('r', 'rev', '', _('revision to distribute'), _('REV')),
307 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
307 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
308 ] + subrepoopts + walkopts,
308 ] + subrepoopts + walkopts,
309 _('[OPTION]... DEST'))
309 _('[OPTION]... DEST'))
310 def archive(ui, repo, dest, **opts):
310 def archive(ui, repo, dest, **opts):
311 '''create an unversioned archive of a repository revision
311 '''create an unversioned archive of a repository revision
312
312
313 By default, the revision used is the parent of the working
313 By default, the revision used is the parent of the working
314 directory; use -r/--rev to specify a different revision.
314 directory; use -r/--rev to specify a different revision.
315
315
316 The archive type is automatically detected based on file
316 The archive type is automatically detected based on file
317 extension (or override using -t/--type).
317 extension (or override using -t/--type).
318
318
319 .. container:: verbose
319 .. container:: verbose
320
320
321 Examples:
321 Examples:
322
322
323 - create a zip file containing the 1.0 release::
323 - create a zip file containing the 1.0 release::
324
324
325 hg archive -r 1.0 project-1.0.zip
325 hg archive -r 1.0 project-1.0.zip
326
326
327 - create a tarball excluding .hg files::
327 - create a tarball excluding .hg files::
328
328
329 hg archive project.tar.gz -X ".hg*"
329 hg archive project.tar.gz -X ".hg*"
330
330
331 Valid types are:
331 Valid types are:
332
332
333 :``files``: a directory full of files (default)
333 :``files``: a directory full of files (default)
334 :``tar``: tar archive, uncompressed
334 :``tar``: tar archive, uncompressed
335 :``tbz2``: tar archive, compressed using bzip2
335 :``tbz2``: tar archive, compressed using bzip2
336 :``tgz``: tar archive, compressed using gzip
336 :``tgz``: tar archive, compressed using gzip
337 :``uzip``: zip archive, uncompressed
337 :``uzip``: zip archive, uncompressed
338 :``zip``: zip archive, compressed using deflate
338 :``zip``: zip archive, compressed using deflate
339
339
340 The exact name of the destination archive or directory is given
340 The exact name of the destination archive or directory is given
341 using a format string; see :hg:`help export` for details.
341 using a format string; see :hg:`help export` for details.
342
342
343 Each member added to an archive file has a directory prefix
343 Each member added to an archive file has a directory prefix
344 prepended. Use -p/--prefix to specify a format string for the
344 prepended. Use -p/--prefix to specify a format string for the
345 prefix. The default is the basename of the archive, with suffixes
345 prefix. The default is the basename of the archive, with suffixes
346 removed.
346 removed.
347
347
348 Returns 0 on success.
348 Returns 0 on success.
349 '''
349 '''
350
350
351 ctx = scmutil.revsingle(repo, opts.get('rev'))
351 ctx = scmutil.revsingle(repo, opts.get('rev'))
352 if not ctx:
352 if not ctx:
353 raise util.Abort(_('no working directory: please specify a revision'))
353 raise util.Abort(_('no working directory: please specify a revision'))
354 node = ctx.node()
354 node = ctx.node()
355 dest = cmdutil.makefilename(repo, dest, node)
355 dest = cmdutil.makefilename(repo, dest, node)
356 if os.path.realpath(dest) == repo.root:
356 if os.path.realpath(dest) == repo.root:
357 raise util.Abort(_('repository root cannot be destination'))
357 raise util.Abort(_('repository root cannot be destination'))
358
358
359 kind = opts.get('type') or archival.guesskind(dest) or 'files'
359 kind = opts.get('type') or archival.guesskind(dest) or 'files'
360 prefix = opts.get('prefix')
360 prefix = opts.get('prefix')
361
361
362 if dest == '-':
362 if dest == '-':
363 if kind == 'files':
363 if kind == 'files':
364 raise util.Abort(_('cannot archive plain files to stdout'))
364 raise util.Abort(_('cannot archive plain files to stdout'))
365 dest = cmdutil.makefileobj(repo, dest)
365 dest = cmdutil.makefileobj(repo, dest)
366 if not prefix:
366 if not prefix:
367 prefix = os.path.basename(repo.root) + '-%h'
367 prefix = os.path.basename(repo.root) + '-%h'
368
368
369 prefix = cmdutil.makefilename(repo, prefix, node)
369 prefix = cmdutil.makefilename(repo, prefix, node)
370 matchfn = scmutil.match(ctx, [], opts)
370 matchfn = scmutil.match(ctx, [], opts)
371 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
371 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
372 matchfn, prefix, subrepos=opts.get('subrepos'))
372 matchfn, prefix, subrepos=opts.get('subrepos'))
373
373
374 @command('backout',
374 @command('backout',
375 [('', 'merge', None, _('merge with old dirstate parent after backout')),
375 [('', 'merge', None, _('merge with old dirstate parent after backout')),
376 ('', 'parent', '',
376 ('', 'parent', '',
377 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
377 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
378 ('r', 'rev', '', _('revision to backout'), _('REV')),
378 ('r', 'rev', '', _('revision to backout'), _('REV')),
379 ] + mergetoolopts + walkopts + commitopts + commitopts2,
379 ] + mergetoolopts + walkopts + commitopts + commitopts2,
380 _('[OPTION]... [-r] REV'))
380 _('[OPTION]... [-r] REV'))
381 def backout(ui, repo, node=None, rev=None, **opts):
381 def backout(ui, repo, node=None, rev=None, **opts):
382 '''reverse effect of earlier changeset
382 '''reverse effect of earlier changeset
383
383
384 Prepare a new changeset with the effect of REV undone in the
384 Prepare a new changeset with the effect of REV undone in the
385 current working directory.
385 current working directory.
386
386
387 If REV is the parent of the working directory, then this new changeset
387 If REV is the parent of the working directory, then this new changeset
388 is committed automatically. Otherwise, hg needs to merge the
388 is committed automatically. Otherwise, hg needs to merge the
389 changes and the merged result is left uncommitted.
389 changes and the merged result is left uncommitted.
390
390
391 .. note::
391 .. note::
392 backout cannot be used to fix either an unwanted or
392 backout cannot be used to fix either an unwanted or
393 incorrect merge.
393 incorrect merge.
394
394
395 .. container:: verbose
395 .. container:: verbose
396
396
397 By default, the pending changeset will have one parent,
397 By default, the pending changeset will have one parent,
398 maintaining a linear history. With --merge, the pending
398 maintaining a linear history. With --merge, the pending
399 changeset will instead have two parents: the old parent of the
399 changeset will instead have two parents: the old parent of the
400 working directory and a new child of REV that simply undoes REV.
400 working directory and a new child of REV that simply undoes REV.
401
401
402 Before version 1.7, the behavior without --merge was equivalent
402 Before version 1.7, the behavior without --merge was equivalent
403 to specifying --merge followed by :hg:`update --clean .` to
403 to specifying --merge followed by :hg:`update --clean .` to
404 cancel the merge and leave the child of REV as a head to be
404 cancel the merge and leave the child of REV as a head to be
405 merged separately.
405 merged separately.
406
406
407 See :hg:`help dates` for a list of formats valid for -d/--date.
407 See :hg:`help dates` for a list of formats valid for -d/--date.
408
408
409 Returns 0 on success.
409 Returns 0 on success.
410 '''
410 '''
411 if rev and node:
411 if rev and node:
412 raise util.Abort(_("please specify just one revision"))
412 raise util.Abort(_("please specify just one revision"))
413
413
414 if not rev:
414 if not rev:
415 rev = node
415 rev = node
416
416
417 if not rev:
417 if not rev:
418 raise util.Abort(_("please specify a revision to backout"))
418 raise util.Abort(_("please specify a revision to backout"))
419
419
420 date = opts.get('date')
420 date = opts.get('date')
421 if date:
421 if date:
422 opts['date'] = util.parsedate(date)
422 opts['date'] = util.parsedate(date)
423
423
424 cmdutil.bailifchanged(repo)
424 cmdutil.bailifchanged(repo)
425 node = scmutil.revsingle(repo, rev).node()
425 node = scmutil.revsingle(repo, rev).node()
426
426
427 op1, op2 = repo.dirstate.parents()
427 op1, op2 = repo.dirstate.parents()
428 a = repo.changelog.ancestor(op1, node)
428 a = repo.changelog.ancestor(op1, node)
429 if a != node:
429 if a != node:
430 raise util.Abort(_('cannot backout change on a different branch'))
430 raise util.Abort(_('cannot backout change on a different branch'))
431
431
432 p1, p2 = repo.changelog.parents(node)
432 p1, p2 = repo.changelog.parents(node)
433 if p1 == nullid:
433 if p1 == nullid:
434 raise util.Abort(_('cannot backout a change with no parents'))
434 raise util.Abort(_('cannot backout a change with no parents'))
435 if p2 != nullid:
435 if p2 != nullid:
436 if not opts.get('parent'):
436 if not opts.get('parent'):
437 raise util.Abort(_('cannot backout a merge changeset'))
437 raise util.Abort(_('cannot backout a merge changeset'))
438 p = repo.lookup(opts['parent'])
438 p = repo.lookup(opts['parent'])
439 if p not in (p1, p2):
439 if p not in (p1, p2):
440 raise util.Abort(_('%s is not a parent of %s') %
440 raise util.Abort(_('%s is not a parent of %s') %
441 (short(p), short(node)))
441 (short(p), short(node)))
442 parent = p
442 parent = p
443 else:
443 else:
444 if opts.get('parent'):
444 if opts.get('parent'):
445 raise util.Abort(_('cannot use --parent on non-merge changeset'))
445 raise util.Abort(_('cannot use --parent on non-merge changeset'))
446 parent = p1
446 parent = p1
447
447
448 # the backout should appear on the same branch
448 # the backout should appear on the same branch
449 branch = repo.dirstate.branch()
449 branch = repo.dirstate.branch()
450 hg.clean(repo, node, show_stats=False)
450 hg.clean(repo, node, show_stats=False)
451 repo.dirstate.setbranch(branch)
451 repo.dirstate.setbranch(branch)
452 revert_opts = opts.copy()
452 revert_opts = opts.copy()
453 revert_opts['date'] = None
453 revert_opts['date'] = None
454 revert_opts['all'] = True
454 revert_opts['all'] = True
455 revert_opts['rev'] = hex(parent)
455 revert_opts['rev'] = hex(parent)
456 revert_opts['no_backup'] = None
456 revert_opts['no_backup'] = None
457 revert(ui, repo, **revert_opts)
457 revert(ui, repo, **revert_opts)
458 if not opts.get('merge') and op1 != node:
458 if not opts.get('merge') and op1 != node:
459 try:
459 try:
460 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
460 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
461 return hg.update(repo, op1)
461 return hg.update(repo, op1)
462 finally:
462 finally:
463 ui.setconfig('ui', 'forcemerge', '')
463 ui.setconfig('ui', 'forcemerge', '')
464
464
465 commit_opts = opts.copy()
465 commit_opts = opts.copy()
466 commit_opts['addremove'] = False
466 commit_opts['addremove'] = False
467 if not commit_opts['message'] and not commit_opts['logfile']:
467 if not commit_opts['message'] and not commit_opts['logfile']:
468 # we don't translate commit messages
468 # we don't translate commit messages
469 commit_opts['message'] = "Backed out changeset %s" % short(node)
469 commit_opts['message'] = "Backed out changeset %s" % short(node)
470 commit_opts['force_editor'] = True
470 commit_opts['force_editor'] = True
471 commit(ui, repo, **commit_opts)
471 commit(ui, repo, **commit_opts)
472 def nice(node):
472 def nice(node):
473 return '%d:%s' % (repo.changelog.rev(node), short(node))
473 return '%d:%s' % (repo.changelog.rev(node), short(node))
474 ui.status(_('changeset %s backs out changeset %s\n') %
474 ui.status(_('changeset %s backs out changeset %s\n') %
475 (nice(repo.changelog.tip()), nice(node)))
475 (nice(repo.changelog.tip()), nice(node)))
476 if opts.get('merge') and op1 != node:
476 if opts.get('merge') and op1 != node:
477 hg.clean(repo, op1, show_stats=False)
477 hg.clean(repo, op1, show_stats=False)
478 ui.status(_('merging with changeset %s\n')
478 ui.status(_('merging with changeset %s\n')
479 % nice(repo.changelog.tip()))
479 % nice(repo.changelog.tip()))
480 try:
480 try:
481 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
481 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
482 return hg.merge(repo, hex(repo.changelog.tip()))
482 return hg.merge(repo, hex(repo.changelog.tip()))
483 finally:
483 finally:
484 ui.setconfig('ui', 'forcemerge', '')
484 ui.setconfig('ui', 'forcemerge', '')
485 return 0
485 return 0
486
486
487 @command('bisect',
487 @command('bisect',
488 [('r', 'reset', False, _('reset bisect state')),
488 [('r', 'reset', False, _('reset bisect state')),
489 ('g', 'good', False, _('mark changeset good')),
489 ('g', 'good', False, _('mark changeset good')),
490 ('b', 'bad', False, _('mark changeset bad')),
490 ('b', 'bad', False, _('mark changeset bad')),
491 ('s', 'skip', False, _('skip testing changeset')),
491 ('s', 'skip', False, _('skip testing changeset')),
492 ('e', 'extend', False, _('extend the bisect range')),
492 ('e', 'extend', False, _('extend the bisect range')),
493 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
493 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
494 ('U', 'noupdate', False, _('do not update to target'))],
494 ('U', 'noupdate', False, _('do not update to target'))],
495 _("[-gbsr] [-U] [-c CMD] [REV]"))
495 _("[-gbsr] [-U] [-c CMD] [REV]"))
496 def bisect(ui, repo, rev=None, extra=None, command=None,
496 def bisect(ui, repo, rev=None, extra=None, command=None,
497 reset=None, good=None, bad=None, skip=None, extend=None,
497 reset=None, good=None, bad=None, skip=None, extend=None,
498 noupdate=None):
498 noupdate=None):
499 """subdivision search of changesets
499 """subdivision search of changesets
500
500
501 This command helps to find changesets which introduce problems. To
501 This command helps to find changesets which introduce problems. To
502 use, mark the earliest changeset you know exhibits the problem as
502 use, mark the earliest changeset you know exhibits the problem as
503 bad, then mark the latest changeset which is free from the problem
503 bad, then mark the latest changeset which is free from the problem
504 as good. Bisect will update your working directory to a revision
504 as good. Bisect will update your working directory to a revision
505 for testing (unless the -U/--noupdate option is specified). Once
505 for testing (unless the -U/--noupdate option is specified). Once
506 you have performed tests, mark the working directory as good or
506 you have performed tests, mark the working directory as good or
507 bad, and bisect will either update to another candidate changeset
507 bad, and bisect will either update to another candidate changeset
508 or announce that it has found the bad revision.
508 or announce that it has found the bad revision.
509
509
510 As a shortcut, you can also use the revision argument to mark a
510 As a shortcut, you can also use the revision argument to mark a
511 revision as good or bad without checking it out first.
511 revision as good or bad without checking it out first.
512
512
513 If you supply a command, it will be used for automatic bisection.
513 If you supply a command, it will be used for automatic bisection.
514 Its exit status will be used to mark revisions as good or bad:
514 Its exit status will be used to mark revisions as good or bad:
515 status 0 means good, 125 means to skip the revision, 127
515 status 0 means good, 125 means to skip the revision, 127
516 (command not found) will abort the bisection, and any other
516 (command not found) will abort the bisection, and any other
517 non-zero exit status means the revision is bad.
517 non-zero exit status means the revision is bad.
518
518
519 .. container:: verbose
519 .. container:: verbose
520
520
521 Some examples:
521 Some examples:
522
522
523 - start a bisection with known bad revision 12, and good revision 34::
523 - start a bisection with known bad revision 12, and good revision 34::
524
524
525 hg bisect --bad 34
525 hg bisect --bad 34
526 hg bisect --good 12
526 hg bisect --good 12
527
527
528 - advance the current bisection by marking current revision as good or
528 - advance the current bisection by marking current revision as good or
529 bad::
529 bad::
530
530
531 hg bisect --good
531 hg bisect --good
532 hg bisect --bad
532 hg bisect --bad
533
533
534 - mark the current revision, or a known revision, to be skipped (eg. if
534 - mark the current revision, or a known revision, to be skipped (eg. if
535 that revision is not usable because of another issue)::
535 that revision is not usable because of another issue)::
536
536
537 hg bisect --skip
537 hg bisect --skip
538 hg bisect --skip 23
538 hg bisect --skip 23
539
539
540 - forget the current bisection::
540 - forget the current bisection::
541
541
542 hg bisect --reset
542 hg bisect --reset
543
543
544 - use 'make && make tests' to automatically find the first broken
544 - use 'make && make tests' to automatically find the first broken
545 revision::
545 revision::
546
546
547 hg bisect --reset
547 hg bisect --reset
548 hg bisect --bad 34
548 hg bisect --bad 34
549 hg bisect --good 12
549 hg bisect --good 12
550 hg bisect --command 'make && make tests'
550 hg bisect --command 'make && make tests'
551
551
552 - see all changesets whose states are already known in the current
552 - see all changesets whose states are already known in the current
553 bisection::
553 bisection::
554
554
555 hg log -r "bisect(pruned)"
555 hg log -r "bisect(pruned)"
556
556
557 - see all changesets that took part in the current bisection::
557 - see all changesets that took part in the current bisection::
558
558
559 hg log -r "bisect(range)"
559 hg log -r "bisect(range)"
560
560
561 - with the graphlog extension, you can even get a nice graph::
561 - with the graphlog extension, you can even get a nice graph::
562
562
563 hg log --graph -r "bisect(range)"
563 hg log --graph -r "bisect(range)"
564
564
565 See :hg:`help revsets` for more about the `bisect()` keyword.
565 See :hg:`help revsets` for more about the `bisect()` keyword.
566
566
567 Returns 0 on success.
567 Returns 0 on success.
568 """
568 """
569 def extendbisectrange(nodes, good):
569 def extendbisectrange(nodes, good):
570 # bisect is incomplete when it ends on a merge node and
570 # bisect is incomplete when it ends on a merge node and
571 # one of the parent was not checked.
571 # one of the parent was not checked.
572 parents = repo[nodes[0]].parents()
572 parents = repo[nodes[0]].parents()
573 if len(parents) > 1:
573 if len(parents) > 1:
574 side = good and state['bad'] or state['good']
574 side = good and state['bad'] or state['good']
575 num = len(set(i.node() for i in parents) & set(side))
575 num = len(set(i.node() for i in parents) & set(side))
576 if num == 1:
576 if num == 1:
577 return parents[0].ancestor(parents[1])
577 return parents[0].ancestor(parents[1])
578 return None
578 return None
579
579
580 def print_result(nodes, good):
580 def print_result(nodes, good):
581 displayer = cmdutil.show_changeset(ui, repo, {})
581 displayer = cmdutil.show_changeset(ui, repo, {})
582 if len(nodes) == 1:
582 if len(nodes) == 1:
583 # narrowed it down to a single revision
583 # narrowed it down to a single revision
584 if good:
584 if good:
585 ui.write(_("The first good revision is:\n"))
585 ui.write(_("The first good revision is:\n"))
586 else:
586 else:
587 ui.write(_("The first bad revision is:\n"))
587 ui.write(_("The first bad revision is:\n"))
588 displayer.show(repo[nodes[0]])
588 displayer.show(repo[nodes[0]])
589 extendnode = extendbisectrange(nodes, good)
589 extendnode = extendbisectrange(nodes, good)
590 if extendnode is not None:
590 if extendnode is not None:
591 ui.write(_('Not all ancestors of this changeset have been'
591 ui.write(_('Not all ancestors of this changeset have been'
592 ' checked.\nUse bisect --extend to continue the '
592 ' checked.\nUse bisect --extend to continue the '
593 'bisection from\nthe common ancestor, %s.\n')
593 'bisection from\nthe common ancestor, %s.\n')
594 % extendnode)
594 % extendnode)
595 else:
595 else:
596 # multiple possible revisions
596 # multiple possible revisions
597 if good:
597 if good:
598 ui.write(_("Due to skipped revisions, the first "
598 ui.write(_("Due to skipped revisions, the first "
599 "good revision could be any of:\n"))
599 "good revision could be any of:\n"))
600 else:
600 else:
601 ui.write(_("Due to skipped revisions, the first "
601 ui.write(_("Due to skipped revisions, the first "
602 "bad revision could be any of:\n"))
602 "bad revision could be any of:\n"))
603 for n in nodes:
603 for n in nodes:
604 displayer.show(repo[n])
604 displayer.show(repo[n])
605 displayer.close()
605 displayer.close()
606
606
607 def check_state(state, interactive=True):
607 def check_state(state, interactive=True):
608 if not state['good'] or not state['bad']:
608 if not state['good'] or not state['bad']:
609 if (good or bad or skip or reset) and interactive:
609 if (good or bad or skip or reset) and interactive:
610 return
610 return
611 if not state['good']:
611 if not state['good']:
612 raise util.Abort(_('cannot bisect (no known good revisions)'))
612 raise util.Abort(_('cannot bisect (no known good revisions)'))
613 else:
613 else:
614 raise util.Abort(_('cannot bisect (no known bad revisions)'))
614 raise util.Abort(_('cannot bisect (no known bad revisions)'))
615 return True
615 return True
616
616
617 # backward compatibility
617 # backward compatibility
618 if rev in "good bad reset init".split():
618 if rev in "good bad reset init".split():
619 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
619 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
620 cmd, rev, extra = rev, extra, None
620 cmd, rev, extra = rev, extra, None
621 if cmd == "good":
621 if cmd == "good":
622 good = True
622 good = True
623 elif cmd == "bad":
623 elif cmd == "bad":
624 bad = True
624 bad = True
625 else:
625 else:
626 reset = True
626 reset = True
627 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
627 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
628 raise util.Abort(_('incompatible arguments'))
628 raise util.Abort(_('incompatible arguments'))
629
629
630 if reset:
630 if reset:
631 p = repo.join("bisect.state")
631 p = repo.join("bisect.state")
632 if os.path.exists(p):
632 if os.path.exists(p):
633 os.unlink(p)
633 os.unlink(p)
634 return
634 return
635
635
636 state = hbisect.load_state(repo)
636 state = hbisect.load_state(repo)
637
637
638 if command:
638 if command:
639 changesets = 1
639 changesets = 1
640 try:
640 try:
641 while changesets:
641 while changesets:
642 # update state
642 # update state
643 status = util.system(command, out=ui.fout)
643 status = util.system(command, out=ui.fout)
644 if status == 125:
644 if status == 125:
645 transition = "skip"
645 transition = "skip"
646 elif status == 0:
646 elif status == 0:
647 transition = "good"
647 transition = "good"
648 # status < 0 means process was killed
648 # status < 0 means process was killed
649 elif status == 127:
649 elif status == 127:
650 raise util.Abort(_("failed to execute %s") % command)
650 raise util.Abort(_("failed to execute %s") % command)
651 elif status < 0:
651 elif status < 0:
652 raise util.Abort(_("%s killed") % command)
652 raise util.Abort(_("%s killed") % command)
653 else:
653 else:
654 transition = "bad"
654 transition = "bad"
655 ctx = scmutil.revsingle(repo, rev)
655 ctx = scmutil.revsingle(repo, rev)
656 rev = None # clear for future iterations
656 rev = None # clear for future iterations
657 state[transition].append(ctx.node())
657 state[transition].append(ctx.node())
658 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
658 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
659 check_state(state, interactive=False)
659 check_state(state, interactive=False)
660 # bisect
660 # bisect
661 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
661 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
662 # update to next check
662 # update to next check
663 cmdutil.bailifchanged(repo)
663 cmdutil.bailifchanged(repo)
664 hg.clean(repo, nodes[0], show_stats=False)
664 hg.clean(repo, nodes[0], show_stats=False)
665 finally:
665 finally:
666 hbisect.save_state(repo, state)
666 hbisect.save_state(repo, state)
667 print_result(nodes, good)
667 print_result(nodes, good)
668 return
668 return
669
669
670 # update state
670 # update state
671
671
672 if rev:
672 if rev:
673 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
673 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
674 else:
674 else:
675 nodes = [repo.lookup('.')]
675 nodes = [repo.lookup('.')]
676
676
677 if good or bad or skip:
677 if good or bad or skip:
678 if good:
678 if good:
679 state['good'] += nodes
679 state['good'] += nodes
680 elif bad:
680 elif bad:
681 state['bad'] += nodes
681 state['bad'] += nodes
682 elif skip:
682 elif skip:
683 state['skip'] += nodes
683 state['skip'] += nodes
684 hbisect.save_state(repo, state)
684 hbisect.save_state(repo, state)
685
685
686 if not check_state(state):
686 if not check_state(state):
687 return
687 return
688
688
689 # actually bisect
689 # actually bisect
690 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
690 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
691 if extend:
691 if extend:
692 if not changesets:
692 if not changesets:
693 extendnode = extendbisectrange(nodes, good)
693 extendnode = extendbisectrange(nodes, good)
694 if extendnode is not None:
694 if extendnode is not None:
695 ui.write(_("Extending search to changeset %d:%s\n"
695 ui.write(_("Extending search to changeset %d:%s\n"
696 % (extendnode.rev(), extendnode)))
696 % (extendnode.rev(), extendnode)))
697 if noupdate:
697 if noupdate:
698 return
698 return
699 cmdutil.bailifchanged(repo)
699 cmdutil.bailifchanged(repo)
700 return hg.clean(repo, extendnode.node())
700 return hg.clean(repo, extendnode.node())
701 raise util.Abort(_("nothing to extend"))
701 raise util.Abort(_("nothing to extend"))
702
702
703 if changesets == 0:
703 if changesets == 0:
704 print_result(nodes, good)
704 print_result(nodes, good)
705 else:
705 else:
706 assert len(nodes) == 1 # only a single node can be tested next
706 assert len(nodes) == 1 # only a single node can be tested next
707 node = nodes[0]
707 node = nodes[0]
708 # compute the approximate number of remaining tests
708 # compute the approximate number of remaining tests
709 tests, size = 0, 2
709 tests, size = 0, 2
710 while size <= changesets:
710 while size <= changesets:
711 tests, size = tests + 1, size * 2
711 tests, size = tests + 1, size * 2
712 rev = repo.changelog.rev(node)
712 rev = repo.changelog.rev(node)
713 ui.write(_("Testing changeset %d:%s "
713 ui.write(_("Testing changeset %d:%s "
714 "(%d changesets remaining, ~%d tests)\n")
714 "(%d changesets remaining, ~%d tests)\n")
715 % (rev, short(node), changesets, tests))
715 % (rev, short(node), changesets, tests))
716 if not noupdate:
716 if not noupdate:
717 cmdutil.bailifchanged(repo)
717 cmdutil.bailifchanged(repo)
718 return hg.clean(repo, node)
718 return hg.clean(repo, node)
719
719
720 @command('bookmarks',
720 @command('bookmarks',
721 [('f', 'force', False, _('force')),
721 [('f', 'force', False, _('force')),
722 ('r', 'rev', '', _('revision'), _('REV')),
722 ('r', 'rev', '', _('revision'), _('REV')),
723 ('d', 'delete', False, _('delete a given bookmark')),
723 ('d', 'delete', False, _('delete a given bookmark')),
724 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
724 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
725 ('i', 'inactive', False, _('do not mark a new bookmark active'))],
725 ('i', 'inactive', False, _('do not mark a new bookmark active'))],
726 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
726 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
727 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
727 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
728 rename=None, inactive=False):
728 rename=None, inactive=False):
729 '''track a line of development with movable markers
729 '''track a line of development with movable markers
730
730
731 Bookmarks are pointers to certain commits that move when committing.
731 Bookmarks are pointers to certain commits that move when committing.
732 Bookmarks are local. They can be renamed, copied and deleted. It is
732 Bookmarks are local. They can be renamed, copied and deleted. It is
733 possible to use :hg:`merge NAME` to merge from a given bookmark, and
733 possible to use :hg:`merge NAME` to merge from a given bookmark, and
734 :hg:`update NAME` to update to a given bookmark.
734 :hg:`update NAME` to update to a given bookmark.
735
735
736 You can use :hg:`bookmark NAME` to set a bookmark on the working
736 You can use :hg:`bookmark NAME` to set a bookmark on the working
737 directory's parent revision with the given name. If you specify
737 directory's parent revision with the given name. If you specify
738 a revision using -r REV (where REV may be an existing bookmark),
738 a revision using -r REV (where REV may be an existing bookmark),
739 the bookmark is assigned to that revision.
739 the bookmark is assigned to that revision.
740
740
741 Bookmarks can be pushed and pulled between repositories (see :hg:`help
741 Bookmarks can be pushed and pulled between repositories (see :hg:`help
742 push` and :hg:`help pull`). This requires both the local and remote
742 push` and :hg:`help pull`). This requires both the local and remote
743 repositories to support bookmarks. For versions prior to 1.8, this means
743 repositories to support bookmarks. For versions prior to 1.8, this means
744 the bookmarks extension must be enabled.
744 the bookmarks extension must be enabled.
745 '''
745 '''
746 hexfn = ui.debugflag and hex or short
746 hexfn = ui.debugflag and hex or short
747 marks = repo._bookmarks
747 marks = repo._bookmarks
748 cur = repo.changectx('.').node()
748 cur = repo.changectx('.').node()
749
749
750 if delete:
750 if delete:
751 if mark is None:
751 if mark is None:
752 raise util.Abort(_("bookmark name required"))
752 raise util.Abort(_("bookmark name required"))
753 if mark not in marks:
753 if mark not in marks:
754 raise util.Abort(_("bookmark '%s' does not exist") % mark)
754 raise util.Abort(_("bookmark '%s' does not exist") % mark)
755 if mark == repo._bookmarkcurrent:
755 if mark == repo._bookmarkcurrent:
756 bookmarks.setcurrent(repo, None)
756 bookmarks.setcurrent(repo, None)
757 del marks[mark]
757 del marks[mark]
758 bookmarks.write(repo)
758 bookmarks.write(repo)
759 return
759 return
760
760
761 if rename:
761 if rename:
762 if rename not in marks:
762 if rename not in marks:
763 raise util.Abort(_("bookmark '%s' does not exist") % rename)
763 raise util.Abort(_("bookmark '%s' does not exist") % rename)
764 if mark in marks and not force:
764 if mark in marks and not force:
765 raise util.Abort(_("bookmark '%s' already exists "
765 raise util.Abort(_("bookmark '%s' already exists "
766 "(use -f to force)") % mark)
766 "(use -f to force)") % mark)
767 if mark is None:
767 if mark is None:
768 raise util.Abort(_("new bookmark name required"))
768 raise util.Abort(_("new bookmark name required"))
769 marks[mark] = marks[rename]
769 marks[mark] = marks[rename]
770 if repo._bookmarkcurrent == rename and not inactive:
770 if repo._bookmarkcurrent == rename and not inactive:
771 bookmarks.setcurrent(repo, mark)
771 bookmarks.setcurrent(repo, mark)
772 del marks[rename]
772 del marks[rename]
773 bookmarks.write(repo)
773 bookmarks.write(repo)
774 return
774 return
775
775
776 if mark is not None:
776 if mark is not None:
777 if "\n" in mark:
777 if "\n" in mark:
778 raise util.Abort(_("bookmark name cannot contain newlines"))
778 raise util.Abort(_("bookmark name cannot contain newlines"))
779 mark = mark.strip()
779 mark = mark.strip()
780 if not mark:
780 if not mark:
781 raise util.Abort(_("bookmark names cannot consist entirely of "
781 raise util.Abort(_("bookmark names cannot consist entirely of "
782 "whitespace"))
782 "whitespace"))
783 if inactive and mark == repo._bookmarkcurrent:
783 if inactive and mark == repo._bookmarkcurrent:
784 bookmarks.setcurrent(repo, None)
784 bookmarks.setcurrent(repo, None)
785 return
785 return
786 if mark in marks and not force:
786 if mark in marks and not force:
787 raise util.Abort(_("bookmark '%s' already exists "
787 raise util.Abort(_("bookmark '%s' already exists "
788 "(use -f to force)") % mark)
788 "(use -f to force)") % mark)
789 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
789 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
790 and not force):
790 and not force):
791 raise util.Abort(
791 raise util.Abort(
792 _("a bookmark cannot have the name of an existing branch"))
792 _("a bookmark cannot have the name of an existing branch"))
793 if rev:
793 if rev:
794 marks[mark] = repo.lookup(rev)
794 marks[mark] = repo.lookup(rev)
795 else:
795 else:
796 marks[mark] = cur
796 marks[mark] = cur
797 if not inactive and cur == marks[mark]:
797 if not inactive and cur == marks[mark]:
798 bookmarks.setcurrent(repo, mark)
798 bookmarks.setcurrent(repo, mark)
799 bookmarks.write(repo)
799 bookmarks.write(repo)
800 return
800 return
801
801
802 if mark is None:
802 if mark is None:
803 if rev:
803 if rev:
804 raise util.Abort(_("bookmark name required"))
804 raise util.Abort(_("bookmark name required"))
805 if len(marks) == 0:
805 if len(marks) == 0:
806 ui.status(_("no bookmarks set\n"))
806 ui.status(_("no bookmarks set\n"))
807 else:
807 else:
808 for bmark, n in sorted(marks.iteritems()):
808 for bmark, n in sorted(marks.iteritems()):
809 current = repo._bookmarkcurrent
809 current = repo._bookmarkcurrent
810 if bmark == current and n == cur:
810 if bmark == current and n == cur:
811 prefix, label = '*', 'bookmarks.current'
811 prefix, label = '*', 'bookmarks.current'
812 else:
812 else:
813 prefix, label = ' ', ''
813 prefix, label = ' ', ''
814
814
815 if ui.quiet:
815 if ui.quiet:
816 ui.write("%s\n" % bmark, label=label)
816 ui.write("%s\n" % bmark, label=label)
817 else:
817 else:
818 ui.write(" %s %-25s %d:%s\n" % (
818 ui.write(" %s %-25s %d:%s\n" % (
819 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
819 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
820 label=label)
820 label=label)
821 return
821 return
822
822
823 @command('branch',
823 @command('branch',
824 [('f', 'force', None,
824 [('f', 'force', None,
825 _('set branch name even if it shadows an existing branch')),
825 _('set branch name even if it shadows an existing branch')),
826 ('C', 'clean', None, _('reset branch name to parent branch name'))],
826 ('C', 'clean', None, _('reset branch name to parent branch name'))],
827 _('[-fC] [NAME]'))
827 _('[-fC] [NAME]'))
828 def branch(ui, repo, label=None, **opts):
828 def branch(ui, repo, label=None, **opts):
829 """set or show the current branch name
829 """set or show the current branch name
830
830
831 .. note::
831 .. note::
832 Branch names are permanent and global. Use :hg:`bookmark` to create a
832 Branch names are permanent and global. Use :hg:`bookmark` to create a
833 light-weight bookmark instead. See :hg:`help glossary` for more
833 light-weight bookmark instead. See :hg:`help glossary` for more
834 information about named branches and bookmarks.
834 information about named branches and bookmarks.
835
835
836 With no argument, show the current branch name. With one argument,
836 With no argument, show the current branch name. With one argument,
837 set the working directory branch name (the branch will not exist
837 set the working directory branch name (the branch will not exist
838 in the repository until the next commit). Standard practice
838 in the repository until the next commit). Standard practice
839 recommends that primary development take place on the 'default'
839 recommends that primary development take place on the 'default'
840 branch.
840 branch.
841
841
842 Unless -f/--force is specified, branch will not let you set a
842 Unless -f/--force is specified, branch will not let you set a
843 branch name that already exists, even if it's inactive.
843 branch name that already exists, even if it's inactive.
844
844
845 Use -C/--clean to reset the working directory branch to that of
845 Use -C/--clean to reset the working directory branch to that of
846 the parent of the working directory, negating a previous branch
846 the parent of the working directory, negating a previous branch
847 change.
847 change.
848
848
849 Use the command :hg:`update` to switch to an existing branch. Use
849 Use the command :hg:`update` to switch to an existing branch. Use
850 :hg:`commit --close-branch` to mark this branch as closed.
850 :hg:`commit --close-branch` to mark this branch as closed.
851
851
852 Returns 0 on success.
852 Returns 0 on success.
853 """
853 """
854
854
855 if opts.get('clean'):
855 if opts.get('clean'):
856 label = repo[None].p1().branch()
856 label = repo[None].p1().branch()
857 repo.dirstate.setbranch(label)
857 repo.dirstate.setbranch(label)
858 ui.status(_('reset working directory to branch %s\n') % label)
858 ui.status(_('reset working directory to branch %s\n') % label)
859 elif label:
859 elif label:
860 if not opts.get('force') and label in repo.branchtags():
860 if not opts.get('force') and label in repo.branchtags():
861 if label not in [p.branch() for p in repo.parents()]:
861 if label not in [p.branch() for p in repo.parents()]:
862 raise util.Abort(_('a branch of the same name already exists'),
862 raise util.Abort(_('a branch of the same name already exists'),
863 # i18n: "it" refers to an existing branch
863 # i18n: "it" refers to an existing branch
864 hint=_("use 'hg update' to switch to it"))
864 hint=_("use 'hg update' to switch to it"))
865 repo.dirstate.setbranch(label)
865 repo.dirstate.setbranch(label)
866 ui.status(_('marked working directory as branch %s\n') % label)
866 ui.status(_('marked working directory as branch %s\n') % label)
867 ui.status(_('(branches are permanent and global, '
867 ui.status(_('(branches are permanent and global, '
868 'did you want a bookmark?)\n'))
868 'did you want a bookmark?)\n'))
869 else:
869 else:
870 ui.write("%s\n" % repo.dirstate.branch())
870 ui.write("%s\n" % repo.dirstate.branch())
871
871
872 @command('branches',
872 @command('branches',
873 [('a', 'active', False, _('show only branches that have unmerged heads')),
873 [('a', 'active', False, _('show only branches that have unmerged heads')),
874 ('c', 'closed', False, _('show normal and closed branches'))],
874 ('c', 'closed', False, _('show normal and closed branches'))],
875 _('[-ac]'))
875 _('[-ac]'))
876 def branches(ui, repo, active=False, closed=False):
876 def branches(ui, repo, active=False, closed=False):
877 """list repository named branches
877 """list repository named branches
878
878
879 List the repository's named branches, indicating which ones are
879 List the repository's named branches, indicating which ones are
880 inactive. If -c/--closed is specified, also list branches which have
880 inactive. If -c/--closed is specified, also list branches which have
881 been marked closed (see :hg:`commit --close-branch`).
881 been marked closed (see :hg:`commit --close-branch`).
882
882
883 If -a/--active is specified, only show active branches. A branch
883 If -a/--active is specified, only show active branches. A branch
884 is considered active if it contains repository heads.
884 is considered active if it contains repository heads.
885
885
886 Use the command :hg:`update` to switch to an existing branch.
886 Use the command :hg:`update` to switch to an existing branch.
887
887
888 Returns 0.
888 Returns 0.
889 """
889 """
890
890
891 hexfunc = ui.debugflag and hex or short
891 hexfunc = ui.debugflag and hex or short
892 activebranches = [repo[n].branch() for n in repo.heads()]
892 activebranches = [repo[n].branch() for n in repo.heads()]
893 def testactive(tag, node):
893 def testactive(tag, node):
894 realhead = tag in activebranches
894 realhead = tag in activebranches
895 open = node in repo.branchheads(tag, closed=False)
895 open = node in repo.branchheads(tag, closed=False)
896 return realhead and open
896 return realhead and open
897 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
897 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
898 for tag, node in repo.branchtags().items()],
898 for tag, node in repo.branchtags().items()],
899 reverse=True)
899 reverse=True)
900
900
901 for isactive, node, tag in branches:
901 for isactive, node, tag in branches:
902 if (not active) or isactive:
902 if (not active) or isactive:
903 if ui.quiet:
903 if ui.quiet:
904 ui.write("%s\n" % tag)
904 ui.write("%s\n" % tag)
905 else:
905 else:
906 hn = repo.lookup(node)
906 hn = repo.lookup(node)
907 if isactive:
907 if isactive:
908 label = 'branches.active'
908 label = 'branches.active'
909 notice = ''
909 notice = ''
910 elif hn not in repo.branchheads(tag, closed=False):
910 elif hn not in repo.branchheads(tag, closed=False):
911 if not closed:
911 if not closed:
912 continue
912 continue
913 label = 'branches.closed'
913 label = 'branches.closed'
914 notice = _(' (closed)')
914 notice = _(' (closed)')
915 else:
915 else:
916 label = 'branches.inactive'
916 label = 'branches.inactive'
917 notice = _(' (inactive)')
917 notice = _(' (inactive)')
918 if tag == repo.dirstate.branch():
918 if tag == repo.dirstate.branch():
919 label = 'branches.current'
919 label = 'branches.current'
920 rev = str(node).rjust(31 - encoding.colwidth(tag))
920 rev = str(node).rjust(31 - encoding.colwidth(tag))
921 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
921 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
922 tag = ui.label(tag, label)
922 tag = ui.label(tag, label)
923 ui.write("%s %s%s\n" % (tag, rev, notice))
923 ui.write("%s %s%s\n" % (tag, rev, notice))
924
924
925 @command('bundle',
925 @command('bundle',
926 [('f', 'force', None, _('run even when the destination is unrelated')),
926 [('f', 'force', None, _('run even when the destination is unrelated')),
927 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
927 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
928 _('REV')),
928 _('REV')),
929 ('b', 'branch', [], _('a specific branch you would like to bundle'),
929 ('b', 'branch', [], _('a specific branch you would like to bundle'),
930 _('BRANCH')),
930 _('BRANCH')),
931 ('', 'base', [],
931 ('', 'base', [],
932 _('a base changeset assumed to be available at the destination'),
932 _('a base changeset assumed to be available at the destination'),
933 _('REV')),
933 _('REV')),
934 ('a', 'all', None, _('bundle all changesets in the repository')),
934 ('a', 'all', None, _('bundle all changesets in the repository')),
935 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
935 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
936 ] + remoteopts,
936 ] + remoteopts,
937 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
937 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
938 def bundle(ui, repo, fname, dest=None, **opts):
938 def bundle(ui, repo, fname, dest=None, **opts):
939 """create a changegroup file
939 """create a changegroup file
940
940
941 Generate a compressed changegroup file collecting changesets not
941 Generate a compressed changegroup file collecting changesets not
942 known to be in another repository.
942 known to be in another repository.
943
943
944 If you omit the destination repository, then hg assumes the
944 If you omit the destination repository, then hg assumes the
945 destination will have all the nodes you specify with --base
945 destination will have all the nodes you specify with --base
946 parameters. To create a bundle containing all changesets, use
946 parameters. To create a bundle containing all changesets, use
947 -a/--all (or --base null).
947 -a/--all (or --base null).
948
948
949 You can change compression method with the -t/--type option.
949 You can change compression method with the -t/--type option.
950 The available compression methods are: none, bzip2, and
950 The available compression methods are: none, bzip2, and
951 gzip (by default, bundles are compressed using bzip2).
951 gzip (by default, bundles are compressed using bzip2).
952
952
953 The bundle file can then be transferred using conventional means
953 The bundle file can then be transferred using conventional means
954 and applied to another repository with the unbundle or pull
954 and applied to another repository with the unbundle or pull
955 command. This is useful when direct push and pull are not
955 command. This is useful when direct push and pull are not
956 available or when exporting an entire repository is undesirable.
956 available or when exporting an entire repository is undesirable.
957
957
958 Applying bundles preserves all changeset contents including
958 Applying bundles preserves all changeset contents including
959 permissions, copy/rename information, and revision history.
959 permissions, copy/rename information, and revision history.
960
960
961 Returns 0 on success, 1 if no changes found.
961 Returns 0 on success, 1 if no changes found.
962 """
962 """
963 revs = None
963 revs = None
964 if 'rev' in opts:
964 if 'rev' in opts:
965 revs = scmutil.revrange(repo, opts['rev'])
965 revs = scmutil.revrange(repo, opts['rev'])
966
966
967 if opts.get('all'):
967 if opts.get('all'):
968 base = ['null']
968 base = ['null']
969 else:
969 else:
970 base = scmutil.revrange(repo, opts.get('base'))
970 base = scmutil.revrange(repo, opts.get('base'))
971 if base:
971 if base:
972 if dest:
972 if dest:
973 raise util.Abort(_("--base is incompatible with specifying "
973 raise util.Abort(_("--base is incompatible with specifying "
974 "a destination"))
974 "a destination"))
975 common = [repo.lookup(rev) for rev in base]
975 common = [repo.lookup(rev) for rev in base]
976 heads = revs and map(repo.lookup, revs) or revs
976 heads = revs and map(repo.lookup, revs) or revs
977 else:
977 else:
978 dest = ui.expandpath(dest or 'default-push', dest or 'default')
978 dest = ui.expandpath(dest or 'default-push', dest or 'default')
979 dest, branches = hg.parseurl(dest, opts.get('branch'))
979 dest, branches = hg.parseurl(dest, opts.get('branch'))
980 other = hg.peer(repo, opts, dest)
980 other = hg.peer(repo, opts, dest)
981 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
981 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
982 heads = revs and map(repo.lookup, revs) or revs
982 heads = revs and map(repo.lookup, revs) or revs
983 common, outheads = discovery.findcommonoutgoing(repo, other,
983 common, outheads = discovery.findcommonoutgoing(repo, other,
984 onlyheads=heads,
984 onlyheads=heads,
985 force=opts.get('force'))
985 force=opts.get('force'))
986
986
987 cg = repo.getbundle('bundle', common=common, heads=heads)
987 cg = repo.getbundle('bundle', common=common, heads=heads)
988 if not cg:
988 if not cg:
989 ui.status(_("no changes found\n"))
989 ui.status(_("no changes found\n"))
990 return 1
990 return 1
991
991
992 bundletype = opts.get('type', 'bzip2').lower()
992 bundletype = opts.get('type', 'bzip2').lower()
993 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
993 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
994 bundletype = btypes.get(bundletype)
994 bundletype = btypes.get(bundletype)
995 if bundletype not in changegroup.bundletypes:
995 if bundletype not in changegroup.bundletypes:
996 raise util.Abort(_('unknown bundle type specified with --type'))
996 raise util.Abort(_('unknown bundle type specified with --type'))
997
997
998 changegroup.writebundle(cg, fname, bundletype)
998 changegroup.writebundle(cg, fname, bundletype)
999
999
1000 @command('cat',
1000 @command('cat',
1001 [('o', 'output', '',
1001 [('o', 'output', '',
1002 _('print output to file with formatted name'), _('FORMAT')),
1002 _('print output to file with formatted name'), _('FORMAT')),
1003 ('r', 'rev', '', _('print the given revision'), _('REV')),
1003 ('r', 'rev', '', _('print the given revision'), _('REV')),
1004 ('', 'decode', None, _('apply any matching decode filter')),
1004 ('', 'decode', None, _('apply any matching decode filter')),
1005 ] + walkopts,
1005 ] + walkopts,
1006 _('[OPTION]... FILE...'))
1006 _('[OPTION]... FILE...'))
1007 def cat(ui, repo, file1, *pats, **opts):
1007 def cat(ui, repo, file1, *pats, **opts):
1008 """output the current or given revision of files
1008 """output the current or given revision of files
1009
1009
1010 Print the specified files as they were at the given revision. If
1010 Print the specified files as they were at the given revision. If
1011 no revision is given, the parent of the working directory is used,
1011 no revision is given, the parent of the working directory is used,
1012 or tip if no revision is checked out.
1012 or tip if no revision is checked out.
1013
1013
1014 Output may be to a file, in which case the name of the file is
1014 Output may be to a file, in which case the name of the file is
1015 given using a format string. The formatting rules are the same as
1015 given using a format string. The formatting rules are the same as
1016 for the export command, with the following additions:
1016 for the export command, with the following additions:
1017
1017
1018 :``%s``: basename of file being printed
1018 :``%s``: basename of file being printed
1019 :``%d``: dirname of file being printed, or '.' if in repository root
1019 :``%d``: dirname of file being printed, or '.' if in repository root
1020 :``%p``: root-relative path name of file being printed
1020 :``%p``: root-relative path name of file being printed
1021
1021
1022 Returns 0 on success.
1022 Returns 0 on success.
1023 """
1023 """
1024 ctx = scmutil.revsingle(repo, opts.get('rev'))
1024 ctx = scmutil.revsingle(repo, opts.get('rev'))
1025 err = 1
1025 err = 1
1026 m = scmutil.match(ctx, (file1,) + pats, opts)
1026 m = scmutil.match(ctx, (file1,) + pats, opts)
1027 for abs in ctx.walk(m):
1027 for abs in ctx.walk(m):
1028 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1028 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1029 pathname=abs)
1029 pathname=abs)
1030 data = ctx[abs].data()
1030 data = ctx[abs].data()
1031 if opts.get('decode'):
1031 if opts.get('decode'):
1032 data = repo.wwritedata(abs, data)
1032 data = repo.wwritedata(abs, data)
1033 fp.write(data)
1033 fp.write(data)
1034 fp.close()
1034 fp.close()
1035 err = 0
1035 err = 0
1036 return err
1036 return err
1037
1037
1038 @command('^clone',
1038 @command('^clone',
1039 [('U', 'noupdate', None,
1039 [('U', 'noupdate', None,
1040 _('the clone will include an empty working copy (only a repository)')),
1040 _('the clone will include an empty working copy (only a repository)')),
1041 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1041 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1042 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1042 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1043 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1043 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1044 ('', 'pull', None, _('use pull protocol to copy metadata')),
1044 ('', 'pull', None, _('use pull protocol to copy metadata')),
1045 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1045 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1046 ] + remoteopts,
1046 ] + remoteopts,
1047 _('[OPTION]... SOURCE [DEST]'))
1047 _('[OPTION]... SOURCE [DEST]'))
1048 def clone(ui, source, dest=None, **opts):
1048 def clone(ui, source, dest=None, **opts):
1049 """make a copy of an existing repository
1049 """make a copy of an existing repository
1050
1050
1051 Create a copy of an existing repository in a new directory.
1051 Create a copy of an existing repository in a new directory.
1052
1052
1053 If no destination directory name is specified, it defaults to the
1053 If no destination directory name is specified, it defaults to the
1054 basename of the source.
1054 basename of the source.
1055
1055
1056 The location of the source is added to the new repository's
1056 The location of the source is added to the new repository's
1057 ``.hg/hgrc`` file, as the default to be used for future pulls.
1057 ``.hg/hgrc`` file, as the default to be used for future pulls.
1058
1058
1059 Only local paths and ``ssh://`` URLs are supported as
1059 Only local paths and ``ssh://`` URLs are supported as
1060 destinations. For ``ssh://`` destinations, no working directory or
1060 destinations. For ``ssh://`` destinations, no working directory or
1061 ``.hg/hgrc`` will be created on the remote side.
1061 ``.hg/hgrc`` will be created on the remote side.
1062
1062
1063 To pull only a subset of changesets, specify one or more revisions
1063 To pull only a subset of changesets, specify one or more revisions
1064 identifiers with -r/--rev or branches with -b/--branch. The
1064 identifiers with -r/--rev or branches with -b/--branch. The
1065 resulting clone will contain only the specified changesets and
1065 resulting clone will contain only the specified changesets and
1066 their ancestors. These options (or 'clone src#rev dest') imply
1066 their ancestors. These options (or 'clone src#rev dest') imply
1067 --pull, even for local source repositories. Note that specifying a
1067 --pull, even for local source repositories. Note that specifying a
1068 tag will include the tagged changeset but not the changeset
1068 tag will include the tagged changeset but not the changeset
1069 containing the tag.
1069 containing the tag.
1070
1070
1071 To check out a particular version, use -u/--update, or
1071 To check out a particular version, use -u/--update, or
1072 -U/--noupdate to create a clone with no working directory.
1072 -U/--noupdate to create a clone with no working directory.
1073
1073
1074 .. container:: verbose
1074 .. container:: verbose
1075
1075
1076 For efficiency, hardlinks are used for cloning whenever the
1076 For efficiency, hardlinks are used for cloning whenever the
1077 source and destination are on the same filesystem (note this
1077 source and destination are on the same filesystem (note this
1078 applies only to the repository data, not to the working
1078 applies only to the repository data, not to the working
1079 directory). Some filesystems, such as AFS, implement hardlinking
1079 directory). Some filesystems, such as AFS, implement hardlinking
1080 incorrectly, but do not report errors. In these cases, use the
1080 incorrectly, but do not report errors. In these cases, use the
1081 --pull option to avoid hardlinking.
1081 --pull option to avoid hardlinking.
1082
1082
1083 In some cases, you can clone repositories and the working
1083 In some cases, you can clone repositories and the working
1084 directory using full hardlinks with ::
1084 directory using full hardlinks with ::
1085
1085
1086 $ cp -al REPO REPOCLONE
1086 $ cp -al REPO REPOCLONE
1087
1087
1088 This is the fastest way to clone, but it is not always safe. The
1088 This is the fastest way to clone, but it is not always safe. The
1089 operation is not atomic (making sure REPO is not modified during
1089 operation is not atomic (making sure REPO is not modified during
1090 the operation is up to you) and you have to make sure your
1090 the operation is up to you) and you have to make sure your
1091 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1091 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1092 so). Also, this is not compatible with certain extensions that
1092 so). Also, this is not compatible with certain extensions that
1093 place their metadata under the .hg directory, such as mq.
1093 place their metadata under the .hg directory, such as mq.
1094
1094
1095 Mercurial will update the working directory to the first applicable
1095 Mercurial will update the working directory to the first applicable
1096 revision from this list:
1096 revision from this list:
1097
1097
1098 a) null if -U or the source repository has no changesets
1098 a) null if -U or the source repository has no changesets
1099 b) if -u . and the source repository is local, the first parent of
1099 b) if -u . and the source repository is local, the first parent of
1100 the source repository's working directory
1100 the source repository's working directory
1101 c) the changeset specified with -u (if a branch name, this means the
1101 c) the changeset specified with -u (if a branch name, this means the
1102 latest head of that branch)
1102 latest head of that branch)
1103 d) the changeset specified with -r
1103 d) the changeset specified with -r
1104 e) the tipmost head specified with -b
1104 e) the tipmost head specified with -b
1105 f) the tipmost head specified with the url#branch source syntax
1105 f) the tipmost head specified with the url#branch source syntax
1106 g) the tipmost head of the default branch
1106 g) the tipmost head of the default branch
1107 h) tip
1107 h) tip
1108
1108
1109 Examples:
1109 Examples:
1110
1110
1111 - clone a remote repository to a new directory named hg/::
1111 - clone a remote repository to a new directory named hg/::
1112
1112
1113 hg clone http://selenic.com/hg
1113 hg clone http://selenic.com/hg
1114
1114
1115 - create a lightweight local clone::
1115 - create a lightweight local clone::
1116
1116
1117 hg clone project/ project-feature/
1117 hg clone project/ project-feature/
1118
1118
1119 - clone from an absolute path on an ssh server (note double-slash)::
1119 - clone from an absolute path on an ssh server (note double-slash)::
1120
1120
1121 hg clone ssh://user@server//home/projects/alpha/
1121 hg clone ssh://user@server//home/projects/alpha/
1122
1122
1123 - do a high-speed clone over a LAN while checking out a
1123 - do a high-speed clone over a LAN while checking out a
1124 specified version::
1124 specified version::
1125
1125
1126 hg clone --uncompressed http://server/repo -u 1.5
1126 hg clone --uncompressed http://server/repo -u 1.5
1127
1127
1128 - create a repository without changesets after a particular revision::
1128 - create a repository without changesets after a particular revision::
1129
1129
1130 hg clone -r 04e544 experimental/ good/
1130 hg clone -r 04e544 experimental/ good/
1131
1131
1132 - clone (and track) a particular named branch::
1132 - clone (and track) a particular named branch::
1133
1133
1134 hg clone http://selenic.com/hg#stable
1134 hg clone http://selenic.com/hg#stable
1135
1135
1136 See :hg:`help urls` for details on specifying URLs.
1136 See :hg:`help urls` for details on specifying URLs.
1137
1137
1138 Returns 0 on success.
1138 Returns 0 on success.
1139 """
1139 """
1140 if opts.get('noupdate') and opts.get('updaterev'):
1140 if opts.get('noupdate') and opts.get('updaterev'):
1141 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1141 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1142
1142
1143 r = hg.clone(ui, opts, source, dest,
1143 r = hg.clone(ui, opts, source, dest,
1144 pull=opts.get('pull'),
1144 pull=opts.get('pull'),
1145 stream=opts.get('uncompressed'),
1145 stream=opts.get('uncompressed'),
1146 rev=opts.get('rev'),
1146 rev=opts.get('rev'),
1147 update=opts.get('updaterev') or not opts.get('noupdate'),
1147 update=opts.get('updaterev') or not opts.get('noupdate'),
1148 branch=opts.get('branch'))
1148 branch=opts.get('branch'))
1149
1149
1150 return r is None
1150 return r is None
1151
1151
1152 @command('^commit|ci',
1152 @command('^commit|ci',
1153 [('A', 'addremove', None,
1153 [('A', 'addremove', None,
1154 _('mark new/missing files as added/removed before committing')),
1154 _('mark new/missing files as added/removed before committing')),
1155 ('', 'close-branch', None,
1155 ('', 'close-branch', None,
1156 _('mark a branch as closed, hiding it from the branch list')),
1156 _('mark a branch as closed, hiding it from the branch list')),
1157 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1157 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1158 _('[OPTION]... [FILE]...'))
1158 _('[OPTION]... [FILE]...'))
1159 def commit(ui, repo, *pats, **opts):
1159 def commit(ui, repo, *pats, **opts):
1160 """commit the specified files or all outstanding changes
1160 """commit the specified files or all outstanding changes
1161
1161
1162 Commit changes to the given files into the repository. Unlike a
1162 Commit changes to the given files into the repository. Unlike a
1163 centralized SCM, this operation is a local operation. See
1163 centralized SCM, this operation is a local operation. See
1164 :hg:`push` for a way to actively distribute your changes.
1164 :hg:`push` for a way to actively distribute your changes.
1165
1165
1166 If a list of files is omitted, all changes reported by :hg:`status`
1166 If a list of files is omitted, all changes reported by :hg:`status`
1167 will be committed.
1167 will be committed.
1168
1168
1169 If you are committing the result of a merge, do not provide any
1169 If you are committing the result of a merge, do not provide any
1170 filenames or -I/-X filters.
1170 filenames or -I/-X filters.
1171
1171
1172 If no commit message is specified, Mercurial starts your
1172 If no commit message is specified, Mercurial starts your
1173 configured editor where you can enter a message. In case your
1173 configured editor where you can enter a message. In case your
1174 commit fails, you will find a backup of your message in
1174 commit fails, you will find a backup of your message in
1175 ``.hg/last-message.txt``.
1175 ``.hg/last-message.txt``.
1176
1176
1177 See :hg:`help dates` for a list of formats valid for -d/--date.
1177 See :hg:`help dates` for a list of formats valid for -d/--date.
1178
1178
1179 Returns 0 on success, 1 if nothing changed.
1179 Returns 0 on success, 1 if nothing changed.
1180 """
1180 """
1181 if opts.get('subrepos'):
1181 if opts.get('subrepos'):
1182 # Let --subrepos on the command line overide config setting.
1182 # Let --subrepos on the command line overide config setting.
1183 ui.setconfig('ui', 'commitsubrepos', True)
1183 ui.setconfig('ui', 'commitsubrepos', True)
1184
1184
1185 extra = {}
1185 extra = {}
1186 if opts.get('close_branch'):
1186 if opts.get('close_branch'):
1187 if repo['.'].node() not in repo.branchheads():
1187 if repo['.'].node() not in repo.branchheads():
1188 # The topo heads set is included in the branch heads set of the
1188 # The topo heads set is included in the branch heads set of the
1189 # current branch, so it's sufficient to test branchheads
1189 # current branch, so it's sufficient to test branchheads
1190 raise util.Abort(_('can only close branch heads'))
1190 raise util.Abort(_('can only close branch heads'))
1191 extra['close'] = 1
1191 extra['close'] = 1
1192 e = cmdutil.commiteditor
1192 e = cmdutil.commiteditor
1193 if opts.get('force_editor'):
1193 if opts.get('force_editor'):
1194 e = cmdutil.commitforceeditor
1194 e = cmdutil.commitforceeditor
1195
1195
1196 def commitfunc(ui, repo, message, match, opts):
1196 def commitfunc(ui, repo, message, match, opts):
1197 return repo.commit(message, opts.get('user'), opts.get('date'), match,
1197 return repo.commit(message, opts.get('user'), opts.get('date'), match,
1198 editor=e, extra=extra)
1198 editor=e, extra=extra)
1199
1199
1200 branch = repo[None].branch()
1200 branch = repo[None].branch()
1201 bheads = repo.branchheads(branch)
1201 bheads = repo.branchheads(branch)
1202
1202
1203 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1203 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1204 if not node:
1204 if not node:
1205 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1205 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1206 if stat[3]:
1206 if stat[3]:
1207 ui.status(_("nothing changed (%d missing files, see 'hg status')\n")
1207 ui.status(_("nothing changed (%d missing files, see 'hg status')\n")
1208 % len(stat[3]))
1208 % len(stat[3]))
1209 else:
1209 else:
1210 ui.status(_("nothing changed\n"))
1210 ui.status(_("nothing changed\n"))
1211 return 1
1211 return 1
1212
1212
1213 ctx = repo[node]
1213 ctx = repo[node]
1214 parents = ctx.parents()
1214 parents = ctx.parents()
1215
1215
1216 if (bheads and node not in bheads and not
1216 if (bheads and node not in bheads and not
1217 [x for x in parents if x.node() in bheads and x.branch() == branch]):
1217 [x for x in parents if x.node() in bheads and x.branch() == branch]):
1218 ui.status(_('created new head\n'))
1218 ui.status(_('created new head\n'))
1219 # The message is not printed for initial roots. For the other
1219 # The message is not printed for initial roots. For the other
1220 # changesets, it is printed in the following situations:
1220 # changesets, it is printed in the following situations:
1221 #
1221 #
1222 # Par column: for the 2 parents with ...
1222 # Par column: for the 2 parents with ...
1223 # N: null or no parent
1223 # N: null or no parent
1224 # B: parent is on another named branch
1224 # B: parent is on another named branch
1225 # C: parent is a regular non head changeset
1225 # C: parent is a regular non head changeset
1226 # H: parent was a branch head of the current branch
1226 # H: parent was a branch head of the current branch
1227 # Msg column: whether we print "created new head" message
1227 # Msg column: whether we print "created new head" message
1228 # In the following, it is assumed that there already exists some
1228 # In the following, it is assumed that there already exists some
1229 # initial branch heads of the current branch, otherwise nothing is
1229 # initial branch heads of the current branch, otherwise nothing is
1230 # printed anyway.
1230 # printed anyway.
1231 #
1231 #
1232 # Par Msg Comment
1232 # Par Msg Comment
1233 # NN y additional topo root
1233 # NN y additional topo root
1234 #
1234 #
1235 # BN y additional branch root
1235 # BN y additional branch root
1236 # CN y additional topo head
1236 # CN y additional topo head
1237 # HN n usual case
1237 # HN n usual case
1238 #
1238 #
1239 # BB y weird additional branch root
1239 # BB y weird additional branch root
1240 # CB y branch merge
1240 # CB y branch merge
1241 # HB n merge with named branch
1241 # HB n merge with named branch
1242 #
1242 #
1243 # CC y additional head from merge
1243 # CC y additional head from merge
1244 # CH n merge with a head
1244 # CH n merge with a head
1245 #
1245 #
1246 # HH n head merge: head count decreases
1246 # HH n head merge: head count decreases
1247
1247
1248 if not opts.get('close_branch'):
1248 if not opts.get('close_branch'):
1249 for r in parents:
1249 for r in parents:
1250 if r.extra().get('close') and r.branch() == branch:
1250 if r.extra().get('close') and r.branch() == branch:
1251 ui.status(_('reopening closed branch head %d\n') % r)
1251 ui.status(_('reopening closed branch head %d\n') % r)
1252
1252
1253 if ui.debugflag:
1253 if ui.debugflag:
1254 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1254 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1255 elif ui.verbose:
1255 elif ui.verbose:
1256 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1256 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1257
1257
1258 @command('copy|cp',
1258 @command('copy|cp',
1259 [('A', 'after', None, _('record a copy that has already occurred')),
1259 [('A', 'after', None, _('record a copy that has already occurred')),
1260 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1260 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1261 ] + walkopts + dryrunopts,
1261 ] + walkopts + dryrunopts,
1262 _('[OPTION]... [SOURCE]... DEST'))
1262 _('[OPTION]... [SOURCE]... DEST'))
1263 def copy(ui, repo, *pats, **opts):
1263 def copy(ui, repo, *pats, **opts):
1264 """mark files as copied for the next commit
1264 """mark files as copied for the next commit
1265
1265
1266 Mark dest as having copies of source files. If dest is a
1266 Mark dest as having copies of source files. If dest is a
1267 directory, copies are put in that directory. If dest is a file,
1267 directory, copies are put in that directory. If dest is a file,
1268 the source must be a single file.
1268 the source must be a single file.
1269
1269
1270 By default, this command copies the contents of files as they
1270 By default, this command copies the contents of files as they
1271 exist in the working directory. If invoked with -A/--after, the
1271 exist in the working directory. If invoked with -A/--after, the
1272 operation is recorded, but no copying is performed.
1272 operation is recorded, but no copying is performed.
1273
1273
1274 This command takes effect with the next commit. To undo a copy
1274 This command takes effect with the next commit. To undo a copy
1275 before that, see :hg:`revert`.
1275 before that, see :hg:`revert`.
1276
1276
1277 Returns 0 on success, 1 if errors are encountered.
1277 Returns 0 on success, 1 if errors are encountered.
1278 """
1278 """
1279 wlock = repo.wlock(False)
1279 wlock = repo.wlock(False)
1280 try:
1280 try:
1281 return cmdutil.copy(ui, repo, pats, opts)
1281 return cmdutil.copy(ui, repo, pats, opts)
1282 finally:
1282 finally:
1283 wlock.release()
1283 wlock.release()
1284
1284
1285 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1285 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1286 def debugancestor(ui, repo, *args):
1286 def debugancestor(ui, repo, *args):
1287 """find the ancestor revision of two revisions in a given index"""
1287 """find the ancestor revision of two revisions in a given index"""
1288 if len(args) == 3:
1288 if len(args) == 3:
1289 index, rev1, rev2 = args
1289 index, rev1, rev2 = args
1290 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1290 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1291 lookup = r.lookup
1291 lookup = r.lookup
1292 elif len(args) == 2:
1292 elif len(args) == 2:
1293 if not repo:
1293 if not repo:
1294 raise util.Abort(_("there is no Mercurial repository here "
1294 raise util.Abort(_("there is no Mercurial repository here "
1295 "(.hg not found)"))
1295 "(.hg not found)"))
1296 rev1, rev2 = args
1296 rev1, rev2 = args
1297 r = repo.changelog
1297 r = repo.changelog
1298 lookup = repo.lookup
1298 lookup = repo.lookup
1299 else:
1299 else:
1300 raise util.Abort(_('either two or three arguments required'))
1300 raise util.Abort(_('either two or three arguments required'))
1301 a = r.ancestor(lookup(rev1), lookup(rev2))
1301 a = r.ancestor(lookup(rev1), lookup(rev2))
1302 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1302 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1303
1303
1304 @command('debugbuilddag',
1304 @command('debugbuilddag',
1305 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1305 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1306 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1306 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1307 ('n', 'new-file', None, _('add new file at each rev'))],
1307 ('n', 'new-file', None, _('add new file at each rev'))],
1308 _('[OPTION]... [TEXT]'))
1308 _('[OPTION]... [TEXT]'))
1309 def debugbuilddag(ui, repo, text=None,
1309 def debugbuilddag(ui, repo, text=None,
1310 mergeable_file=False,
1310 mergeable_file=False,
1311 overwritten_file=False,
1311 overwritten_file=False,
1312 new_file=False):
1312 new_file=False):
1313 """builds a repo with a given DAG from scratch in the current empty repo
1313 """builds a repo with a given DAG from scratch in the current empty repo
1314
1314
1315 The description of the DAG is read from stdin if not given on the
1315 The description of the DAG is read from stdin if not given on the
1316 command line.
1316 command line.
1317
1317
1318 Elements:
1318 Elements:
1319
1319
1320 - "+n" is a linear run of n nodes based on the current default parent
1320 - "+n" is a linear run of n nodes based on the current default parent
1321 - "." is a single node based on the current default parent
1321 - "." is a single node based on the current default parent
1322 - "$" resets the default parent to null (implied at the start);
1322 - "$" resets the default parent to null (implied at the start);
1323 otherwise the default parent is always the last node created
1323 otherwise the default parent is always the last node created
1324 - "<p" sets the default parent to the backref p
1324 - "<p" sets the default parent to the backref p
1325 - "*p" is a fork at parent p, which is a backref
1325 - "*p" is a fork at parent p, which is a backref
1326 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1326 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1327 - "/p2" is a merge of the preceding node and p2
1327 - "/p2" is a merge of the preceding node and p2
1328 - ":tag" defines a local tag for the preceding node
1328 - ":tag" defines a local tag for the preceding node
1329 - "@branch" sets the named branch for subsequent nodes
1329 - "@branch" sets the named branch for subsequent nodes
1330 - "#...\\n" is a comment up to the end of the line
1330 - "#...\\n" is a comment up to the end of the line
1331
1331
1332 Whitespace between the above elements is ignored.
1332 Whitespace between the above elements is ignored.
1333
1333
1334 A backref is either
1334 A backref is either
1335
1335
1336 - a number n, which references the node curr-n, where curr is the current
1336 - a number n, which references the node curr-n, where curr is the current
1337 node, or
1337 node, or
1338 - the name of a local tag you placed earlier using ":tag", or
1338 - the name of a local tag you placed earlier using ":tag", or
1339 - empty to denote the default parent.
1339 - empty to denote the default parent.
1340
1340
1341 All string valued-elements are either strictly alphanumeric, or must
1341 All string valued-elements are either strictly alphanumeric, or must
1342 be enclosed in double quotes ("..."), with "\\" as escape character.
1342 be enclosed in double quotes ("..."), with "\\" as escape character.
1343 """
1343 """
1344
1344
1345 if text is None:
1345 if text is None:
1346 ui.status(_("reading DAG from stdin\n"))
1346 ui.status(_("reading DAG from stdin\n"))
1347 text = ui.fin.read()
1347 text = ui.fin.read()
1348
1348
1349 cl = repo.changelog
1349 cl = repo.changelog
1350 if len(cl) > 0:
1350 if len(cl) > 0:
1351 raise util.Abort(_('repository is not empty'))
1351 raise util.Abort(_('repository is not empty'))
1352
1352
1353 # determine number of revs in DAG
1353 # determine number of revs in DAG
1354 total = 0
1354 total = 0
1355 for type, data in dagparser.parsedag(text):
1355 for type, data in dagparser.parsedag(text):
1356 if type == 'n':
1356 if type == 'n':
1357 total += 1
1357 total += 1
1358
1358
1359 if mergeable_file:
1359 if mergeable_file:
1360 linesperrev = 2
1360 linesperrev = 2
1361 # make a file with k lines per rev
1361 # make a file with k lines per rev
1362 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1362 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1363 initialmergedlines.append("")
1363 initialmergedlines.append("")
1364
1364
1365 tags = []
1365 tags = []
1366
1366
1367 tr = repo.transaction("builddag")
1367 tr = repo.transaction("builddag")
1368 try:
1368 try:
1369
1369
1370 at = -1
1370 at = -1
1371 atbranch = 'default'
1371 atbranch = 'default'
1372 nodeids = []
1372 nodeids = []
1373 ui.progress(_('building'), 0, unit=_('revisions'), total=total)
1373 ui.progress(_('building'), 0, unit=_('revisions'), total=total)
1374 for type, data in dagparser.parsedag(text):
1374 for type, data in dagparser.parsedag(text):
1375 if type == 'n':
1375 if type == 'n':
1376 ui.note('node %s\n' % str(data))
1376 ui.note('node %s\n' % str(data))
1377 id, ps = data
1377 id, ps = data
1378
1378
1379 files = []
1379 files = []
1380 fctxs = {}
1380 fctxs = {}
1381
1381
1382 p2 = None
1382 p2 = None
1383 if mergeable_file:
1383 if mergeable_file:
1384 fn = "mf"
1384 fn = "mf"
1385 p1 = repo[ps[0]]
1385 p1 = repo[ps[0]]
1386 if len(ps) > 1:
1386 if len(ps) > 1:
1387 p2 = repo[ps[1]]
1387 p2 = repo[ps[1]]
1388 pa = p1.ancestor(p2)
1388 pa = p1.ancestor(p2)
1389 base, local, other = [x[fn].data() for x in pa, p1, p2]
1389 base, local, other = [x[fn].data() for x in pa, p1, p2]
1390 m3 = simplemerge.Merge3Text(base, local, other)
1390 m3 = simplemerge.Merge3Text(base, local, other)
1391 ml = [l.strip() for l in m3.merge_lines()]
1391 ml = [l.strip() for l in m3.merge_lines()]
1392 ml.append("")
1392 ml.append("")
1393 elif at > 0:
1393 elif at > 0:
1394 ml = p1[fn].data().split("\n")
1394 ml = p1[fn].data().split("\n")
1395 else:
1395 else:
1396 ml = initialmergedlines
1396 ml = initialmergedlines
1397 ml[id * linesperrev] += " r%i" % id
1397 ml[id * linesperrev] += " r%i" % id
1398 mergedtext = "\n".join(ml)
1398 mergedtext = "\n".join(ml)
1399 files.append(fn)
1399 files.append(fn)
1400 fctxs[fn] = context.memfilectx(fn, mergedtext)
1400 fctxs[fn] = context.memfilectx(fn, mergedtext)
1401
1401
1402 if overwritten_file:
1402 if overwritten_file:
1403 fn = "of"
1403 fn = "of"
1404 files.append(fn)
1404 files.append(fn)
1405 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1405 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1406
1406
1407 if new_file:
1407 if new_file:
1408 fn = "nf%i" % id
1408 fn = "nf%i" % id
1409 files.append(fn)
1409 files.append(fn)
1410 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1410 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1411 if len(ps) > 1:
1411 if len(ps) > 1:
1412 if not p2:
1412 if not p2:
1413 p2 = repo[ps[1]]
1413 p2 = repo[ps[1]]
1414 for fn in p2:
1414 for fn in p2:
1415 if fn.startswith("nf"):
1415 if fn.startswith("nf"):
1416 files.append(fn)
1416 files.append(fn)
1417 fctxs[fn] = p2[fn]
1417 fctxs[fn] = p2[fn]
1418
1418
1419 def fctxfn(repo, cx, path):
1419 def fctxfn(repo, cx, path):
1420 return fctxs.get(path)
1420 return fctxs.get(path)
1421
1421
1422 if len(ps) == 0 or ps[0] < 0:
1422 if len(ps) == 0 or ps[0] < 0:
1423 pars = [None, None]
1423 pars = [None, None]
1424 elif len(ps) == 1:
1424 elif len(ps) == 1:
1425 pars = [nodeids[ps[0]], None]
1425 pars = [nodeids[ps[0]], None]
1426 else:
1426 else:
1427 pars = [nodeids[p] for p in ps]
1427 pars = [nodeids[p] for p in ps]
1428 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1428 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1429 date=(id, 0),
1429 date=(id, 0),
1430 user="debugbuilddag",
1430 user="debugbuilddag",
1431 extra={'branch': atbranch})
1431 extra={'branch': atbranch})
1432 nodeid = repo.commitctx(cx)
1432 nodeid = repo.commitctx(cx)
1433 nodeids.append(nodeid)
1433 nodeids.append(nodeid)
1434 at = id
1434 at = id
1435 elif type == 'l':
1435 elif type == 'l':
1436 id, name = data
1436 id, name = data
1437 ui.note('tag %s\n' % name)
1437 ui.note('tag %s\n' % name)
1438 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1438 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1439 elif type == 'a':
1439 elif type == 'a':
1440 ui.note('branch %s\n' % data)
1440 ui.note('branch %s\n' % data)
1441 atbranch = data
1441 atbranch = data
1442 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1442 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1443 tr.close()
1443 tr.close()
1444 finally:
1444 finally:
1445 ui.progress(_('building'), None)
1445 ui.progress(_('building'), None)
1446 tr.release()
1446 tr.release()
1447
1447
1448 if tags:
1448 if tags:
1449 repo.opener.write("localtags", "".join(tags))
1449 repo.opener.write("localtags", "".join(tags))
1450
1450
1451 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1451 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1452 def debugbundle(ui, bundlepath, all=None, **opts):
1452 def debugbundle(ui, bundlepath, all=None, **opts):
1453 """lists the contents of a bundle"""
1453 """lists the contents of a bundle"""
1454 f = url.open(ui, bundlepath)
1454 f = url.open(ui, bundlepath)
1455 try:
1455 try:
1456 gen = changegroup.readbundle(f, bundlepath)
1456 gen = changegroup.readbundle(f, bundlepath)
1457 if all:
1457 if all:
1458 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1458 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1459
1459
1460 def showchunks(named):
1460 def showchunks(named):
1461 ui.write("\n%s\n" % named)
1461 ui.write("\n%s\n" % named)
1462 chain = None
1462 chain = None
1463 while True:
1463 while True:
1464 chunkdata = gen.deltachunk(chain)
1464 chunkdata = gen.deltachunk(chain)
1465 if not chunkdata:
1465 if not chunkdata:
1466 break
1466 break
1467 node = chunkdata['node']
1467 node = chunkdata['node']
1468 p1 = chunkdata['p1']
1468 p1 = chunkdata['p1']
1469 p2 = chunkdata['p2']
1469 p2 = chunkdata['p2']
1470 cs = chunkdata['cs']
1470 cs = chunkdata['cs']
1471 deltabase = chunkdata['deltabase']
1471 deltabase = chunkdata['deltabase']
1472 delta = chunkdata['delta']
1472 delta = chunkdata['delta']
1473 ui.write("%s %s %s %s %s %s\n" %
1473 ui.write("%s %s %s %s %s %s\n" %
1474 (hex(node), hex(p1), hex(p2),
1474 (hex(node), hex(p1), hex(p2),
1475 hex(cs), hex(deltabase), len(delta)))
1475 hex(cs), hex(deltabase), len(delta)))
1476 chain = node
1476 chain = node
1477
1477
1478 chunkdata = gen.changelogheader()
1478 chunkdata = gen.changelogheader()
1479 showchunks("changelog")
1479 showchunks("changelog")
1480 chunkdata = gen.manifestheader()
1480 chunkdata = gen.manifestheader()
1481 showchunks("manifest")
1481 showchunks("manifest")
1482 while True:
1482 while True:
1483 chunkdata = gen.filelogheader()
1483 chunkdata = gen.filelogheader()
1484 if not chunkdata:
1484 if not chunkdata:
1485 break
1485 break
1486 fname = chunkdata['filename']
1486 fname = chunkdata['filename']
1487 showchunks(fname)
1487 showchunks(fname)
1488 else:
1488 else:
1489 chunkdata = gen.changelogheader()
1489 chunkdata = gen.changelogheader()
1490 chain = None
1490 chain = None
1491 while True:
1491 while True:
1492 chunkdata = gen.deltachunk(chain)
1492 chunkdata = gen.deltachunk(chain)
1493 if not chunkdata:
1493 if not chunkdata:
1494 break
1494 break
1495 node = chunkdata['node']
1495 node = chunkdata['node']
1496 ui.write("%s\n" % hex(node))
1496 ui.write("%s\n" % hex(node))
1497 chain = node
1497 chain = node
1498 finally:
1498 finally:
1499 f.close()
1499 f.close()
1500
1500
1501 @command('debugcheckstate', [], '')
1501 @command('debugcheckstate', [], '')
1502 def debugcheckstate(ui, repo):
1502 def debugcheckstate(ui, repo):
1503 """validate the correctness of the current dirstate"""
1503 """validate the correctness of the current dirstate"""
1504 parent1, parent2 = repo.dirstate.parents()
1504 parent1, parent2 = repo.dirstate.parents()
1505 m1 = repo[parent1].manifest()
1505 m1 = repo[parent1].manifest()
1506 m2 = repo[parent2].manifest()
1506 m2 = repo[parent2].manifest()
1507 errors = 0
1507 errors = 0
1508 for f in repo.dirstate:
1508 for f in repo.dirstate:
1509 state = repo.dirstate[f]
1509 state = repo.dirstate[f]
1510 if state in "nr" and f not in m1:
1510 if state in "nr" and f not in m1:
1511 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1511 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1512 errors += 1
1512 errors += 1
1513 if state in "a" and f in m1:
1513 if state in "a" and f in m1:
1514 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1514 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1515 errors += 1
1515 errors += 1
1516 if state in "m" and f not in m1 and f not in m2:
1516 if state in "m" and f not in m1 and f not in m2:
1517 ui.warn(_("%s in state %s, but not in either manifest\n") %
1517 ui.warn(_("%s in state %s, but not in either manifest\n") %
1518 (f, state))
1518 (f, state))
1519 errors += 1
1519 errors += 1
1520 for f in m1:
1520 for f in m1:
1521 state = repo.dirstate[f]
1521 state = repo.dirstate[f]
1522 if state not in "nrm":
1522 if state not in "nrm":
1523 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1523 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1524 errors += 1
1524 errors += 1
1525 if errors:
1525 if errors:
1526 error = _(".hg/dirstate inconsistent with current parent's manifest")
1526 error = _(".hg/dirstate inconsistent with current parent's manifest")
1527 raise util.Abort(error)
1527 raise util.Abort(error)
1528
1528
1529 @command('debugcommands', [], _('[COMMAND]'))
1529 @command('debugcommands', [], _('[COMMAND]'))
1530 def debugcommands(ui, cmd='', *args):
1530 def debugcommands(ui, cmd='', *args):
1531 """list all available commands and options"""
1531 """list all available commands and options"""
1532 for cmd, vals in sorted(table.iteritems()):
1532 for cmd, vals in sorted(table.iteritems()):
1533 cmd = cmd.split('|')[0].strip('^')
1533 cmd = cmd.split('|')[0].strip('^')
1534 opts = ', '.join([i[1] for i in vals[1]])
1534 opts = ', '.join([i[1] for i in vals[1]])
1535 ui.write('%s: %s\n' % (cmd, opts))
1535 ui.write('%s: %s\n' % (cmd, opts))
1536
1536
1537 @command('debugcomplete',
1537 @command('debugcomplete',
1538 [('o', 'options', None, _('show the command options'))],
1538 [('o', 'options', None, _('show the command options'))],
1539 _('[-o] CMD'))
1539 _('[-o] CMD'))
1540 def debugcomplete(ui, cmd='', **opts):
1540 def debugcomplete(ui, cmd='', **opts):
1541 """returns the completion list associated with the given command"""
1541 """returns the completion list associated with the given command"""
1542
1542
1543 if opts.get('options'):
1543 if opts.get('options'):
1544 options = []
1544 options = []
1545 otables = [globalopts]
1545 otables = [globalopts]
1546 if cmd:
1546 if cmd:
1547 aliases, entry = cmdutil.findcmd(cmd, table, False)
1547 aliases, entry = cmdutil.findcmd(cmd, table, False)
1548 otables.append(entry[1])
1548 otables.append(entry[1])
1549 for t in otables:
1549 for t in otables:
1550 for o in t:
1550 for o in t:
1551 if "(DEPRECATED)" in o[3]:
1551 if "(DEPRECATED)" in o[3]:
1552 continue
1552 continue
1553 if o[0]:
1553 if o[0]:
1554 options.append('-%s' % o[0])
1554 options.append('-%s' % o[0])
1555 options.append('--%s' % o[1])
1555 options.append('--%s' % o[1])
1556 ui.write("%s\n" % "\n".join(options))
1556 ui.write("%s\n" % "\n".join(options))
1557 return
1557 return
1558
1558
1559 cmdlist = cmdutil.findpossible(cmd, table)
1559 cmdlist = cmdutil.findpossible(cmd, table)
1560 if ui.verbose:
1560 if ui.verbose:
1561 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1561 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1562 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1562 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1563
1563
1564 @command('debugdag',
1564 @command('debugdag',
1565 [('t', 'tags', None, _('use tags as labels')),
1565 [('t', 'tags', None, _('use tags as labels')),
1566 ('b', 'branches', None, _('annotate with branch names')),
1566 ('b', 'branches', None, _('annotate with branch names')),
1567 ('', 'dots', None, _('use dots for runs')),
1567 ('', 'dots', None, _('use dots for runs')),
1568 ('s', 'spaces', None, _('separate elements by spaces'))],
1568 ('s', 'spaces', None, _('separate elements by spaces'))],
1569 _('[OPTION]... [FILE [REV]...]'))
1569 _('[OPTION]... [FILE [REV]...]'))
1570 def debugdag(ui, repo, file_=None, *revs, **opts):
1570 def debugdag(ui, repo, file_=None, *revs, **opts):
1571 """format the changelog or an index DAG as a concise textual description
1571 """format the changelog or an index DAG as a concise textual description
1572
1572
1573 If you pass a revlog index, the revlog's DAG is emitted. If you list
1573 If you pass a revlog index, the revlog's DAG is emitted. If you list
1574 revision numbers, they get labelled in the output as rN.
1574 revision numbers, they get labelled in the output as rN.
1575
1575
1576 Otherwise, the changelog DAG of the current repo is emitted.
1576 Otherwise, the changelog DAG of the current repo is emitted.
1577 """
1577 """
1578 spaces = opts.get('spaces')
1578 spaces = opts.get('spaces')
1579 dots = opts.get('dots')
1579 dots = opts.get('dots')
1580 if file_:
1580 if file_:
1581 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1581 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1582 revs = set((int(r) for r in revs))
1582 revs = set((int(r) for r in revs))
1583 def events():
1583 def events():
1584 for r in rlog:
1584 for r in rlog:
1585 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1585 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1586 if r in revs:
1586 if r in revs:
1587 yield 'l', (r, "r%i" % r)
1587 yield 'l', (r, "r%i" % r)
1588 elif repo:
1588 elif repo:
1589 cl = repo.changelog
1589 cl = repo.changelog
1590 tags = opts.get('tags')
1590 tags = opts.get('tags')
1591 branches = opts.get('branches')
1591 branches = opts.get('branches')
1592 if tags:
1592 if tags:
1593 labels = {}
1593 labels = {}
1594 for l, n in repo.tags().items():
1594 for l, n in repo.tags().items():
1595 labels.setdefault(cl.rev(n), []).append(l)
1595 labels.setdefault(cl.rev(n), []).append(l)
1596 def events():
1596 def events():
1597 b = "default"
1597 b = "default"
1598 for r in cl:
1598 for r in cl:
1599 if branches:
1599 if branches:
1600 newb = cl.read(cl.node(r))[5]['branch']
1600 newb = cl.read(cl.node(r))[5]['branch']
1601 if newb != b:
1601 if newb != b:
1602 yield 'a', newb
1602 yield 'a', newb
1603 b = newb
1603 b = newb
1604 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1604 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1605 if tags:
1605 if tags:
1606 ls = labels.get(r)
1606 ls = labels.get(r)
1607 if ls:
1607 if ls:
1608 for l in ls:
1608 for l in ls:
1609 yield 'l', (r, l)
1609 yield 'l', (r, l)
1610 else:
1610 else:
1611 raise util.Abort(_('need repo for changelog dag'))
1611 raise util.Abort(_('need repo for changelog dag'))
1612
1612
1613 for line in dagparser.dagtextlines(events(),
1613 for line in dagparser.dagtextlines(events(),
1614 addspaces=spaces,
1614 addspaces=spaces,
1615 wraplabels=True,
1615 wraplabels=True,
1616 wrapannotations=True,
1616 wrapannotations=True,
1617 wrapnonlinear=dots,
1617 wrapnonlinear=dots,
1618 usedots=dots,
1618 usedots=dots,
1619 maxlinewidth=70):
1619 maxlinewidth=70):
1620 ui.write(line)
1620 ui.write(line)
1621 ui.write("\n")
1621 ui.write("\n")
1622
1622
1623 @command('debugdata',
1623 @command('debugdata',
1624 [('c', 'changelog', False, _('open changelog')),
1624 [('c', 'changelog', False, _('open changelog')),
1625 ('m', 'manifest', False, _('open manifest'))],
1625 ('m', 'manifest', False, _('open manifest'))],
1626 _('-c|-m|FILE REV'))
1626 _('-c|-m|FILE REV'))
1627 def debugdata(ui, repo, file_, rev = None, **opts):
1627 def debugdata(ui, repo, file_, rev = None, **opts):
1628 """dump the contents of a data file revision"""
1628 """dump the contents of a data file revision"""
1629 if opts.get('changelog') or opts.get('manifest'):
1629 if opts.get('changelog') or opts.get('manifest'):
1630 file_, rev = None, file_
1630 file_, rev = None, file_
1631 elif rev is None:
1631 elif rev is None:
1632 raise error.CommandError('debugdata', _('invalid arguments'))
1632 raise error.CommandError('debugdata', _('invalid arguments'))
1633 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1633 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1634 try:
1634 try:
1635 ui.write(r.revision(r.lookup(rev)))
1635 ui.write(r.revision(r.lookup(rev)))
1636 except KeyError:
1636 except KeyError:
1637 raise util.Abort(_('invalid revision identifier %s') % rev)
1637 raise util.Abort(_('invalid revision identifier %s') % rev)
1638
1638
1639 @command('debugdate',
1639 @command('debugdate',
1640 [('e', 'extended', None, _('try extended date formats'))],
1640 [('e', 'extended', None, _('try extended date formats'))],
1641 _('[-e] DATE [RANGE]'))
1641 _('[-e] DATE [RANGE]'))
1642 def debugdate(ui, date, range=None, **opts):
1642 def debugdate(ui, date, range=None, **opts):
1643 """parse and display a date"""
1643 """parse and display a date"""
1644 if opts["extended"]:
1644 if opts["extended"]:
1645 d = util.parsedate(date, util.extendeddateformats)
1645 d = util.parsedate(date, util.extendeddateformats)
1646 else:
1646 else:
1647 d = util.parsedate(date)
1647 d = util.parsedate(date)
1648 ui.write("internal: %s %s\n" % d)
1648 ui.write("internal: %s %s\n" % d)
1649 ui.write("standard: %s\n" % util.datestr(d))
1649 ui.write("standard: %s\n" % util.datestr(d))
1650 if range:
1650 if range:
1651 m = util.matchdate(range)
1651 m = util.matchdate(range)
1652 ui.write("match: %s\n" % m(d[0]))
1652 ui.write("match: %s\n" % m(d[0]))
1653
1653
1654 @command('debugdiscovery',
1654 @command('debugdiscovery',
1655 [('', 'old', None, _('use old-style discovery')),
1655 [('', 'old', None, _('use old-style discovery')),
1656 ('', 'nonheads', None,
1656 ('', 'nonheads', None,
1657 _('use old-style discovery with non-heads included')),
1657 _('use old-style discovery with non-heads included')),
1658 ] + remoteopts,
1658 ] + remoteopts,
1659 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1659 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1660 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1660 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1661 """runs the changeset discovery protocol in isolation"""
1661 """runs the changeset discovery protocol in isolation"""
1662 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl), opts.get('branch'))
1662 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl), opts.get('branch'))
1663 remote = hg.peer(repo, opts, remoteurl)
1663 remote = hg.peer(repo, opts, remoteurl)
1664 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1664 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1665
1665
1666 # make sure tests are repeatable
1666 # make sure tests are repeatable
1667 random.seed(12323)
1667 random.seed(12323)
1668
1668
1669 def doit(localheads, remoteheads):
1669 def doit(localheads, remoteheads):
1670 if opts.get('old'):
1670 if opts.get('old'):
1671 if localheads:
1671 if localheads:
1672 raise util.Abort('cannot use localheads with old style discovery')
1672 raise util.Abort('cannot use localheads with old style discovery')
1673 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1673 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1674 force=True)
1674 force=True)
1675 common = set(common)
1675 common = set(common)
1676 if not opts.get('nonheads'):
1676 if not opts.get('nonheads'):
1677 ui.write("unpruned common: %s\n" % " ".join([short(n)
1677 ui.write("unpruned common: %s\n" % " ".join([short(n)
1678 for n in common]))
1678 for n in common]))
1679 dag = dagutil.revlogdag(repo.changelog)
1679 dag = dagutil.revlogdag(repo.changelog)
1680 all = dag.ancestorset(dag.internalizeall(common))
1680 all = dag.ancestorset(dag.internalizeall(common))
1681 common = dag.externalizeall(dag.headsetofconnecteds(all))
1681 common = dag.externalizeall(dag.headsetofconnecteds(all))
1682 else:
1682 else:
1683 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1683 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1684 common = set(common)
1684 common = set(common)
1685 rheads = set(hds)
1685 rheads = set(hds)
1686 lheads = set(repo.heads())
1686 lheads = set(repo.heads())
1687 ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
1687 ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
1688 if lheads <= common:
1688 if lheads <= common:
1689 ui.write("local is subset\n")
1689 ui.write("local is subset\n")
1690 elif rheads <= common:
1690 elif rheads <= common:
1691 ui.write("remote is subset\n")
1691 ui.write("remote is subset\n")
1692
1692
1693 serverlogs = opts.get('serverlog')
1693 serverlogs = opts.get('serverlog')
1694 if serverlogs:
1694 if serverlogs:
1695 for filename in serverlogs:
1695 for filename in serverlogs:
1696 logfile = open(filename, 'r')
1696 logfile = open(filename, 'r')
1697 try:
1697 try:
1698 line = logfile.readline()
1698 line = logfile.readline()
1699 while line:
1699 while line:
1700 parts = line.strip().split(';')
1700 parts = line.strip().split(';')
1701 op = parts[1]
1701 op = parts[1]
1702 if op == 'cg':
1702 if op == 'cg':
1703 pass
1703 pass
1704 elif op == 'cgss':
1704 elif op == 'cgss':
1705 doit(parts[2].split(' '), parts[3].split(' '))
1705 doit(parts[2].split(' '), parts[3].split(' '))
1706 elif op == 'unb':
1706 elif op == 'unb':
1707 doit(parts[3].split(' '), parts[2].split(' '))
1707 doit(parts[3].split(' '), parts[2].split(' '))
1708 line = logfile.readline()
1708 line = logfile.readline()
1709 finally:
1709 finally:
1710 logfile.close()
1710 logfile.close()
1711
1711
1712 else:
1712 else:
1713 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1713 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1714 opts.get('remote_head'))
1714 opts.get('remote_head'))
1715 localrevs = opts.get('local_head')
1715 localrevs = opts.get('local_head')
1716 doit(localrevs, remoterevs)
1716 doit(localrevs, remoterevs)
1717
1717
1718 @command('debugfileset', [], ('REVSPEC'))
1718 @command('debugfileset', [], ('REVSPEC'))
1719 def debugfileset(ui, repo, expr):
1719 def debugfileset(ui, repo, expr):
1720 '''parse and apply a fileset specification'''
1720 '''parse and apply a fileset specification'''
1721 if ui.verbose:
1721 if ui.verbose:
1722 tree = fileset.parse(expr)[0]
1722 tree = fileset.parse(expr)[0]
1723 ui.note(tree, "\n")
1723 ui.note(tree, "\n")
1724
1724
1725 for f in fileset.getfileset(repo[None], expr):
1725 for f in fileset.getfileset(repo[None], expr):
1726 ui.write("%s\n" % f)
1726 ui.write("%s\n" % f)
1727
1727
1728 @command('debugfsinfo', [], _('[PATH]'))
1728 @command('debugfsinfo', [], _('[PATH]'))
1729 def debugfsinfo(ui, path = "."):
1729 def debugfsinfo(ui, path = "."):
1730 """show information detected about current filesystem"""
1730 """show information detected about current filesystem"""
1731 util.writefile('.debugfsinfo', '')
1731 util.writefile('.debugfsinfo', '')
1732 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1732 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1733 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1733 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1734 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1734 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1735 and 'yes' or 'no'))
1735 and 'yes' or 'no'))
1736 os.unlink('.debugfsinfo')
1736 os.unlink('.debugfsinfo')
1737
1737
1738 @command('debuggetbundle',
1738 @command('debuggetbundle',
1739 [('H', 'head', [], _('id of head node'), _('ID')),
1739 [('H', 'head', [], _('id of head node'), _('ID')),
1740 ('C', 'common', [], _('id of common node'), _('ID')),
1740 ('C', 'common', [], _('id of common node'), _('ID')),
1741 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1741 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1742 _('REPO FILE [-H|-C ID]...'))
1742 _('REPO FILE [-H|-C ID]...'))
1743 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1743 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1744 """retrieves a bundle from a repo
1744 """retrieves a bundle from a repo
1745
1745
1746 Every ID must be a full-length hex node id string. Saves the bundle to the
1746 Every ID must be a full-length hex node id string. Saves the bundle to the
1747 given file.
1747 given file.
1748 """
1748 """
1749 repo = hg.peer(ui, opts, repopath)
1749 repo = hg.peer(ui, opts, repopath)
1750 if not repo.capable('getbundle'):
1750 if not repo.capable('getbundle'):
1751 raise util.Abort("getbundle() not supported by target repository")
1751 raise util.Abort("getbundle() not supported by target repository")
1752 args = {}
1752 args = {}
1753 if common:
1753 if common:
1754 args['common'] = [bin(s) for s in common]
1754 args['common'] = [bin(s) for s in common]
1755 if head:
1755 if head:
1756 args['heads'] = [bin(s) for s in head]
1756 args['heads'] = [bin(s) for s in head]
1757 bundle = repo.getbundle('debug', **args)
1757 bundle = repo.getbundle('debug', **args)
1758
1758
1759 bundletype = opts.get('type', 'bzip2').lower()
1759 bundletype = opts.get('type', 'bzip2').lower()
1760 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1760 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1761 bundletype = btypes.get(bundletype)
1761 bundletype = btypes.get(bundletype)
1762 if bundletype not in changegroup.bundletypes:
1762 if bundletype not in changegroup.bundletypes:
1763 raise util.Abort(_('unknown bundle type specified with --type'))
1763 raise util.Abort(_('unknown bundle type specified with --type'))
1764 changegroup.writebundle(bundle, bundlepath, bundletype)
1764 changegroup.writebundle(bundle, bundlepath, bundletype)
1765
1765
1766 @command('debugignore', [], '')
1766 @command('debugignore', [], '')
1767 def debugignore(ui, repo, *values, **opts):
1767 def debugignore(ui, repo, *values, **opts):
1768 """display the combined ignore pattern"""
1768 """display the combined ignore pattern"""
1769 ignore = repo.dirstate._ignore
1769 ignore = repo.dirstate._ignore
1770 includepat = getattr(ignore, 'includepat', None)
1770 includepat = getattr(ignore, 'includepat', None)
1771 if includepat is not None:
1771 if includepat is not None:
1772 ui.write("%s\n" % includepat)
1772 ui.write("%s\n" % includepat)
1773 else:
1773 else:
1774 raise util.Abort(_("no ignore patterns found"))
1774 raise util.Abort(_("no ignore patterns found"))
1775
1775
1776 @command('debugindex',
1776 @command('debugindex',
1777 [('c', 'changelog', False, _('open changelog')),
1777 [('c', 'changelog', False, _('open changelog')),
1778 ('m', 'manifest', False, _('open manifest')),
1778 ('m', 'manifest', False, _('open manifest')),
1779 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1779 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1780 _('[-f FORMAT] -c|-m|FILE'))
1780 _('[-f FORMAT] -c|-m|FILE'))
1781 def debugindex(ui, repo, file_ = None, **opts):
1781 def debugindex(ui, repo, file_ = None, **opts):
1782 """dump the contents of an index file"""
1782 """dump the contents of an index file"""
1783 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1783 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1784 format = opts.get('format', 0)
1784 format = opts.get('format', 0)
1785 if format not in (0, 1):
1785 if format not in (0, 1):
1786 raise util.Abort(_("unknown format %d") % format)
1786 raise util.Abort(_("unknown format %d") % format)
1787
1787
1788 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1788 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1789 if generaldelta:
1789 if generaldelta:
1790 basehdr = ' delta'
1790 basehdr = ' delta'
1791 else:
1791 else:
1792 basehdr = ' base'
1792 basehdr = ' base'
1793
1793
1794 if format == 0:
1794 if format == 0:
1795 ui.write(" rev offset length " + basehdr + " linkrev"
1795 ui.write(" rev offset length " + basehdr + " linkrev"
1796 " nodeid p1 p2\n")
1796 " nodeid p1 p2\n")
1797 elif format == 1:
1797 elif format == 1:
1798 ui.write(" rev flag offset length"
1798 ui.write(" rev flag offset length"
1799 " size " + basehdr + " link p1 p2 nodeid\n")
1799 " size " + basehdr + " link p1 p2 nodeid\n")
1800
1800
1801 for i in r:
1801 for i in r:
1802 node = r.node(i)
1802 node = r.node(i)
1803 if generaldelta:
1803 if generaldelta:
1804 base = r.deltaparent(i)
1804 base = r.deltaparent(i)
1805 else:
1805 else:
1806 base = r.chainbase(i)
1806 base = r.chainbase(i)
1807 if format == 0:
1807 if format == 0:
1808 try:
1808 try:
1809 pp = r.parents(node)
1809 pp = r.parents(node)
1810 except:
1810 except:
1811 pp = [nullid, nullid]
1811 pp = [nullid, nullid]
1812 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1812 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1813 i, r.start(i), r.length(i), base, r.linkrev(i),
1813 i, r.start(i), r.length(i), base, r.linkrev(i),
1814 short(node), short(pp[0]), short(pp[1])))
1814 short(node), short(pp[0]), short(pp[1])))
1815 elif format == 1:
1815 elif format == 1:
1816 pr = r.parentrevs(i)
1816 pr = r.parentrevs(i)
1817 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1817 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1818 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1818 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1819 base, r.linkrev(i), pr[0], pr[1], short(node)))
1819 base, r.linkrev(i), pr[0], pr[1], short(node)))
1820
1820
1821 @command('debugindexdot', [], _('FILE'))
1821 @command('debugindexdot', [], _('FILE'))
1822 def debugindexdot(ui, repo, file_):
1822 def debugindexdot(ui, repo, file_):
1823 """dump an index DAG as a graphviz dot file"""
1823 """dump an index DAG as a graphviz dot file"""
1824 r = None
1824 r = None
1825 if repo:
1825 if repo:
1826 filelog = repo.file(file_)
1826 filelog = repo.file(file_)
1827 if len(filelog):
1827 if len(filelog):
1828 r = filelog
1828 r = filelog
1829 if not r:
1829 if not r:
1830 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1830 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1831 ui.write("digraph G {\n")
1831 ui.write("digraph G {\n")
1832 for i in r:
1832 for i in r:
1833 node = r.node(i)
1833 node = r.node(i)
1834 pp = r.parents(node)
1834 pp = r.parents(node)
1835 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1835 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1836 if pp[1] != nullid:
1836 if pp[1] != nullid:
1837 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1837 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1838 ui.write("}\n")
1838 ui.write("}\n")
1839
1839
1840 @command('debuginstall', [], '')
1840 @command('debuginstall', [], '')
1841 def debuginstall(ui):
1841 def debuginstall(ui):
1842 '''test Mercurial installation
1842 '''test Mercurial installation
1843
1843
1844 Returns 0 on success.
1844 Returns 0 on success.
1845 '''
1845 '''
1846
1846
1847 def writetemp(contents):
1847 def writetemp(contents):
1848 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1848 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1849 f = os.fdopen(fd, "wb")
1849 f = os.fdopen(fd, "wb")
1850 f.write(contents)
1850 f.write(contents)
1851 f.close()
1851 f.close()
1852 return name
1852 return name
1853
1853
1854 problems = 0
1854 problems = 0
1855
1855
1856 # encoding
1856 # encoding
1857 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1857 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1858 try:
1858 try:
1859 encoding.fromlocal("test")
1859 encoding.fromlocal("test")
1860 except util.Abort, inst:
1860 except util.Abort, inst:
1861 ui.write(" %s\n" % inst)
1861 ui.write(" %s\n" % inst)
1862 ui.write(_(" (check that your locale is properly set)\n"))
1862 ui.write(_(" (check that your locale is properly set)\n"))
1863 problems += 1
1863 problems += 1
1864
1864
1865 # compiled modules
1865 # compiled modules
1866 ui.status(_("Checking installed modules (%s)...\n")
1866 ui.status(_("Checking installed modules (%s)...\n")
1867 % os.path.dirname(__file__))
1867 % os.path.dirname(__file__))
1868 try:
1868 try:
1869 import bdiff, mpatch, base85, osutil
1869 import bdiff, mpatch, base85, osutil
1870 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
1870 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
1871 except Exception, inst:
1871 except Exception, inst:
1872 ui.write(" %s\n" % inst)
1872 ui.write(" %s\n" % inst)
1873 ui.write(_(" One or more extensions could not be found"))
1873 ui.write(_(" One or more extensions could not be found"))
1874 ui.write(_(" (check that you compiled the extensions)\n"))
1874 ui.write(_(" (check that you compiled the extensions)\n"))
1875 problems += 1
1875 problems += 1
1876
1876
1877 # templates
1877 # templates
1878 import templater
1878 import templater
1879 p = templater.templatepath()
1879 p = templater.templatepath()
1880 ui.status(_("Checking templates (%s)...\n") % ' '.join(p))
1880 ui.status(_("Checking templates (%s)...\n") % ' '.join(p))
1881 try:
1881 try:
1882 templater.templater(templater.templatepath("map-cmdline.default"))
1882 templater.templater(templater.templatepath("map-cmdline.default"))
1883 except Exception, inst:
1883 except Exception, inst:
1884 ui.write(" %s\n" % inst)
1884 ui.write(" %s\n" % inst)
1885 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1885 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1886 problems += 1
1886 problems += 1
1887
1887
1888 # editor
1888 # editor
1889 ui.status(_("Checking commit editor...\n"))
1889 ui.status(_("Checking commit editor...\n"))
1890 editor = ui.geteditor()
1890 editor = ui.geteditor()
1891 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
1891 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
1892 if not cmdpath:
1892 if not cmdpath:
1893 if editor == 'vi':
1893 if editor == 'vi':
1894 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1894 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1895 ui.write(_(" (specify a commit editor in your configuration"
1895 ui.write(_(" (specify a commit editor in your configuration"
1896 " file)\n"))
1896 " file)\n"))
1897 else:
1897 else:
1898 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1898 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1899 ui.write(_(" (specify a commit editor in your configuration"
1899 ui.write(_(" (specify a commit editor in your configuration"
1900 " file)\n"))
1900 " file)\n"))
1901 problems += 1
1901 problems += 1
1902
1902
1903 # check username
1903 # check username
1904 ui.status(_("Checking username...\n"))
1904 ui.status(_("Checking username...\n"))
1905 try:
1905 try:
1906 ui.username()
1906 ui.username()
1907 except util.Abort, e:
1907 except util.Abort, e:
1908 ui.write(" %s\n" % e)
1908 ui.write(" %s\n" % e)
1909 ui.write(_(" (specify a username in your configuration file)\n"))
1909 ui.write(_(" (specify a username in your configuration file)\n"))
1910 problems += 1
1910 problems += 1
1911
1911
1912 if not problems:
1912 if not problems:
1913 ui.status(_("No problems detected\n"))
1913 ui.status(_("No problems detected\n"))
1914 else:
1914 else:
1915 ui.write(_("%s problems detected,"
1915 ui.write(_("%s problems detected,"
1916 " please check your install!\n") % problems)
1916 " please check your install!\n") % problems)
1917
1917
1918 return problems
1918 return problems
1919
1919
1920 @command('debugknown', [], _('REPO ID...'))
1920 @command('debugknown', [], _('REPO ID...'))
1921 def debugknown(ui, repopath, *ids, **opts):
1921 def debugknown(ui, repopath, *ids, **opts):
1922 """test whether node ids are known to a repo
1922 """test whether node ids are known to a repo
1923
1923
1924 Every ID must be a full-length hex node id string. Returns a list of 0s and 1s
1924 Every ID must be a full-length hex node id string. Returns a list of 0s and 1s
1925 indicating unknown/known.
1925 indicating unknown/known.
1926 """
1926 """
1927 repo = hg.peer(ui, opts, repopath)
1927 repo = hg.peer(ui, opts, repopath)
1928 if not repo.capable('known'):
1928 if not repo.capable('known'):
1929 raise util.Abort("known() not supported by target repository")
1929 raise util.Abort("known() not supported by target repository")
1930 flags = repo.known([bin(s) for s in ids])
1930 flags = repo.known([bin(s) for s in ids])
1931 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1931 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1932
1932
1933 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
1933 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
1934 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
1934 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
1935 '''access the pushkey key/value protocol
1935 '''access the pushkey key/value protocol
1936
1936
1937 With two args, list the keys in the given namespace.
1937 With two args, list the keys in the given namespace.
1938
1938
1939 With five args, set a key to new if it currently is set to old.
1939 With five args, set a key to new if it currently is set to old.
1940 Reports success or failure.
1940 Reports success or failure.
1941 '''
1941 '''
1942
1942
1943 target = hg.peer(ui, {}, repopath)
1943 target = hg.peer(ui, {}, repopath)
1944 if keyinfo:
1944 if keyinfo:
1945 key, old, new = keyinfo
1945 key, old, new = keyinfo
1946 r = target.pushkey(namespace, key, old, new)
1946 r = target.pushkey(namespace, key, old, new)
1947 ui.status(str(r) + '\n')
1947 ui.status(str(r) + '\n')
1948 return not r
1948 return not r
1949 else:
1949 else:
1950 for k, v in target.listkeys(namespace).iteritems():
1950 for k, v in target.listkeys(namespace).iteritems():
1951 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1951 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1952 v.encode('string-escape')))
1952 v.encode('string-escape')))
1953
1953
1954 @command('debugrebuildstate',
1954 @command('debugrebuildstate',
1955 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
1955 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
1956 _('[-r REV] [REV]'))
1956 _('[-r REV] [REV]'))
1957 def debugrebuildstate(ui, repo, rev="tip"):
1957 def debugrebuildstate(ui, repo, rev="tip"):
1958 """rebuild the dirstate as it would look like for the given revision"""
1958 """rebuild the dirstate as it would look like for the given revision"""
1959 ctx = scmutil.revsingle(repo, rev)
1959 ctx = scmutil.revsingle(repo, rev)
1960 wlock = repo.wlock()
1960 wlock = repo.wlock()
1961 try:
1961 try:
1962 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1962 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1963 finally:
1963 finally:
1964 wlock.release()
1964 wlock.release()
1965
1965
1966 @command('debugrename',
1966 @command('debugrename',
1967 [('r', 'rev', '', _('revision to debug'), _('REV'))],
1967 [('r', 'rev', '', _('revision to debug'), _('REV'))],
1968 _('[-r REV] FILE'))
1968 _('[-r REV] FILE'))
1969 def debugrename(ui, repo, file1, *pats, **opts):
1969 def debugrename(ui, repo, file1, *pats, **opts):
1970 """dump rename information"""
1970 """dump rename information"""
1971
1971
1972 ctx = scmutil.revsingle(repo, opts.get('rev'))
1972 ctx = scmutil.revsingle(repo, opts.get('rev'))
1973 m = scmutil.match(ctx, (file1,) + pats, opts)
1973 m = scmutil.match(ctx, (file1,) + pats, opts)
1974 for abs in ctx.walk(m):
1974 for abs in ctx.walk(m):
1975 fctx = ctx[abs]
1975 fctx = ctx[abs]
1976 o = fctx.filelog().renamed(fctx.filenode())
1976 o = fctx.filelog().renamed(fctx.filenode())
1977 rel = m.rel(abs)
1977 rel = m.rel(abs)
1978 if o:
1978 if o:
1979 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1979 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1980 else:
1980 else:
1981 ui.write(_("%s not renamed\n") % rel)
1981 ui.write(_("%s not renamed\n") % rel)
1982
1982
1983 @command('debugrevlog',
1983 @command('debugrevlog',
1984 [('c', 'changelog', False, _('open changelog')),
1984 [('c', 'changelog', False, _('open changelog')),
1985 ('m', 'manifest', False, _('open manifest')),
1985 ('m', 'manifest', False, _('open manifest')),
1986 ('d', 'dump', False, _('dump index data'))],
1986 ('d', 'dump', False, _('dump index data'))],
1987 _('-c|-m|FILE'))
1987 _('-c|-m|FILE'))
1988 def debugrevlog(ui, repo, file_ = None, **opts):
1988 def debugrevlog(ui, repo, file_ = None, **opts):
1989 """show data and statistics about a revlog"""
1989 """show data and statistics about a revlog"""
1990 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
1990 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
1991
1991
1992 if opts.get("dump"):
1992 if opts.get("dump"):
1993 numrevs = len(r)
1993 numrevs = len(r)
1994 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
1994 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
1995 " rawsize totalsize compression heads\n")
1995 " rawsize totalsize compression heads\n")
1996 ts = 0
1996 ts = 0
1997 heads = set()
1997 heads = set()
1998 for rev in xrange(numrevs):
1998 for rev in xrange(numrevs):
1999 dbase = r.deltaparent(rev)
1999 dbase = r.deltaparent(rev)
2000 if dbase == -1:
2000 if dbase == -1:
2001 dbase = rev
2001 dbase = rev
2002 cbase = r.chainbase(rev)
2002 cbase = r.chainbase(rev)
2003 p1, p2 = r.parentrevs(rev)
2003 p1, p2 = r.parentrevs(rev)
2004 rs = r.rawsize(rev)
2004 rs = r.rawsize(rev)
2005 ts = ts + rs
2005 ts = ts + rs
2006 heads -= set(r.parentrevs(rev))
2006 heads -= set(r.parentrevs(rev))
2007 heads.add(rev)
2007 heads.add(rev)
2008 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
2008 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
2009 (rev, p1, p2, r.start(rev), r.end(rev),
2009 (rev, p1, p2, r.start(rev), r.end(rev),
2010 r.start(dbase), r.start(cbase),
2010 r.start(dbase), r.start(cbase),
2011 r.start(p1), r.start(p2),
2011 r.start(p1), r.start(p2),
2012 rs, ts, ts / r.end(rev), len(heads)))
2012 rs, ts, ts / r.end(rev), len(heads)))
2013 return 0
2013 return 0
2014
2014
2015 v = r.version
2015 v = r.version
2016 format = v & 0xFFFF
2016 format = v & 0xFFFF
2017 flags = []
2017 flags = []
2018 gdelta = False
2018 gdelta = False
2019 if v & revlog.REVLOGNGINLINEDATA:
2019 if v & revlog.REVLOGNGINLINEDATA:
2020 flags.append('inline')
2020 flags.append('inline')
2021 if v & revlog.REVLOGGENERALDELTA:
2021 if v & revlog.REVLOGGENERALDELTA:
2022 gdelta = True
2022 gdelta = True
2023 flags.append('generaldelta')
2023 flags.append('generaldelta')
2024 if not flags:
2024 if not flags:
2025 flags = ['(none)']
2025 flags = ['(none)']
2026
2026
2027 nummerges = 0
2027 nummerges = 0
2028 numfull = 0
2028 numfull = 0
2029 numprev = 0
2029 numprev = 0
2030 nump1 = 0
2030 nump1 = 0
2031 nump2 = 0
2031 nump2 = 0
2032 numother = 0
2032 numother = 0
2033 nump1prev = 0
2033 nump1prev = 0
2034 nump2prev = 0
2034 nump2prev = 0
2035 chainlengths = []
2035 chainlengths = []
2036
2036
2037 datasize = [None, 0, 0L]
2037 datasize = [None, 0, 0L]
2038 fullsize = [None, 0, 0L]
2038 fullsize = [None, 0, 0L]
2039 deltasize = [None, 0, 0L]
2039 deltasize = [None, 0, 0L]
2040
2040
2041 def addsize(size, l):
2041 def addsize(size, l):
2042 if l[0] is None or size < l[0]:
2042 if l[0] is None or size < l[0]:
2043 l[0] = size
2043 l[0] = size
2044 if size > l[1]:
2044 if size > l[1]:
2045 l[1] = size
2045 l[1] = size
2046 l[2] += size
2046 l[2] += size
2047
2047
2048 numrevs = len(r)
2048 numrevs = len(r)
2049 for rev in xrange(numrevs):
2049 for rev in xrange(numrevs):
2050 p1, p2 = r.parentrevs(rev)
2050 p1, p2 = r.parentrevs(rev)
2051 delta = r.deltaparent(rev)
2051 delta = r.deltaparent(rev)
2052 if format > 0:
2052 if format > 0:
2053 addsize(r.rawsize(rev), datasize)
2053 addsize(r.rawsize(rev), datasize)
2054 if p2 != nullrev:
2054 if p2 != nullrev:
2055 nummerges += 1
2055 nummerges += 1
2056 size = r.length(rev)
2056 size = r.length(rev)
2057 if delta == nullrev:
2057 if delta == nullrev:
2058 chainlengths.append(0)
2058 chainlengths.append(0)
2059 numfull += 1
2059 numfull += 1
2060 addsize(size, fullsize)
2060 addsize(size, fullsize)
2061 else:
2061 else:
2062 chainlengths.append(chainlengths[delta] + 1)
2062 chainlengths.append(chainlengths[delta] + 1)
2063 addsize(size, deltasize)
2063 addsize(size, deltasize)
2064 if delta == rev - 1:
2064 if delta == rev - 1:
2065 numprev += 1
2065 numprev += 1
2066 if delta == p1:
2066 if delta == p1:
2067 nump1prev += 1
2067 nump1prev += 1
2068 elif delta == p2:
2068 elif delta == p2:
2069 nump2prev += 1
2069 nump2prev += 1
2070 elif delta == p1:
2070 elif delta == p1:
2071 nump1 += 1
2071 nump1 += 1
2072 elif delta == p2:
2072 elif delta == p2:
2073 nump2 += 1
2073 nump2 += 1
2074 elif delta != nullrev:
2074 elif delta != nullrev:
2075 numother += 1
2075 numother += 1
2076
2076
2077 numdeltas = numrevs - numfull
2077 numdeltas = numrevs - numfull
2078 numoprev = numprev - nump1prev - nump2prev
2078 numoprev = numprev - nump1prev - nump2prev
2079 totalrawsize = datasize[2]
2079 totalrawsize = datasize[2]
2080 datasize[2] /= numrevs
2080 datasize[2] /= numrevs
2081 fulltotal = fullsize[2]
2081 fulltotal = fullsize[2]
2082 fullsize[2] /= numfull
2082 fullsize[2] /= numfull
2083 deltatotal = deltasize[2]
2083 deltatotal = deltasize[2]
2084 deltasize[2] /= numrevs - numfull
2084 deltasize[2] /= numrevs - numfull
2085 totalsize = fulltotal + deltatotal
2085 totalsize = fulltotal + deltatotal
2086 avgchainlen = sum(chainlengths) / numrevs
2086 avgchainlen = sum(chainlengths) / numrevs
2087 compratio = totalrawsize / totalsize
2087 compratio = totalrawsize / totalsize
2088
2088
2089 basedfmtstr = '%%%dd\n'
2089 basedfmtstr = '%%%dd\n'
2090 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2090 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2091
2091
2092 def dfmtstr(max):
2092 def dfmtstr(max):
2093 return basedfmtstr % len(str(max))
2093 return basedfmtstr % len(str(max))
2094 def pcfmtstr(max, padding=0):
2094 def pcfmtstr(max, padding=0):
2095 return basepcfmtstr % (len(str(max)), ' ' * padding)
2095 return basepcfmtstr % (len(str(max)), ' ' * padding)
2096
2096
2097 def pcfmt(value, total):
2097 def pcfmt(value, total):
2098 return (value, 100 * float(value) / total)
2098 return (value, 100 * float(value) / total)
2099
2099
2100 ui.write('format : %d\n' % format)
2100 ui.write('format : %d\n' % format)
2101 ui.write('flags : %s\n' % ', '.join(flags))
2101 ui.write('flags : %s\n' % ', '.join(flags))
2102
2102
2103 ui.write('\n')
2103 ui.write('\n')
2104 fmt = pcfmtstr(totalsize)
2104 fmt = pcfmtstr(totalsize)
2105 fmt2 = dfmtstr(totalsize)
2105 fmt2 = dfmtstr(totalsize)
2106 ui.write('revisions : ' + fmt2 % numrevs)
2106 ui.write('revisions : ' + fmt2 % numrevs)
2107 ui.write(' merges : ' + fmt % pcfmt(nummerges, numrevs))
2107 ui.write(' merges : ' + fmt % pcfmt(nummerges, numrevs))
2108 ui.write(' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs))
2108 ui.write(' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs))
2109 ui.write('revisions : ' + fmt2 % numrevs)
2109 ui.write('revisions : ' + fmt2 % numrevs)
2110 ui.write(' full : ' + fmt % pcfmt(numfull, numrevs))
2110 ui.write(' full : ' + fmt % pcfmt(numfull, numrevs))
2111 ui.write(' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
2111 ui.write(' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
2112 ui.write('revision size : ' + fmt2 % totalsize)
2112 ui.write('revision size : ' + fmt2 % totalsize)
2113 ui.write(' full : ' + fmt % pcfmt(fulltotal, totalsize))
2113 ui.write(' full : ' + fmt % pcfmt(fulltotal, totalsize))
2114 ui.write(' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
2114 ui.write(' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
2115
2115
2116 ui.write('\n')
2116 ui.write('\n')
2117 fmt = dfmtstr(max(avgchainlen, compratio))
2117 fmt = dfmtstr(max(avgchainlen, compratio))
2118 ui.write('avg chain length : ' + fmt % avgchainlen)
2118 ui.write('avg chain length : ' + fmt % avgchainlen)
2119 ui.write('compression ratio : ' + fmt % compratio)
2119 ui.write('compression ratio : ' + fmt % compratio)
2120
2120
2121 if format > 0:
2121 if format > 0:
2122 ui.write('\n')
2122 ui.write('\n')
2123 ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
2123 ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
2124 % tuple(datasize))
2124 % tuple(datasize))
2125 ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
2125 ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
2126 % tuple(fullsize))
2126 % tuple(fullsize))
2127 ui.write('delta size (min/max/avg) : %d / %d / %d\n'
2127 ui.write('delta size (min/max/avg) : %d / %d / %d\n'
2128 % tuple(deltasize))
2128 % tuple(deltasize))
2129
2129
2130 if numdeltas > 0:
2130 if numdeltas > 0:
2131 ui.write('\n')
2131 ui.write('\n')
2132 fmt = pcfmtstr(numdeltas)
2132 fmt = pcfmtstr(numdeltas)
2133 fmt2 = pcfmtstr(numdeltas, 4)
2133 fmt2 = pcfmtstr(numdeltas, 4)
2134 ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
2134 ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
2135 if numprev > 0:
2135 if numprev > 0:
2136 ui.write(' where prev = p1 : ' + fmt2 % pcfmt(nump1prev, numprev))
2136 ui.write(' where prev = p1 : ' + fmt2 % pcfmt(nump1prev, numprev))
2137 ui.write(' where prev = p2 : ' + fmt2 % pcfmt(nump2prev, numprev))
2137 ui.write(' where prev = p2 : ' + fmt2 % pcfmt(nump2prev, numprev))
2138 ui.write(' other : ' + fmt2 % pcfmt(numoprev, numprev))
2138 ui.write(' other : ' + fmt2 % pcfmt(numoprev, numprev))
2139 if gdelta:
2139 if gdelta:
2140 ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
2140 ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
2141 ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
2141 ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
2142 ui.write('deltas against other : ' + fmt % pcfmt(numother, numdeltas))
2142 ui.write('deltas against other : ' + fmt % pcfmt(numother, numdeltas))
2143
2143
2144 @command('debugrevspec', [], ('REVSPEC'))
2144 @command('debugrevspec', [], ('REVSPEC'))
2145 def debugrevspec(ui, repo, expr):
2145 def debugrevspec(ui, repo, expr):
2146 '''parse and apply a revision specification'''
2146 '''parse and apply a revision specification'''
2147 if ui.verbose:
2147 if ui.verbose:
2148 tree = revset.parse(expr)[0]
2148 tree = revset.parse(expr)[0]
2149 ui.note(tree, "\n")
2149 ui.note(tree, "\n")
2150 newtree = revset.findaliases(ui, tree)
2150 newtree = revset.findaliases(ui, tree)
2151 if newtree != tree:
2151 if newtree != tree:
2152 ui.note(newtree, "\n")
2152 ui.note(newtree, "\n")
2153 func = revset.match(ui, expr)
2153 func = revset.match(ui, expr)
2154 for c in func(repo, range(len(repo))):
2154 for c in func(repo, range(len(repo))):
2155 ui.write("%s\n" % c)
2155 ui.write("%s\n" % c)
2156
2156
2157 @command('debugsetparents', [], _('REV1 [REV2]'))
2157 @command('debugsetparents', [], _('REV1 [REV2]'))
2158 def debugsetparents(ui, repo, rev1, rev2=None):
2158 def debugsetparents(ui, repo, rev1, rev2=None):
2159 """manually set the parents of the current working directory
2159 """manually set the parents of the current working directory
2160
2160
2161 This is useful for writing repository conversion tools, but should
2161 This is useful for writing repository conversion tools, but should
2162 be used with care.
2162 be used with care.
2163
2163
2164 Returns 0 on success.
2164 Returns 0 on success.
2165 """
2165 """
2166
2166
2167 r1 = scmutil.revsingle(repo, rev1).node()
2167 r1 = scmutil.revsingle(repo, rev1).node()
2168 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2168 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2169
2169
2170 wlock = repo.wlock()
2170 wlock = repo.wlock()
2171 try:
2171 try:
2172 repo.dirstate.setparents(r1, r2)
2172 repo.dirstate.setparents(r1, r2)
2173 finally:
2173 finally:
2174 wlock.release()
2174 wlock.release()
2175
2175
2176 @command('debugstate',
2176 @command('debugstate',
2177 [('', 'nodates', None, _('do not display the saved mtime')),
2177 [('', 'nodates', None, _('do not display the saved mtime')),
2178 ('', 'datesort', None, _('sort by saved mtime'))],
2178 ('', 'datesort', None, _('sort by saved mtime'))],
2179 _('[OPTION]...'))
2179 _('[OPTION]...'))
2180 def debugstate(ui, repo, nodates=None, datesort=None):
2180 def debugstate(ui, repo, nodates=None, datesort=None):
2181 """show the contents of the current dirstate"""
2181 """show the contents of the current dirstate"""
2182 timestr = ""
2182 timestr = ""
2183 showdate = not nodates
2183 showdate = not nodates
2184 if datesort:
2184 if datesort:
2185 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2185 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2186 else:
2186 else:
2187 keyfunc = None # sort by filename
2187 keyfunc = None # sort by filename
2188 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2188 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2189 if showdate:
2189 if showdate:
2190 if ent[3] == -1:
2190 if ent[3] == -1:
2191 # Pad or slice to locale representation
2191 # Pad or slice to locale representation
2192 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2192 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2193 time.localtime(0)))
2193 time.localtime(0)))
2194 timestr = 'unset'
2194 timestr = 'unset'
2195 timestr = (timestr[:locale_len] +
2195 timestr = (timestr[:locale_len] +
2196 ' ' * (locale_len - len(timestr)))
2196 ' ' * (locale_len - len(timestr)))
2197 else:
2197 else:
2198 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2198 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2199 time.localtime(ent[3]))
2199 time.localtime(ent[3]))
2200 if ent[1] & 020000:
2200 if ent[1] & 020000:
2201 mode = 'lnk'
2201 mode = 'lnk'
2202 else:
2202 else:
2203 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2203 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2204 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2204 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2205 for f in repo.dirstate.copies():
2205 for f in repo.dirstate.copies():
2206 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2206 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2207
2207
2208 @command('debugsub',
2208 @command('debugsub',
2209 [('r', 'rev', '',
2209 [('r', 'rev', '',
2210 _('revision to check'), _('REV'))],
2210 _('revision to check'), _('REV'))],
2211 _('[-r REV] [REV]'))
2211 _('[-r REV] [REV]'))
2212 def debugsub(ui, repo, rev=None):
2212 def debugsub(ui, repo, rev=None):
2213 ctx = scmutil.revsingle(repo, rev, None)
2213 ctx = scmutil.revsingle(repo, rev, None)
2214 for k, v in sorted(ctx.substate.items()):
2214 for k, v in sorted(ctx.substate.items()):
2215 ui.write('path %s\n' % k)
2215 ui.write('path %s\n' % k)
2216 ui.write(' source %s\n' % v[0])
2216 ui.write(' source %s\n' % v[0])
2217 ui.write(' revision %s\n' % v[1])
2217 ui.write(' revision %s\n' % v[1])
2218
2218
2219 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2219 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2220 def debugwalk(ui, repo, *pats, **opts):
2220 def debugwalk(ui, repo, *pats, **opts):
2221 """show how files match on given patterns"""
2221 """show how files match on given patterns"""
2222 m = scmutil.match(repo[None], pats, opts)
2222 m = scmutil.match(repo[None], pats, opts)
2223 items = list(repo.walk(m))
2223 items = list(repo.walk(m))
2224 if not items:
2224 if not items:
2225 return
2225 return
2226 fmt = 'f %%-%ds %%-%ds %%s' % (
2226 fmt = 'f %%-%ds %%-%ds %%s' % (
2227 max([len(abs) for abs in items]),
2227 max([len(abs) for abs in items]),
2228 max([len(m.rel(abs)) for abs in items]))
2228 max([len(m.rel(abs)) for abs in items]))
2229 for abs in items:
2229 for abs in items:
2230 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
2230 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
2231 ui.write("%s\n" % line.rstrip())
2231 ui.write("%s\n" % line.rstrip())
2232
2232
2233 @command('debugwireargs',
2233 @command('debugwireargs',
2234 [('', 'three', '', 'three'),
2234 [('', 'three', '', 'three'),
2235 ('', 'four', '', 'four'),
2235 ('', 'four', '', 'four'),
2236 ('', 'five', '', 'five'),
2236 ('', 'five', '', 'five'),
2237 ] + remoteopts,
2237 ] + remoteopts,
2238 _('REPO [OPTIONS]... [ONE [TWO]]'))
2238 _('REPO [OPTIONS]... [ONE [TWO]]'))
2239 def debugwireargs(ui, repopath, *vals, **opts):
2239 def debugwireargs(ui, repopath, *vals, **opts):
2240 repo = hg.peer(ui, opts, repopath)
2240 repo = hg.peer(ui, opts, repopath)
2241 for opt in remoteopts:
2241 for opt in remoteopts:
2242 del opts[opt[1]]
2242 del opts[opt[1]]
2243 args = {}
2243 args = {}
2244 for k, v in opts.iteritems():
2244 for k, v in opts.iteritems():
2245 if v:
2245 if v:
2246 args[k] = v
2246 args[k] = v
2247 # run twice to check that we don't mess up the stream for the next command
2247 # run twice to check that we don't mess up the stream for the next command
2248 res1 = repo.debugwireargs(*vals, **args)
2248 res1 = repo.debugwireargs(*vals, **args)
2249 res2 = repo.debugwireargs(*vals, **args)
2249 res2 = repo.debugwireargs(*vals, **args)
2250 ui.write("%s\n" % res1)
2250 ui.write("%s\n" % res1)
2251 if res1 != res2:
2251 if res1 != res2:
2252 ui.warn("%s\n" % res2)
2252 ui.warn("%s\n" % res2)
2253
2253
2254 @command('^diff',
2254 @command('^diff',
2255 [('r', 'rev', [], _('revision'), _('REV')),
2255 [('r', 'rev', [], _('revision'), _('REV')),
2256 ('c', 'change', '', _('change made by revision'), _('REV'))
2256 ('c', 'change', '', _('change made by revision'), _('REV'))
2257 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2257 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2258 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2258 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2259 def diff(ui, repo, *pats, **opts):
2259 def diff(ui, repo, *pats, **opts):
2260 """diff repository (or selected files)
2260 """diff repository (or selected files)
2261
2261
2262 Show differences between revisions for the specified files.
2262 Show differences between revisions for the specified files.
2263
2263
2264 Differences between files are shown using the unified diff format.
2264 Differences between files are shown using the unified diff format.
2265
2265
2266 .. note::
2266 .. note::
2267 diff may generate unexpected results for merges, as it will
2267 diff may generate unexpected results for merges, as it will
2268 default to comparing against the working directory's first
2268 default to comparing against the working directory's first
2269 parent changeset if no revisions are specified.
2269 parent changeset if no revisions are specified.
2270
2270
2271 When two revision arguments are given, then changes are shown
2271 When two revision arguments are given, then changes are shown
2272 between those revisions. If only one revision is specified then
2272 between those revisions. If only one revision is specified then
2273 that revision is compared to the working directory, and, when no
2273 that revision is compared to the working directory, and, when no
2274 revisions are specified, the working directory files are compared
2274 revisions are specified, the working directory files are compared
2275 to its parent.
2275 to its parent.
2276
2276
2277 Alternatively you can specify -c/--change with a revision to see
2277 Alternatively you can specify -c/--change with a revision to see
2278 the changes in that changeset relative to its first parent.
2278 the changes in that changeset relative to its first parent.
2279
2279
2280 Without the -a/--text option, diff will avoid generating diffs of
2280 Without the -a/--text option, diff will avoid generating diffs of
2281 files it detects as binary. With -a, diff will generate a diff
2281 files it detects as binary. With -a, diff will generate a diff
2282 anyway, probably with undesirable results.
2282 anyway, probably with undesirable results.
2283
2283
2284 Use the -g/--git option to generate diffs in the git extended diff
2284 Use the -g/--git option to generate diffs in the git extended diff
2285 format. For more information, read :hg:`help diffs`.
2285 format. For more information, read :hg:`help diffs`.
2286
2286
2287 .. container:: verbose
2287 .. container:: verbose
2288
2288
2289 Examples:
2289 Examples:
2290
2290
2291 - compare a file in the current working directory to its parent::
2291 - compare a file in the current working directory to its parent::
2292
2292
2293 hg diff foo.c
2293 hg diff foo.c
2294
2294
2295 - compare two historical versions of a directory, with rename info::
2295 - compare two historical versions of a directory, with rename info::
2296
2296
2297 hg diff --git -r 1.0:1.2 lib/
2297 hg diff --git -r 1.0:1.2 lib/
2298
2298
2299 - get change stats relative to the last change on some date::
2299 - get change stats relative to the last change on some date::
2300
2300
2301 hg diff --stat -r "date('may 2')"
2301 hg diff --stat -r "date('may 2')"
2302
2302
2303 - diff all newly-added files that contain a keyword::
2303 - diff all newly-added files that contain a keyword::
2304
2304
2305 hg diff "set:added() and grep(GNU)"
2305 hg diff "set:added() and grep(GNU)"
2306
2306
2307 - compare a revision and its parents::
2307 - compare a revision and its parents::
2308
2308
2309 hg diff -c 9353 # compare against first parent
2309 hg diff -c 9353 # compare against first parent
2310 hg diff -r 9353^:9353 # same using revset syntax
2310 hg diff -r 9353^:9353 # same using revset syntax
2311 hg diff -r 9353^2:9353 # compare against the second parent
2311 hg diff -r 9353^2:9353 # compare against the second parent
2312
2312
2313 Returns 0 on success.
2313 Returns 0 on success.
2314 """
2314 """
2315
2315
2316 revs = opts.get('rev')
2316 revs = opts.get('rev')
2317 change = opts.get('change')
2317 change = opts.get('change')
2318 stat = opts.get('stat')
2318 stat = opts.get('stat')
2319 reverse = opts.get('reverse')
2319 reverse = opts.get('reverse')
2320
2320
2321 if revs and change:
2321 if revs and change:
2322 msg = _('cannot specify --rev and --change at the same time')
2322 msg = _('cannot specify --rev and --change at the same time')
2323 raise util.Abort(msg)
2323 raise util.Abort(msg)
2324 elif change:
2324 elif change:
2325 node2 = scmutil.revsingle(repo, change, None).node()
2325 node2 = scmutil.revsingle(repo, change, None).node()
2326 node1 = repo[node2].p1().node()
2326 node1 = repo[node2].p1().node()
2327 else:
2327 else:
2328 node1, node2 = scmutil.revpair(repo, revs)
2328 node1, node2 = scmutil.revpair(repo, revs)
2329
2329
2330 if reverse:
2330 if reverse:
2331 node1, node2 = node2, node1
2331 node1, node2 = node2, node1
2332
2332
2333 diffopts = patch.diffopts(ui, opts)
2333 diffopts = patch.diffopts(ui, opts)
2334 m = scmutil.match(repo[node2], pats, opts)
2334 m = scmutil.match(repo[node2], pats, opts)
2335 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2335 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2336 listsubrepos=opts.get('subrepos'))
2336 listsubrepos=opts.get('subrepos'))
2337
2337
2338 @command('^export',
2338 @command('^export',
2339 [('o', 'output', '',
2339 [('o', 'output', '',
2340 _('print output to file with formatted name'), _('FORMAT')),
2340 _('print output to file with formatted name'), _('FORMAT')),
2341 ('', 'switch-parent', None, _('diff against the second parent')),
2341 ('', 'switch-parent', None, _('diff against the second parent')),
2342 ('r', 'rev', [], _('revisions to export'), _('REV')),
2342 ('r', 'rev', [], _('revisions to export'), _('REV')),
2343 ] + diffopts,
2343 ] + diffopts,
2344 _('[OPTION]... [-o OUTFILESPEC] REV...'))
2344 _('[OPTION]... [-o OUTFILESPEC] REV...'))
2345 def export(ui, repo, *changesets, **opts):
2345 def export(ui, repo, *changesets, **opts):
2346 """dump the header and diffs for one or more changesets
2346 """dump the header and diffs for one or more changesets
2347
2347
2348 Print the changeset header and diffs for one or more revisions.
2348 Print the changeset header and diffs for one or more revisions.
2349
2349
2350 The information shown in the changeset header is: author, date,
2350 The information shown in the changeset header is: author, date,
2351 branch name (if non-default), changeset hash, parent(s) and commit
2351 branch name (if non-default), changeset hash, parent(s) and commit
2352 comment.
2352 comment.
2353
2353
2354 .. note::
2354 .. note::
2355 export may generate unexpected diff output for merge
2355 export may generate unexpected diff output for merge
2356 changesets, as it will compare the merge changeset against its
2356 changesets, as it will compare the merge changeset against its
2357 first parent only.
2357 first parent only.
2358
2358
2359 Output may be to a file, in which case the name of the file is
2359 Output may be to a file, in which case the name of the file is
2360 given using a format string. The formatting rules are as follows:
2360 given using a format string. The formatting rules are as follows:
2361
2361
2362 :``%%``: literal "%" character
2362 :``%%``: literal "%" character
2363 :``%H``: changeset hash (40 hexadecimal digits)
2363 :``%H``: changeset hash (40 hexadecimal digits)
2364 :``%N``: number of patches being generated
2364 :``%N``: number of patches being generated
2365 :``%R``: changeset revision number
2365 :``%R``: changeset revision number
2366 :``%b``: basename of the exporting repository
2366 :``%b``: basename of the exporting repository
2367 :``%h``: short-form changeset hash (12 hexadecimal digits)
2367 :``%h``: short-form changeset hash (12 hexadecimal digits)
2368 :``%m``: first line of the commit message (only alphanumeric characters)
2368 :``%m``: first line of the commit message (only alphanumeric characters)
2369 :``%n``: zero-padded sequence number, starting at 1
2369 :``%n``: zero-padded sequence number, starting at 1
2370 :``%r``: zero-padded changeset revision number
2370 :``%r``: zero-padded changeset revision number
2371
2371
2372 Without the -a/--text option, export will avoid generating diffs
2372 Without the -a/--text option, export will avoid generating diffs
2373 of files it detects as binary. With -a, export will generate a
2373 of files it detects as binary. With -a, export will generate a
2374 diff anyway, probably with undesirable results.
2374 diff anyway, probably with undesirable results.
2375
2375
2376 Use the -g/--git option to generate diffs in the git extended diff
2376 Use the -g/--git option to generate diffs in the git extended diff
2377 format. See :hg:`help diffs` for more information.
2377 format. See :hg:`help diffs` for more information.
2378
2378
2379 With the --switch-parent option, the diff will be against the
2379 With the --switch-parent option, the diff will be against the
2380 second parent. It can be useful to review a merge.
2380 second parent. It can be useful to review a merge.
2381
2381
2382 .. container:: verbose
2382 .. container:: verbose
2383
2383
2384 Examples:
2384 Examples:
2385
2385
2386 - use export and import to transplant a bugfix to the current
2386 - use export and import to transplant a bugfix to the current
2387 branch::
2387 branch::
2388
2388
2389 hg export -r 9353 | hg import -
2389 hg export -r 9353 | hg import -
2390
2390
2391 - export all the changesets between two revisions to a file with
2391 - export all the changesets between two revisions to a file with
2392 rename information::
2392 rename information::
2393
2393
2394 hg export --git -r 123:150 > changes.txt
2394 hg export --git -r 123:150 > changes.txt
2395
2395
2396 - split outgoing changes into a series of patches with
2396 - split outgoing changes into a series of patches with
2397 descriptive names::
2397 descriptive names::
2398
2398
2399 hg export -r "outgoing()" -o "%n-%m.patch"
2399 hg export -r "outgoing()" -o "%n-%m.patch"
2400
2400
2401 Returns 0 on success.
2401 Returns 0 on success.
2402 """
2402 """
2403 changesets += tuple(opts.get('rev', []))
2403 changesets += tuple(opts.get('rev', []))
2404 if not changesets:
2404 if not changesets:
2405 raise util.Abort(_("export requires at least one changeset"))
2405 raise util.Abort(_("export requires at least one changeset"))
2406 revs = scmutil.revrange(repo, changesets)
2406 revs = scmutil.revrange(repo, changesets)
2407 if len(revs) > 1:
2407 if len(revs) > 1:
2408 ui.note(_('exporting patches:\n'))
2408 ui.note(_('exporting patches:\n'))
2409 else:
2409 else:
2410 ui.note(_('exporting patch:\n'))
2410 ui.note(_('exporting patch:\n'))
2411 cmdutil.export(repo, revs, template=opts.get('output'),
2411 cmdutil.export(repo, revs, template=opts.get('output'),
2412 switch_parent=opts.get('switch_parent'),
2412 switch_parent=opts.get('switch_parent'),
2413 opts=patch.diffopts(ui, opts))
2413 opts=patch.diffopts(ui, opts))
2414
2414
2415 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2415 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2416 def forget(ui, repo, *pats, **opts):
2416 def forget(ui, repo, *pats, **opts):
2417 """forget the specified files on the next commit
2417 """forget the specified files on the next commit
2418
2418
2419 Mark the specified files so they will no longer be tracked
2419 Mark the specified files so they will no longer be tracked
2420 after the next commit.
2420 after the next commit.
2421
2421
2422 This only removes files from the current branch, not from the
2422 This only removes files from the current branch, not from the
2423 entire project history, and it does not delete them from the
2423 entire project history, and it does not delete them from the
2424 working directory.
2424 working directory.
2425
2425
2426 To undo a forget before the next commit, see :hg:`add`.
2426 To undo a forget before the next commit, see :hg:`add`.
2427
2427
2428 .. container:: verbose
2428 .. container:: verbose
2429
2429
2430 Examples:
2430 Examples:
2431
2431
2432 - forget newly-added binary files::
2432 - forget newly-added binary files::
2433
2433
2434 hg forget "set:added() and binary()"
2434 hg forget "set:added() and binary()"
2435
2435
2436 - forget files that would be excluded by .hgignore::
2436 - forget files that would be excluded by .hgignore::
2437
2437
2438 hg forget "set:hgignore()"
2438 hg forget "set:hgignore()"
2439
2439
2440 Returns 0 on success.
2440 Returns 0 on success.
2441 """
2441 """
2442
2442
2443 if not pats:
2443 if not pats:
2444 raise util.Abort(_('no files specified'))
2444 raise util.Abort(_('no files specified'))
2445
2445
2446 wctx = repo[None]
2446 wctx = repo[None]
2447 m = scmutil.match(wctx, pats, opts)
2447 m = scmutil.match(wctx, pats, opts)
2448 s = repo.status(match=m, clean=True)
2448 s = repo.status(match=m, clean=True)
2449 forget = sorted(s[0] + s[1] + s[3] + s[6])
2449 forget = sorted(s[0] + s[1] + s[3] + s[6])
2450 subforget = {}
2450 subforget = {}
2451 errs = 0
2451 errs = 0
2452
2452
2453 for subpath in wctx.substate:
2453 for subpath in wctx.substate:
2454 sub = wctx.sub(subpath)
2454 sub = wctx.sub(subpath)
2455 try:
2455 try:
2456 submatch = matchmod.narrowmatcher(subpath, m)
2456 submatch = matchmod.narrowmatcher(subpath, m)
2457 for fsub in sub.walk(submatch):
2457 for fsub in sub.walk(submatch):
2458 if submatch.exact(fsub):
2458 if submatch.exact(fsub):
2459 subforget[subpath + '/' + fsub] = (fsub, sub)
2459 subforget[subpath + '/' + fsub] = (fsub, sub)
2460 except error.LookupError:
2460 except error.LookupError:
2461 ui.status(_("skipping missing subrepository: %s\n") % subpath)
2461 ui.status(_("skipping missing subrepository: %s\n") % subpath)
2462
2462
2463 for f in m.files():
2463 for f in m.files():
2464 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
2464 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
2465 if f not in subforget:
2465 if f not in subforget:
2466 if os.path.exists(m.rel(f)):
2466 if os.path.exists(m.rel(f)):
2467 ui.warn(_('not removing %s: file is already untracked\n')
2467 ui.warn(_('not removing %s: file is already untracked\n')
2468 % m.rel(f))
2468 % m.rel(f))
2469 errs = 1
2469 errs = 1
2470
2470
2471 for f in forget:
2471 for f in forget:
2472 if ui.verbose or not m.exact(f):
2472 if ui.verbose or not m.exact(f):
2473 ui.status(_('removing %s\n') % m.rel(f))
2473 ui.status(_('removing %s\n') % m.rel(f))
2474
2474
2475 if ui.verbose:
2475 if ui.verbose:
2476 for f in sorted(subforget.keys()):
2476 for f in sorted(subforget.keys()):
2477 ui.status(_('removing %s\n') % m.rel(f))
2477 ui.status(_('removing %s\n') % m.rel(f))
2478
2478
2479 wctx.forget(forget)
2479 wctx.forget(forget)
2480
2480
2481 for f in sorted(subforget.keys()):
2481 for f in sorted(subforget.keys()):
2482 fsub, sub = subforget[f]
2482 fsub, sub = subforget[f]
2483 sub.forget([fsub])
2483 sub.forget([fsub])
2484
2484
2485 return errs
2485 return errs
2486
2486
2487 @command(
2487 @command(
2488 'graft',
2488 'graft',
2489 [('c', 'continue', False, _('resume interrupted graft')),
2489 [('c', 'continue', False, _('resume interrupted graft')),
2490 ('e', 'edit', False, _('invoke editor on commit messages')),
2490 ('e', 'edit', False, _('invoke editor on commit messages')),
2491 ('D', 'currentdate', False,
2491 ('D', 'currentdate', False,
2492 _('record the current date as commit date')),
2492 _('record the current date as commit date')),
2493 ('U', 'currentuser', False,
2493 ('U', 'currentuser', False,
2494 _('record the current user as committer'), _('DATE'))]
2494 _('record the current user as committer'), _('DATE'))]
2495 + commitopts2 + mergetoolopts,
2495 + commitopts2 + mergetoolopts,
2496 _('[OPTION]... REVISION...'))
2496 _('[OPTION]... REVISION...'))
2497 def graft(ui, repo, *revs, **opts):
2497 def graft(ui, repo, *revs, **opts):
2498 '''copy changes from other branches onto the current branch
2498 '''copy changes from other branches onto the current branch
2499
2499
2500 This command uses Mercurial's merge logic to copy individual
2500 This command uses Mercurial's merge logic to copy individual
2501 changes from other branches without merging branches in the
2501 changes from other branches without merging branches in the
2502 history graph. This is sometimes known as 'backporting' or
2502 history graph. This is sometimes known as 'backporting' or
2503 'cherry-picking'. By default, graft will copy user, date, and
2503 'cherry-picking'. By default, graft will copy user, date, and
2504 description from the source changesets.
2504 description from the source changesets.
2505
2505
2506 Changesets that are ancestors of the current revision, that have
2506 Changesets that are ancestors of the current revision, that have
2507 already been grafted, or that are merges will be skipped.
2507 already been grafted, or that are merges will be skipped.
2508
2508
2509 If a graft merge results in conflicts, the graft process is
2509 If a graft merge results in conflicts, the graft process is
2510 interrupted so that the current merge can be manually resolved.
2510 interrupted so that the current merge can be manually resolved.
2511 Once all conflicts are addressed, the graft process can be
2511 Once all conflicts are addressed, the graft process can be
2512 continued with the -c/--continue option.
2512 continued with the -c/--continue option.
2513
2513
2514 .. note::
2514 .. note::
2515 The -c/--continue option does not reapply earlier options.
2515 The -c/--continue option does not reapply earlier options.
2516
2516
2517 .. container:: verbose
2517 .. container:: verbose
2518
2518
2519 Examples:
2519 Examples:
2520
2520
2521 - copy a single change to the stable branch and edit its description::
2521 - copy a single change to the stable branch and edit its description::
2522
2522
2523 hg update stable
2523 hg update stable
2524 hg graft --edit 9393
2524 hg graft --edit 9393
2525
2525
2526 - graft a range of changesets with one exception, updating dates::
2526 - graft a range of changesets with one exception, updating dates::
2527
2527
2528 hg graft -D "2085::2093 and not 2091"
2528 hg graft -D "2085::2093 and not 2091"
2529
2529
2530 - continue a graft after resolving conflicts::
2530 - continue a graft after resolving conflicts::
2531
2531
2532 hg graft -c
2532 hg graft -c
2533
2533
2534 - show the source of a grafted changeset::
2534 - show the source of a grafted changeset::
2535
2535
2536 hg log --debug -r tip
2536 hg log --debug -r tip
2537
2537
2538 Returns 0 on successful completion.
2538 Returns 0 on successful completion.
2539 '''
2539 '''
2540
2540
2541 if not opts.get('user') and opts.get('currentuser'):
2541 if not opts.get('user') and opts.get('currentuser'):
2542 opts['user'] = ui.username()
2542 opts['user'] = ui.username()
2543 if not opts.get('date') and opts.get('currentdate'):
2543 if not opts.get('date') and opts.get('currentdate'):
2544 opts['date'] = "%d %d" % util.makedate()
2544 opts['date'] = "%d %d" % util.makedate()
2545
2545
2546 editor = None
2546 editor = None
2547 if opts.get('edit'):
2547 if opts.get('edit'):
2548 editor = cmdutil.commitforceeditor
2548 editor = cmdutil.commitforceeditor
2549
2549
2550 cont = False
2550 cont = False
2551 if opts['continue']:
2551 if opts['continue']:
2552 cont = True
2552 cont = True
2553 if revs:
2553 if revs:
2554 raise util.Abort(_("can't specify --continue and revisions"))
2554 raise util.Abort(_("can't specify --continue and revisions"))
2555 # read in unfinished revisions
2555 # read in unfinished revisions
2556 try:
2556 try:
2557 nodes = repo.opener.read('graftstate').splitlines()
2557 nodes = repo.opener.read('graftstate').splitlines()
2558 revs = [repo[node].rev() for node in nodes]
2558 revs = [repo[node].rev() for node in nodes]
2559 except IOError, inst:
2559 except IOError, inst:
2560 if inst.errno != errno.ENOENT:
2560 if inst.errno != errno.ENOENT:
2561 raise
2561 raise
2562 raise util.Abort(_("no graft state found, can't continue"))
2562 raise util.Abort(_("no graft state found, can't continue"))
2563 else:
2563 else:
2564 cmdutil.bailifchanged(repo)
2564 cmdutil.bailifchanged(repo)
2565 if not revs:
2565 if not revs:
2566 raise util.Abort(_('no revisions specified'))
2566 raise util.Abort(_('no revisions specified'))
2567 revs = scmutil.revrange(repo, revs)
2567 revs = scmutil.revrange(repo, revs)
2568
2568
2569 # check for merges
2569 # check for merges
2570 for rev in repo.revs('%ld and merge()', revs):
2570 for rev in repo.revs('%ld and merge()', revs):
2571 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2571 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2572 revs.remove(rev)
2572 revs.remove(rev)
2573 if not revs:
2573 if not revs:
2574 return -1
2574 return -1
2575
2575
2576 # check for ancestors of dest branch
2576 # check for ancestors of dest branch
2577 for rev in repo.revs('::. and %ld', revs):
2577 for rev in repo.revs('::. and %ld', revs):
2578 ui.warn(_('skipping ancestor revision %s\n') % rev)
2578 ui.warn(_('skipping ancestor revision %s\n') % rev)
2579 revs.remove(rev)
2579 revs.remove(rev)
2580 if not revs:
2580 if not revs:
2581 return -1
2581 return -1
2582
2582
2583 # analyze revs for earlier grafts
2583 # analyze revs for earlier grafts
2584 ids = {}
2584 ids = {}
2585 for ctx in repo.set("%ld", revs):
2585 for ctx in repo.set("%ld", revs):
2586 ids[ctx.hex()] = ctx.rev()
2586 ids[ctx.hex()] = ctx.rev()
2587 n = ctx.extra().get('source')
2587 n = ctx.extra().get('source')
2588 if n:
2588 if n:
2589 ids[n] = ctx.rev()
2589 ids[n] = ctx.rev()
2590
2590
2591 # check ancestors for earlier grafts
2591 # check ancestors for earlier grafts
2592 ui.debug('scanning for duplicate grafts\n')
2592 ui.debug('scanning for duplicate grafts\n')
2593 for ctx in repo.set("::. - ::%ld", revs):
2593 for ctx in repo.set("::. - ::%ld", revs):
2594 n = ctx.extra().get('source')
2594 n = ctx.extra().get('source')
2595 if n in ids:
2595 if n in ids:
2596 r = repo[n].rev()
2596 r = repo[n].rev()
2597 if r in revs:
2597 if r in revs:
2598 ui.warn(_('skipping already grafted revision %s\n') % r)
2598 ui.warn(_('skipping already grafted revision %s\n') % r)
2599 revs.remove(r)
2599 revs.remove(r)
2600 elif ids[n] in revs:
2600 elif ids[n] in revs:
2601 ui.warn(_('skipping already grafted revision %s '
2601 ui.warn(_('skipping already grafted revision %s '
2602 '(same origin %d)\n') % (ids[n], r))
2602 '(same origin %d)\n') % (ids[n], r))
2603 revs.remove(ids[n])
2603 revs.remove(ids[n])
2604 elif ctx.hex() in ids:
2604 elif ctx.hex() in ids:
2605 r = ids[ctx.hex()]
2605 r = ids[ctx.hex()]
2606 ui.warn(_('skipping already grafted revision %s '
2606 ui.warn(_('skipping already grafted revision %s '
2607 '(was grafted from %d)\n') % (r, ctx.rev()))
2607 '(was grafted from %d)\n') % (r, ctx.rev()))
2608 revs.remove(r)
2608 revs.remove(r)
2609 if not revs:
2609 if not revs:
2610 return -1
2610 return -1
2611
2611
2612 for pos, ctx in enumerate(repo.set("%ld", revs)):
2612 for pos, ctx in enumerate(repo.set("%ld", revs)):
2613 current = repo['.']
2613 current = repo['.']
2614 ui.status(_('grafting revision %s\n') % ctx.rev())
2614 ui.status(_('grafting revision %s\n') % ctx.rev())
2615
2615
2616 # we don't merge the first commit when continuing
2616 # we don't merge the first commit when continuing
2617 if not cont:
2617 if not cont:
2618 # perform the graft merge with p1(rev) as 'ancestor'
2618 # perform the graft merge with p1(rev) as 'ancestor'
2619 try:
2619 try:
2620 # ui.forcemerge is an internal variable, do not document
2620 # ui.forcemerge is an internal variable, do not document
2621 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2621 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2622 stats = mergemod.update(repo, ctx.node(), True, True, False,
2622 stats = mergemod.update(repo, ctx.node(), True, True, False,
2623 ctx.p1().node())
2623 ctx.p1().node())
2624 finally:
2624 finally:
2625 ui.setconfig('ui', 'forcemerge', '')
2625 ui.setconfig('ui', 'forcemerge', '')
2626 # drop the second merge parent
2626 # drop the second merge parent
2627 repo.dirstate.setparents(current.node(), nullid)
2627 repo.dirstate.setparents(current.node(), nullid)
2628 repo.dirstate.write()
2628 repo.dirstate.write()
2629 # fix up dirstate for copies and renames
2629 # fix up dirstate for copies and renames
2630 cmdutil.duplicatecopies(repo, ctx.rev(), current.node(), nullid)
2630 cmdutil.duplicatecopies(repo, ctx.rev(), current.node(), nullid)
2631 # report any conflicts
2631 # report any conflicts
2632 if stats and stats[3] > 0:
2632 if stats and stats[3] > 0:
2633 # write out state for --continue
2633 # write out state for --continue
2634 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2634 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2635 repo.opener.write('graftstate', ''.join(nodelines))
2635 repo.opener.write('graftstate', ''.join(nodelines))
2636 raise util.Abort(
2636 raise util.Abort(
2637 _("unresolved conflicts, can't continue"),
2637 _("unresolved conflicts, can't continue"),
2638 hint=_('use hg resolve and hg graft --continue'))
2638 hint=_('use hg resolve and hg graft --continue'))
2639 else:
2639 else:
2640 cont = False
2640 cont = False
2641
2641
2642 # commit
2642 # commit
2643 source = ctx.extra().get('source')
2643 source = ctx.extra().get('source')
2644 if not source:
2644 if not source:
2645 source = ctx.hex()
2645 source = ctx.hex()
2646 extra = {'source': source}
2646 extra = {'source': source}
2647 user = ctx.user()
2647 user = ctx.user()
2648 if opts.get('user'):
2648 if opts.get('user'):
2649 user = opts['user']
2649 user = opts['user']
2650 date = ctx.date()
2650 date = ctx.date()
2651 if opts.get('date'):
2651 if opts.get('date'):
2652 date = opts['date']
2652 date = opts['date']
2653 repo.commit(text=ctx.description(), user=user,
2653 repo.commit(text=ctx.description(), user=user,
2654 date=date, extra=extra, editor=editor)
2654 date=date, extra=extra, editor=editor)
2655
2655
2656 # remove state when we complete successfully
2656 # remove state when we complete successfully
2657 if os.path.exists(repo.join('graftstate')):
2657 if os.path.exists(repo.join('graftstate')):
2658 util.unlinkpath(repo.join('graftstate'))
2658 util.unlinkpath(repo.join('graftstate'))
2659
2659
2660 return 0
2660 return 0
2661
2661
2662 @command('grep',
2662 @command('grep',
2663 [('0', 'print0', None, _('end fields with NUL')),
2663 [('0', 'print0', None, _('end fields with NUL')),
2664 ('', 'all', None, _('print all revisions that match')),
2664 ('', 'all', None, _('print all revisions that match')),
2665 ('a', 'text', None, _('treat all files as text')),
2665 ('a', 'text', None, _('treat all files as text')),
2666 ('f', 'follow', None,
2666 ('f', 'follow', None,
2667 _('follow changeset history,'
2667 _('follow changeset history,'
2668 ' or file history across copies and renames')),
2668 ' or file history across copies and renames')),
2669 ('i', 'ignore-case', None, _('ignore case when matching')),
2669 ('i', 'ignore-case', None, _('ignore case when matching')),
2670 ('l', 'files-with-matches', None,
2670 ('l', 'files-with-matches', None,
2671 _('print only filenames and revisions that match')),
2671 _('print only filenames and revisions that match')),
2672 ('n', 'line-number', None, _('print matching line numbers')),
2672 ('n', 'line-number', None, _('print matching line numbers')),
2673 ('r', 'rev', [],
2673 ('r', 'rev', [],
2674 _('only search files changed within revision range'), _('REV')),
2674 _('only search files changed within revision range'), _('REV')),
2675 ('u', 'user', None, _('list the author (long with -v)')),
2675 ('u', 'user', None, _('list the author (long with -v)')),
2676 ('d', 'date', None, _('list the date (short with -q)')),
2676 ('d', 'date', None, _('list the date (short with -q)')),
2677 ] + walkopts,
2677 ] + walkopts,
2678 _('[OPTION]... PATTERN [FILE]...'))
2678 _('[OPTION]... PATTERN [FILE]...'))
2679 def grep(ui, repo, pattern, *pats, **opts):
2679 def grep(ui, repo, pattern, *pats, **opts):
2680 """search for a pattern in specified files and revisions
2680 """search for a pattern in specified files and revisions
2681
2681
2682 Search revisions of files for a regular expression.
2682 Search revisions of files for a regular expression.
2683
2683
2684 This command behaves differently than Unix grep. It only accepts
2684 This command behaves differently than Unix grep. It only accepts
2685 Python/Perl regexps. It searches repository history, not the
2685 Python/Perl regexps. It searches repository history, not the
2686 working directory. It always prints the revision number in which a
2686 working directory. It always prints the revision number in which a
2687 match appears.
2687 match appears.
2688
2688
2689 By default, grep only prints output for the first revision of a
2689 By default, grep only prints output for the first revision of a
2690 file in which it finds a match. To get it to print every revision
2690 file in which it finds a match. To get it to print every revision
2691 that contains a change in match status ("-" for a match that
2691 that contains a change in match status ("-" for a match that
2692 becomes a non-match, or "+" for a non-match that becomes a match),
2692 becomes a non-match, or "+" for a non-match that becomes a match),
2693 use the --all flag.
2693 use the --all flag.
2694
2694
2695 Returns 0 if a match is found, 1 otherwise.
2695 Returns 0 if a match is found, 1 otherwise.
2696 """
2696 """
2697 reflags = re.M
2697 reflags = re.M
2698 if opts.get('ignore_case'):
2698 if opts.get('ignore_case'):
2699 reflags |= re.I
2699 reflags |= re.I
2700 try:
2700 try:
2701 regexp = re.compile(pattern, reflags)
2701 regexp = re.compile(pattern, reflags)
2702 except re.error, inst:
2702 except re.error, inst:
2703 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2703 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2704 return 1
2704 return 1
2705 sep, eol = ':', '\n'
2705 sep, eol = ':', '\n'
2706 if opts.get('print0'):
2706 if opts.get('print0'):
2707 sep = eol = '\0'
2707 sep = eol = '\0'
2708
2708
2709 getfile = util.lrucachefunc(repo.file)
2709 getfile = util.lrucachefunc(repo.file)
2710
2710
2711 def matchlines(body):
2711 def matchlines(body):
2712 begin = 0
2712 begin = 0
2713 linenum = 0
2713 linenum = 0
2714 while True:
2714 while True:
2715 match = regexp.search(body, begin)
2715 match = regexp.search(body, begin)
2716 if not match:
2716 if not match:
2717 break
2717 break
2718 mstart, mend = match.span()
2718 mstart, mend = match.span()
2719 linenum += body.count('\n', begin, mstart) + 1
2719 linenum += body.count('\n', begin, mstart) + 1
2720 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2720 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2721 begin = body.find('\n', mend) + 1 or len(body) + 1
2721 begin = body.find('\n', mend) + 1 or len(body) + 1
2722 lend = begin - 1
2722 lend = begin - 1
2723 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2723 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2724
2724
2725 class linestate(object):
2725 class linestate(object):
2726 def __init__(self, line, linenum, colstart, colend):
2726 def __init__(self, line, linenum, colstart, colend):
2727 self.line = line
2727 self.line = line
2728 self.linenum = linenum
2728 self.linenum = linenum
2729 self.colstart = colstart
2729 self.colstart = colstart
2730 self.colend = colend
2730 self.colend = colend
2731
2731
2732 def __hash__(self):
2732 def __hash__(self):
2733 return hash((self.linenum, self.line))
2733 return hash((self.linenum, self.line))
2734
2734
2735 def __eq__(self, other):
2735 def __eq__(self, other):
2736 return self.line == other.line
2736 return self.line == other.line
2737
2737
2738 matches = {}
2738 matches = {}
2739 copies = {}
2739 copies = {}
2740 def grepbody(fn, rev, body):
2740 def grepbody(fn, rev, body):
2741 matches[rev].setdefault(fn, [])
2741 matches[rev].setdefault(fn, [])
2742 m = matches[rev][fn]
2742 m = matches[rev][fn]
2743 for lnum, cstart, cend, line in matchlines(body):
2743 for lnum, cstart, cend, line in matchlines(body):
2744 s = linestate(line, lnum, cstart, cend)
2744 s = linestate(line, lnum, cstart, cend)
2745 m.append(s)
2745 m.append(s)
2746
2746
2747 def difflinestates(a, b):
2747 def difflinestates(a, b):
2748 sm = difflib.SequenceMatcher(None, a, b)
2748 sm = difflib.SequenceMatcher(None, a, b)
2749 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2749 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2750 if tag == 'insert':
2750 if tag == 'insert':
2751 for i in xrange(blo, bhi):
2751 for i in xrange(blo, bhi):
2752 yield ('+', b[i])
2752 yield ('+', b[i])
2753 elif tag == 'delete':
2753 elif tag == 'delete':
2754 for i in xrange(alo, ahi):
2754 for i in xrange(alo, ahi):
2755 yield ('-', a[i])
2755 yield ('-', a[i])
2756 elif tag == 'replace':
2756 elif tag == 'replace':
2757 for i in xrange(alo, ahi):
2757 for i in xrange(alo, ahi):
2758 yield ('-', a[i])
2758 yield ('-', a[i])
2759 for i in xrange(blo, bhi):
2759 for i in xrange(blo, bhi):
2760 yield ('+', b[i])
2760 yield ('+', b[i])
2761
2761
2762 def display(fn, ctx, pstates, states):
2762 def display(fn, ctx, pstates, states):
2763 rev = ctx.rev()
2763 rev = ctx.rev()
2764 datefunc = ui.quiet and util.shortdate or util.datestr
2764 datefunc = ui.quiet and util.shortdate or util.datestr
2765 found = False
2765 found = False
2766 filerevmatches = {}
2766 filerevmatches = {}
2767 def binary():
2767 def binary():
2768 flog = getfile(fn)
2768 flog = getfile(fn)
2769 return util.binary(flog.read(ctx.filenode(fn)))
2769 return util.binary(flog.read(ctx.filenode(fn)))
2770
2770
2771 if opts.get('all'):
2771 if opts.get('all'):
2772 iter = difflinestates(pstates, states)
2772 iter = difflinestates(pstates, states)
2773 else:
2773 else:
2774 iter = [('', l) for l in states]
2774 iter = [('', l) for l in states]
2775 for change, l in iter:
2775 for change, l in iter:
2776 cols = [fn, str(rev)]
2776 cols = [fn, str(rev)]
2777 before, match, after = None, None, None
2777 before, match, after = None, None, None
2778 if opts.get('line_number'):
2778 if opts.get('line_number'):
2779 cols.append(str(l.linenum))
2779 cols.append(str(l.linenum))
2780 if opts.get('all'):
2780 if opts.get('all'):
2781 cols.append(change)
2781 cols.append(change)
2782 if opts.get('user'):
2782 if opts.get('user'):
2783 cols.append(ui.shortuser(ctx.user()))
2783 cols.append(ui.shortuser(ctx.user()))
2784 if opts.get('date'):
2784 if opts.get('date'):
2785 cols.append(datefunc(ctx.date()))
2785 cols.append(datefunc(ctx.date()))
2786 if opts.get('files_with_matches'):
2786 if opts.get('files_with_matches'):
2787 c = (fn, rev)
2787 c = (fn, rev)
2788 if c in filerevmatches:
2788 if c in filerevmatches:
2789 continue
2789 continue
2790 filerevmatches[c] = 1
2790 filerevmatches[c] = 1
2791 else:
2791 else:
2792 before = l.line[:l.colstart]
2792 before = l.line[:l.colstart]
2793 match = l.line[l.colstart:l.colend]
2793 match = l.line[l.colstart:l.colend]
2794 after = l.line[l.colend:]
2794 after = l.line[l.colend:]
2795 ui.write(sep.join(cols))
2795 ui.write(sep.join(cols))
2796 if before is not None:
2796 if before is not None:
2797 if not opts.get('text') and binary():
2797 if not opts.get('text') and binary():
2798 ui.write(sep + " Binary file matches")
2798 ui.write(sep + " Binary file matches")
2799 else:
2799 else:
2800 ui.write(sep + before)
2800 ui.write(sep + before)
2801 ui.write(match, label='grep.match')
2801 ui.write(match, label='grep.match')
2802 ui.write(after)
2802 ui.write(after)
2803 ui.write(eol)
2803 ui.write(eol)
2804 found = True
2804 found = True
2805 return found
2805 return found
2806
2806
2807 skip = {}
2807 skip = {}
2808 revfiles = {}
2808 revfiles = {}
2809 matchfn = scmutil.match(repo[None], pats, opts)
2809 matchfn = scmutil.match(repo[None], pats, opts)
2810 found = False
2810 found = False
2811 follow = opts.get('follow')
2811 follow = opts.get('follow')
2812
2812
2813 def prep(ctx, fns):
2813 def prep(ctx, fns):
2814 rev = ctx.rev()
2814 rev = ctx.rev()
2815 pctx = ctx.p1()
2815 pctx = ctx.p1()
2816 parent = pctx.rev()
2816 parent = pctx.rev()
2817 matches.setdefault(rev, {})
2817 matches.setdefault(rev, {})
2818 matches.setdefault(parent, {})
2818 matches.setdefault(parent, {})
2819 files = revfiles.setdefault(rev, [])
2819 files = revfiles.setdefault(rev, [])
2820 for fn in fns:
2820 for fn in fns:
2821 flog = getfile(fn)
2821 flog = getfile(fn)
2822 try:
2822 try:
2823 fnode = ctx.filenode(fn)
2823 fnode = ctx.filenode(fn)
2824 except error.LookupError:
2824 except error.LookupError:
2825 continue
2825 continue
2826
2826
2827 copied = flog.renamed(fnode)
2827 copied = flog.renamed(fnode)
2828 copy = follow and copied and copied[0]
2828 copy = follow and copied and copied[0]
2829 if copy:
2829 if copy:
2830 copies.setdefault(rev, {})[fn] = copy
2830 copies.setdefault(rev, {})[fn] = copy
2831 if fn in skip:
2831 if fn in skip:
2832 if copy:
2832 if copy:
2833 skip[copy] = True
2833 skip[copy] = True
2834 continue
2834 continue
2835 files.append(fn)
2835 files.append(fn)
2836
2836
2837 if fn not in matches[rev]:
2837 if fn not in matches[rev]:
2838 grepbody(fn, rev, flog.read(fnode))
2838 grepbody(fn, rev, flog.read(fnode))
2839
2839
2840 pfn = copy or fn
2840 pfn = copy or fn
2841 if pfn not in matches[parent]:
2841 if pfn not in matches[parent]:
2842 try:
2842 try:
2843 fnode = pctx.filenode(pfn)
2843 fnode = pctx.filenode(pfn)
2844 grepbody(pfn, parent, flog.read(fnode))
2844 grepbody(pfn, parent, flog.read(fnode))
2845 except error.LookupError:
2845 except error.LookupError:
2846 pass
2846 pass
2847
2847
2848 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2848 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2849 rev = ctx.rev()
2849 rev = ctx.rev()
2850 parent = ctx.p1().rev()
2850 parent = ctx.p1().rev()
2851 for fn in sorted(revfiles.get(rev, [])):
2851 for fn in sorted(revfiles.get(rev, [])):
2852 states = matches[rev][fn]
2852 states = matches[rev][fn]
2853 copy = copies.get(rev, {}).get(fn)
2853 copy = copies.get(rev, {}).get(fn)
2854 if fn in skip:
2854 if fn in skip:
2855 if copy:
2855 if copy:
2856 skip[copy] = True
2856 skip[copy] = True
2857 continue
2857 continue
2858 pstates = matches.get(parent, {}).get(copy or fn, [])
2858 pstates = matches.get(parent, {}).get(copy or fn, [])
2859 if pstates or states:
2859 if pstates or states:
2860 r = display(fn, ctx, pstates, states)
2860 r = display(fn, ctx, pstates, states)
2861 found = found or r
2861 found = found or r
2862 if r and not opts.get('all'):
2862 if r and not opts.get('all'):
2863 skip[fn] = True
2863 skip[fn] = True
2864 if copy:
2864 if copy:
2865 skip[copy] = True
2865 skip[copy] = True
2866 del matches[rev]
2866 del matches[rev]
2867 del revfiles[rev]
2867 del revfiles[rev]
2868
2868
2869 return not found
2869 return not found
2870
2870
2871 @command('heads',
2871 @command('heads',
2872 [('r', 'rev', '',
2872 [('r', 'rev', '',
2873 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2873 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2874 ('t', 'topo', False, _('show topological heads only')),
2874 ('t', 'topo', False, _('show topological heads only')),
2875 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2875 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2876 ('c', 'closed', False, _('show normal and closed branch heads')),
2876 ('c', 'closed', False, _('show normal and closed branch heads')),
2877 ] + templateopts,
2877 ] + templateopts,
2878 _('[-ac] [-r STARTREV] [REV]...'))
2878 _('[-ac] [-r STARTREV] [REV]...'))
2879 def heads(ui, repo, *branchrevs, **opts):
2879 def heads(ui, repo, *branchrevs, **opts):
2880 """show current repository heads or show branch heads
2880 """show current repository heads or show branch heads
2881
2881
2882 With no arguments, show all repository branch heads.
2882 With no arguments, show all repository branch heads.
2883
2883
2884 Repository "heads" are changesets with no child changesets. They are
2884 Repository "heads" are changesets with no child changesets. They are
2885 where development generally takes place and are the usual targets
2885 where development generally takes place and are the usual targets
2886 for update and merge operations. Branch heads are changesets that have
2886 for update and merge operations. Branch heads are changesets that have
2887 no child changeset on the same branch.
2887 no child changeset on the same branch.
2888
2888
2889 If one or more REVs are given, only branch heads on the branches
2889 If one or more REVs are given, only branch heads on the branches
2890 associated with the specified changesets are shown. This means
2890 associated with the specified changesets are shown. This means
2891 that you can use :hg:`heads foo` to see the heads on a branch
2891 that you can use :hg:`heads foo` to see the heads on a branch
2892 named ``foo``.
2892 named ``foo``.
2893
2893
2894 If -c/--closed is specified, also show branch heads marked closed
2894 If -c/--closed is specified, also show branch heads marked closed
2895 (see :hg:`commit --close-branch`).
2895 (see :hg:`commit --close-branch`).
2896
2896
2897 If STARTREV is specified, only those heads that are descendants of
2897 If STARTREV is specified, only those heads that are descendants of
2898 STARTREV will be displayed.
2898 STARTREV will be displayed.
2899
2899
2900 If -t/--topo is specified, named branch mechanics will be ignored and only
2900 If -t/--topo is specified, named branch mechanics will be ignored and only
2901 changesets without children will be shown.
2901 changesets without children will be shown.
2902
2902
2903 Returns 0 if matching heads are found, 1 if not.
2903 Returns 0 if matching heads are found, 1 if not.
2904 """
2904 """
2905
2905
2906 start = None
2906 start = None
2907 if 'rev' in opts:
2907 if 'rev' in opts:
2908 start = scmutil.revsingle(repo, opts['rev'], None).node()
2908 start = scmutil.revsingle(repo, opts['rev'], None).node()
2909
2909
2910 if opts.get('topo'):
2910 if opts.get('topo'):
2911 heads = [repo[h] for h in repo.heads(start)]
2911 heads = [repo[h] for h in repo.heads(start)]
2912 else:
2912 else:
2913 heads = []
2913 heads = []
2914 for branch in repo.branchmap():
2914 for branch in repo.branchmap():
2915 heads += repo.branchheads(branch, start, opts.get('closed'))
2915 heads += repo.branchheads(branch, start, opts.get('closed'))
2916 heads = [repo[h] for h in heads]
2916 heads = [repo[h] for h in heads]
2917
2917
2918 if branchrevs:
2918 if branchrevs:
2919 branches = set(repo[br].branch() for br in branchrevs)
2919 branches = set(repo[br].branch() for br in branchrevs)
2920 heads = [h for h in heads if h.branch() in branches]
2920 heads = [h for h in heads if h.branch() in branches]
2921
2921
2922 if opts.get('active') and branchrevs:
2922 if opts.get('active') and branchrevs:
2923 dagheads = repo.heads(start)
2923 dagheads = repo.heads(start)
2924 heads = [h for h in heads if h.node() in dagheads]
2924 heads = [h for h in heads if h.node() in dagheads]
2925
2925
2926 if branchrevs:
2926 if branchrevs:
2927 haveheads = set(h.branch() for h in heads)
2927 haveheads = set(h.branch() for h in heads)
2928 if branches - haveheads:
2928 if branches - haveheads:
2929 headless = ', '.join(b for b in branches - haveheads)
2929 headless = ', '.join(b for b in branches - haveheads)
2930 msg = _('no open branch heads found on branches %s')
2930 msg = _('no open branch heads found on branches %s')
2931 if opts.get('rev'):
2931 if opts.get('rev'):
2932 msg += _(' (started at %s)' % opts['rev'])
2932 msg += _(' (started at %s)' % opts['rev'])
2933 ui.warn((msg + '\n') % headless)
2933 ui.warn((msg + '\n') % headless)
2934
2934
2935 if not heads:
2935 if not heads:
2936 return 1
2936 return 1
2937
2937
2938 heads = sorted(heads, key=lambda x: -x.rev())
2938 heads = sorted(heads, key=lambda x: -x.rev())
2939 displayer = cmdutil.show_changeset(ui, repo, opts)
2939 displayer = cmdutil.show_changeset(ui, repo, opts)
2940 for ctx in heads:
2940 for ctx in heads:
2941 displayer.show(ctx)
2941 displayer.show(ctx)
2942 displayer.close()
2942 displayer.close()
2943
2943
2944 @command('help',
2944 @command('help',
2945 [('e', 'extension', None, _('show only help for extensions')),
2945 [('e', 'extension', None, _('show only help for extensions')),
2946 ('c', 'command', None, _('show only help for commands'))],
2946 ('c', 'command', None, _('show only help for commands'))],
2947 _('[-ec] [TOPIC]'))
2947 _('[-ec] [TOPIC]'))
2948 def help_(ui, name=None, unknowncmd=False, full=True, **opts):
2948 def help_(ui, name=None, unknowncmd=False, full=True, **opts):
2949 """show help for a given topic or a help overview
2949 """show help for a given topic or a help overview
2950
2950
2951 With no arguments, print a list of commands with short help messages.
2951 With no arguments, print a list of commands with short help messages.
2952
2952
2953 Given a topic, extension, or command name, print help for that
2953 Given a topic, extension, or command name, print help for that
2954 topic.
2954 topic.
2955
2955
2956 Returns 0 if successful.
2956 Returns 0 if successful.
2957 """
2957 """
2958
2958
2959 textwidth = min(ui.termwidth(), 80) - 2
2959 textwidth = min(ui.termwidth(), 80) - 2
2960
2960
2961 def optrst(options):
2961 def optrst(options):
2962 data = []
2962 data = []
2963 multioccur = False
2963 multioccur = False
2964 for option in options:
2964 for option in options:
2965 if len(option) == 5:
2965 if len(option) == 5:
2966 shortopt, longopt, default, desc, optlabel = option
2966 shortopt, longopt, default, desc, optlabel = option
2967 else:
2967 else:
2968 shortopt, longopt, default, desc = option
2968 shortopt, longopt, default, desc = option
2969 optlabel = _("VALUE") # default label
2969 optlabel = _("VALUE") # default label
2970
2970
2971 if _("DEPRECATED") in desc and not ui.verbose:
2971 if _("DEPRECATED") in desc and not ui.verbose:
2972 continue
2972 continue
2973
2973
2974 so = ''
2974 so = ''
2975 if shortopt:
2975 if shortopt:
2976 so = '-' + shortopt
2976 so = '-' + shortopt
2977 lo = '--' + longopt
2977 lo = '--' + longopt
2978 if default:
2978 if default:
2979 desc += _(" (default: %s)") % default
2979 desc += _(" (default: %s)") % default
2980
2980
2981 if isinstance(default, list):
2981 if isinstance(default, list):
2982 lo += " %s [+]" % optlabel
2982 lo += " %s [+]" % optlabel
2983 multioccur = True
2983 multioccur = True
2984 elif (default is not None) and not isinstance(default, bool):
2984 elif (default is not None) and not isinstance(default, bool):
2985 lo += " %s" % optlabel
2985 lo += " %s" % optlabel
2986
2986
2987 data.append((so, lo, desc))
2987 data.append((so, lo, desc))
2988
2988
2989 rst = minirst.maketable(data, 1)
2989 rst = minirst.maketable(data, 1)
2990
2990
2991 if multioccur:
2991 if multioccur:
2992 rst += _("\n[+] marked option can be specified multiple times\n")
2992 rst += _("\n[+] marked option can be specified multiple times\n")
2993
2993
2994 return rst
2994 return rst
2995
2995
2996 # list all option lists
2996 # list all option lists
2997 def opttext(optlist, width):
2997 def opttext(optlist, width):
2998 rst = ''
2998 rst = ''
2999 if not optlist:
2999 if not optlist:
3000 return ''
3000 return ''
3001
3001
3002 for title, options in optlist:
3002 for title, options in optlist:
3003 rst += '\n%s\n' % title
3003 rst += '\n%s\n' % title
3004 if options:
3004 if options:
3005 rst += "\n"
3005 rst += "\n"
3006 rst += optrst(options)
3006 rst += optrst(options)
3007 rst += '\n'
3007 rst += '\n'
3008
3008
3009 return '\n' + minirst.format(rst, width)
3009 return '\n' + minirst.format(rst, width)
3010
3010
3011 def addglobalopts(optlist, aliases):
3011 def addglobalopts(optlist, aliases):
3012 if ui.quiet:
3012 if ui.quiet:
3013 return []
3013 return []
3014
3014
3015 if ui.verbose:
3015 if ui.verbose:
3016 optlist.append((_("global options:"), globalopts))
3016 optlist.append((_("global options:"), globalopts))
3017 if name == 'shortlist':
3017 if name == 'shortlist':
3018 optlist.append((_('use "hg help" for the full list '
3018 optlist.append((_('use "hg help" for the full list '
3019 'of commands'), ()))
3019 'of commands'), ()))
3020 else:
3020 else:
3021 if name == 'shortlist':
3021 if name == 'shortlist':
3022 msg = _('use "hg help" for the full list of commands '
3022 msg = _('use "hg help" for the full list of commands '
3023 'or "hg -v" for details')
3023 'or "hg -v" for details')
3024 elif name and not full:
3024 elif name and not full:
3025 msg = _('use "hg help %s" to show the full help text' % name)
3025 msg = _('use "hg help %s" to show the full help text' % name)
3026 elif aliases:
3026 elif aliases:
3027 msg = _('use "hg -v help%s" to show builtin aliases and '
3027 msg = _('use "hg -v help%s" to show builtin aliases and '
3028 'global options') % (name and " " + name or "")
3028 'global options') % (name and " " + name or "")
3029 else:
3029 else:
3030 msg = _('use "hg -v help %s" to show more info') % name
3030 msg = _('use "hg -v help %s" to show more info') % name
3031 optlist.append((msg, ()))
3031 optlist.append((msg, ()))
3032
3032
3033 def helpcmd(name):
3033 def helpcmd(name):
3034 try:
3034 try:
3035 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
3035 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
3036 except error.AmbiguousCommand, inst:
3036 except error.AmbiguousCommand, inst:
3037 # py3k fix: except vars can't be used outside the scope of the
3037 # py3k fix: except vars can't be used outside the scope of the
3038 # except block, nor can be used inside a lambda. python issue4617
3038 # except block, nor can be used inside a lambda. python issue4617
3039 prefix = inst.args[0]
3039 prefix = inst.args[0]
3040 select = lambda c: c.lstrip('^').startswith(prefix)
3040 select = lambda c: c.lstrip('^').startswith(prefix)
3041 helplist(select)
3041 helplist(select)
3042 return
3042 return
3043
3043
3044 # check if it's an invalid alias and display its error if it is
3044 # check if it's an invalid alias and display its error if it is
3045 if getattr(entry[0], 'badalias', False):
3045 if getattr(entry[0], 'badalias', False):
3046 if not unknowncmd:
3046 if not unknowncmd:
3047 entry[0](ui)
3047 entry[0](ui)
3048 return
3048 return
3049
3049
3050 rst = ""
3050 rst = ""
3051
3051
3052 # synopsis
3052 # synopsis
3053 if len(entry) > 2:
3053 if len(entry) > 2:
3054 if entry[2].startswith('hg'):
3054 if entry[2].startswith('hg'):
3055 rst += "%s\n" % entry[2]
3055 rst += "%s\n" % entry[2]
3056 else:
3056 else:
3057 rst += 'hg %s %s\n' % (aliases[0], entry[2])
3057 rst += 'hg %s %s\n' % (aliases[0], entry[2])
3058 else:
3058 else:
3059 rst += 'hg %s\n' % aliases[0]
3059 rst += 'hg %s\n' % aliases[0]
3060
3060
3061 # aliases
3061 # aliases
3062 if full and not ui.quiet and len(aliases) > 1:
3062 if full and not ui.quiet and len(aliases) > 1:
3063 rst += _("\naliases: %s\n") % ', '.join(aliases[1:])
3063 rst += _("\naliases: %s\n") % ', '.join(aliases[1:])
3064
3064
3065 # description
3065 # description
3066 doc = gettext(entry[0].__doc__)
3066 doc = gettext(entry[0].__doc__)
3067 if not doc:
3067 if not doc:
3068 doc = _("(no help text available)")
3068 doc = _("(no help text available)")
3069 if util.safehasattr(entry[0], 'definition'): # aliased command
3069 if util.safehasattr(entry[0], 'definition'): # aliased command
3070 if entry[0].definition.startswith('!'): # shell alias
3070 if entry[0].definition.startswith('!'): # shell alias
3071 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
3071 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
3072 else:
3072 else:
3073 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
3073 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
3074 if ui.quiet or not full:
3074 if ui.quiet or not full:
3075 doc = doc.splitlines()[0]
3075 doc = doc.splitlines()[0]
3076 rst += "\n" + doc + "\n"
3076 rst += "\n" + doc + "\n"
3077
3077
3078 # check if this command shadows a non-trivial (multi-line)
3078 # check if this command shadows a non-trivial (multi-line)
3079 # extension help text
3079 # extension help text
3080 try:
3080 try:
3081 mod = extensions.find(name)
3081 mod = extensions.find(name)
3082 doc = gettext(mod.__doc__) or ''
3082 doc = gettext(mod.__doc__) or ''
3083 if '\n' in doc.strip():
3083 if '\n' in doc.strip():
3084 msg = _('use "hg help -e %s" to show help for '
3084 msg = _('use "hg help -e %s" to show help for '
3085 'the %s extension') % (name, name)
3085 'the %s extension') % (name, name)
3086 rst += '\n%s\n' % msg
3086 rst += '\n%s\n' % msg
3087 except KeyError:
3087 except KeyError:
3088 pass
3088 pass
3089
3089
3090 # options
3090 # options
3091 if not ui.quiet and entry[1]:
3091 if not ui.quiet and entry[1]:
3092 rst += '\noptions:\n\n'
3092 rst += '\noptions:\n\n'
3093 rst += optrst(entry[1])
3093 rst += optrst(entry[1])
3094
3094
3095 if ui.verbose:
3095 if ui.verbose:
3096 rst += '\nglobal options:\n\n'
3096 rst += '\nglobal options:\n\n'
3097 rst += optrst(globalopts)
3097 rst += optrst(globalopts)
3098
3098
3099 keep = ui.verbose and ['verbose'] or []
3099 keep = ui.verbose and ['verbose'] or []
3100 formatted, pruned = minirst.format(rst, textwidth, keep=keep)
3100 formatted, pruned = minirst.format(rst, textwidth, keep=keep)
3101 ui.write(formatted)
3101 ui.write(formatted)
3102
3102
3103 if not ui.verbose:
3103 if not ui.verbose:
3104 if not full:
3104 if not full:
3105 ui.write(_('\nuse "hg help %s" to show the full help text\n')
3105 ui.write(_('\nuse "hg help %s" to show the full help text\n')
3106 % name)
3106 % name)
3107 elif not ui.quiet:
3107 elif not ui.quiet:
3108 ui.write(_('\nuse "hg -v help %s" to show more info\n') % name)
3108 ui.write(_('\nuse "hg -v help %s" to show more info\n') % name)
3109
3109
3110
3110
3111 def helplist(select=None):
3111 def helplist(select=None):
3112 # list of commands
3112 # list of commands
3113 if name == "shortlist":
3113 if name == "shortlist":
3114 header = _('basic commands:\n\n')
3114 header = _('basic commands:\n\n')
3115 else:
3115 else:
3116 header = _('list of commands:\n\n')
3116 header = _('list of commands:\n\n')
3117
3117
3118 h = {}
3118 h = {}
3119 cmds = {}
3119 cmds = {}
3120 for c, e in table.iteritems():
3120 for c, e in table.iteritems():
3121 f = c.split("|", 1)[0]
3121 f = c.split("|", 1)[0]
3122 if select and not select(f):
3122 if select and not select(f):
3123 continue
3123 continue
3124 if (not select and name != 'shortlist' and
3124 if (not select and name != 'shortlist' and
3125 e[0].__module__ != __name__):
3125 e[0].__module__ != __name__):
3126 continue
3126 continue
3127 if name == "shortlist" and not f.startswith("^"):
3127 if name == "shortlist" and not f.startswith("^"):
3128 continue
3128 continue
3129 f = f.lstrip("^")
3129 f = f.lstrip("^")
3130 if not ui.debugflag and f.startswith("debug"):
3130 if not ui.debugflag and f.startswith("debug"):
3131 continue
3131 continue
3132 doc = e[0].__doc__
3132 doc = e[0].__doc__
3133 if doc and 'DEPRECATED' in doc and not ui.verbose:
3133 if doc and 'DEPRECATED' in doc and not ui.verbose:
3134 continue
3134 continue
3135 doc = gettext(doc)
3135 doc = gettext(doc)
3136 if not doc:
3136 if not doc:
3137 doc = _("(no help text available)")
3137 doc = _("(no help text available)")
3138 h[f] = doc.splitlines()[0].rstrip()
3138 h[f] = doc.splitlines()[0].rstrip()
3139 cmds[f] = c.lstrip("^")
3139 cmds[f] = c.lstrip("^")
3140
3140
3141 if not h:
3141 if not h:
3142 ui.status(_('no commands defined\n'))
3142 ui.status(_('no commands defined\n'))
3143 return
3143 return
3144
3144
3145 ui.status(header)
3145 ui.status(header)
3146 fns = sorted(h)
3146 fns = sorted(h)
3147 m = max(map(len, fns))
3147 m = max(map(len, fns))
3148 for f in fns:
3148 for f in fns:
3149 if ui.verbose:
3149 if ui.verbose:
3150 commands = cmds[f].replace("|",", ")
3150 commands = cmds[f].replace("|",", ")
3151 ui.write(" %s:\n %s\n"%(commands, h[f]))
3151 ui.write(" %s:\n %s\n"%(commands, h[f]))
3152 else:
3152 else:
3153 ui.write('%s\n' % (util.wrap(h[f], textwidth,
3153 ui.write('%s\n' % (util.wrap(h[f], textwidth,
3154 initindent=' %-*s ' % (m, f),
3154 initindent=' %-*s ' % (m, f),
3155 hangindent=' ' * (m + 4))))
3155 hangindent=' ' * (m + 4))))
3156
3156
3157 if not name:
3157 if not name:
3158 text = help.listexts(_('enabled extensions:'), extensions.enabled())
3158 text = help.listexts(_('enabled extensions:'), extensions.enabled())
3159 if text:
3159 if text:
3160 ui.write("\n%s" % minirst.format(text, textwidth))
3160 ui.write("\n%s" % minirst.format(text, textwidth))
3161
3161
3162 ui.write(_("\nadditional help topics:\n\n"))
3162 ui.write(_("\nadditional help topics:\n\n"))
3163 topics = []
3163 topics = []
3164 for names, header, doc in help.helptable:
3164 for names, header, doc in help.helptable:
3165 topics.append((sorted(names, key=len, reverse=True)[0], header))
3165 topics.append((sorted(names, key=len, reverse=True)[0], header))
3166 topics_len = max([len(s[0]) for s in topics])
3166 topics_len = max([len(s[0]) for s in topics])
3167 for t, desc in topics:
3167 for t, desc in topics:
3168 ui.write(" %-*s %s\n" % (topics_len, t, desc))
3168 ui.write(" %-*s %s\n" % (topics_len, t, desc))
3169
3169
3170 optlist = []
3170 optlist = []
3171 addglobalopts(optlist, True)
3171 addglobalopts(optlist, True)
3172 ui.write(opttext(optlist, textwidth))
3172 ui.write(opttext(optlist, textwidth))
3173
3173
3174 def helptopic(name):
3174 def helptopic(name):
3175 for names, header, doc in help.helptable:
3175 for names, header, doc in help.helptable:
3176 if name in names:
3176 if name in names:
3177 break
3177 break
3178 else:
3178 else:
3179 raise error.UnknownCommand(name)
3179 raise error.UnknownCommand(name)
3180
3180
3181 # description
3181 # description
3182 if not doc:
3182 if not doc:
3183 doc = _("(no help text available)")
3183 doc = _("(no help text available)")
3184 if util.safehasattr(doc, '__call__'):
3184 if util.safehasattr(doc, '__call__'):
3185 doc = doc()
3185 doc = doc()
3186
3186
3187 ui.write("%s\n\n" % header)
3187 ui.write("%s\n\n" % header)
3188 ui.write("%s" % minirst.format(doc, textwidth, indent=4))
3188 ui.write("%s" % minirst.format(doc, textwidth, indent=4))
3189 try:
3189 try:
3190 cmdutil.findcmd(name, table)
3190 cmdutil.findcmd(name, table)
3191 ui.write(_('\nuse "hg help -c %s" to see help for '
3191 ui.write(_('\nuse "hg help -c %s" to see help for '
3192 'the %s command\n') % (name, name))
3192 'the %s command\n') % (name, name))
3193 except error.UnknownCommand:
3193 except error.UnknownCommand:
3194 pass
3194 pass
3195
3195
3196 def helpext(name):
3196 def helpext(name):
3197 try:
3197 try:
3198 mod = extensions.find(name)
3198 mod = extensions.find(name)
3199 doc = gettext(mod.__doc__) or _('no help text available')
3199 doc = gettext(mod.__doc__) or _('no help text available')
3200 except KeyError:
3200 except KeyError:
3201 mod = None
3201 mod = None
3202 doc = extensions.disabledext(name)
3202 doc = extensions.disabledext(name)
3203 if not doc:
3203 if not doc:
3204 raise error.UnknownCommand(name)
3204 raise error.UnknownCommand(name)
3205
3205
3206 if '\n' not in doc:
3206 if '\n' not in doc:
3207 head, tail = doc, ""
3207 head, tail = doc, ""
3208 else:
3208 else:
3209 head, tail = doc.split('\n', 1)
3209 head, tail = doc.split('\n', 1)
3210 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
3210 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
3211 if tail:
3211 if tail:
3212 ui.write(minirst.format(tail, textwidth))
3212 ui.write(minirst.format(tail, textwidth))
3213 ui.status('\n')
3213 ui.status('\n')
3214
3214
3215 if mod:
3215 if mod:
3216 try:
3216 try:
3217 ct = mod.cmdtable
3217 ct = mod.cmdtable
3218 except AttributeError:
3218 except AttributeError:
3219 ct = {}
3219 ct = {}
3220 modcmds = set([c.split('|', 1)[0] for c in ct])
3220 modcmds = set([c.split('|', 1)[0] for c in ct])
3221 helplist(modcmds.__contains__)
3221 helplist(modcmds.__contains__)
3222 else:
3222 else:
3223 ui.write(_('use "hg help extensions" for information on enabling '
3223 ui.write(_('use "hg help extensions" for information on enabling '
3224 'extensions\n'))
3224 'extensions\n'))
3225
3225
3226 def helpextcmd(name):
3226 def helpextcmd(name):
3227 cmd, ext, mod = extensions.disabledcmd(ui, name, ui.config('ui', 'strict'))
3227 cmd, ext, mod = extensions.disabledcmd(ui, name, ui.config('ui', 'strict'))
3228 doc = gettext(mod.__doc__).splitlines()[0]
3228 doc = gettext(mod.__doc__).splitlines()[0]
3229
3229
3230 msg = help.listexts(_("'%s' is provided by the following "
3230 msg = help.listexts(_("'%s' is provided by the following "
3231 "extension:") % cmd, {ext: doc}, indent=4)
3231 "extension:") % cmd, {ext: doc}, indent=4)
3232 ui.write(minirst.format(msg, textwidth))
3232 ui.write(minirst.format(msg, textwidth))
3233 ui.write('\n')
3233 ui.write('\n')
3234 ui.write(_('use "hg help extensions" for information on enabling '
3234 ui.write(_('use "hg help extensions" for information on enabling '
3235 'extensions\n'))
3235 'extensions\n'))
3236
3236
3237 if name and name != 'shortlist':
3237 if name and name != 'shortlist':
3238 i = None
3238 i = None
3239 if unknowncmd:
3239 if unknowncmd:
3240 queries = (helpextcmd,)
3240 queries = (helpextcmd,)
3241 elif opts.get('extension'):
3241 elif opts.get('extension'):
3242 queries = (helpext,)
3242 queries = (helpext,)
3243 elif opts.get('command'):
3243 elif opts.get('command'):
3244 queries = (helpcmd,)
3244 queries = (helpcmd,)
3245 else:
3245 else:
3246 queries = (helptopic, helpcmd, helpext, helpextcmd)
3246 queries = (helptopic, helpcmd, helpext, helpextcmd)
3247 for f in queries:
3247 for f in queries:
3248 try:
3248 try:
3249 f(name)
3249 f(name)
3250 i = None
3250 i = None
3251 break
3251 break
3252 except error.UnknownCommand, inst:
3252 except error.UnknownCommand, inst:
3253 i = inst
3253 i = inst
3254 if i:
3254 if i:
3255 raise i
3255 raise i
3256 else:
3256 else:
3257 # program name
3257 # program name
3258 ui.status(_("Mercurial Distributed SCM\n"))
3258 ui.status(_("Mercurial Distributed SCM\n"))
3259 ui.status('\n')
3259 ui.status('\n')
3260 helplist()
3260 helplist()
3261
3261
3262
3262
3263 @command('identify|id',
3263 @command('identify|id',
3264 [('r', 'rev', '',
3264 [('r', 'rev', '',
3265 _('identify the specified revision'), _('REV')),
3265 _('identify the specified revision'), _('REV')),
3266 ('n', 'num', None, _('show local revision number')),
3266 ('n', 'num', None, _('show local revision number')),
3267 ('i', 'id', None, _('show global revision id')),
3267 ('i', 'id', None, _('show global revision id')),
3268 ('b', 'branch', None, _('show branch')),
3268 ('b', 'branch', None, _('show branch')),
3269 ('t', 'tags', None, _('show tags')),
3269 ('t', 'tags', None, _('show tags')),
3270 ('B', 'bookmarks', None, _('show bookmarks')),
3270 ('B', 'bookmarks', None, _('show bookmarks')),
3271 ] + remoteopts,
3271 ] + remoteopts,
3272 _('[-nibtB] [-r REV] [SOURCE]'))
3272 _('[-nibtB] [-r REV] [SOURCE]'))
3273 def identify(ui, repo, source=None, rev=None,
3273 def identify(ui, repo, source=None, rev=None,
3274 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3274 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3275 """identify the working copy or specified revision
3275 """identify the working copy or specified revision
3276
3276
3277 Print a summary identifying the repository state at REV using one or
3277 Print a summary identifying the repository state at REV using one or
3278 two parent hash identifiers, followed by a "+" if the working
3278 two parent hash identifiers, followed by a "+" if the working
3279 directory has uncommitted changes, the branch name (if not default),
3279 directory has uncommitted changes, the branch name (if not default),
3280 a list of tags, and a list of bookmarks.
3280 a list of tags, and a list of bookmarks.
3281
3281
3282 When REV is not given, print a summary of the current state of the
3282 When REV is not given, print a summary of the current state of the
3283 repository.
3283 repository.
3284
3284
3285 Specifying a path to a repository root or Mercurial bundle will
3285 Specifying a path to a repository root or Mercurial bundle will
3286 cause lookup to operate on that repository/bundle.
3286 cause lookup to operate on that repository/bundle.
3287
3287
3288 .. container:: verbose
3288 .. container:: verbose
3289
3289
3290 Examples:
3290 Examples:
3291
3291
3292 - generate a build identifier for the working directory::
3292 - generate a build identifier for the working directory::
3293
3293
3294 hg id --id > build-id.dat
3294 hg id --id > build-id.dat
3295
3295
3296 - find the revision corresponding to a tag::
3296 - find the revision corresponding to a tag::
3297
3297
3298 hg id -n -r 1.3
3298 hg id -n -r 1.3
3299
3299
3300 - check the most recent revision of a remote repository::
3300 - check the most recent revision of a remote repository::
3301
3301
3302 hg id -r tip http://selenic.com/hg/
3302 hg id -r tip http://selenic.com/hg/
3303
3303
3304 Returns 0 if successful.
3304 Returns 0 if successful.
3305 """
3305 """
3306
3306
3307 if not repo and not source:
3307 if not repo and not source:
3308 raise util.Abort(_("there is no Mercurial repository here "
3308 raise util.Abort(_("there is no Mercurial repository here "
3309 "(.hg not found)"))
3309 "(.hg not found)"))
3310
3310
3311 hexfunc = ui.debugflag and hex or short
3311 hexfunc = ui.debugflag and hex or short
3312 default = not (num or id or branch or tags or bookmarks)
3312 default = not (num or id or branch or tags or bookmarks)
3313 output = []
3313 output = []
3314 revs = []
3314 revs = []
3315
3315
3316 if source:
3316 if source:
3317 source, branches = hg.parseurl(ui.expandpath(source))
3317 source, branches = hg.parseurl(ui.expandpath(source))
3318 repo = hg.peer(ui, opts, source)
3318 repo = hg.peer(ui, opts, source)
3319 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
3319 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
3320
3320
3321 if not repo.local():
3321 if not repo.local():
3322 if num or branch or tags:
3322 if num or branch or tags:
3323 raise util.Abort(
3323 raise util.Abort(
3324 _("can't query remote revision number, branch, or tags"))
3324 _("can't query remote revision number, branch, or tags"))
3325 if not rev and revs:
3325 if not rev and revs:
3326 rev = revs[0]
3326 rev = revs[0]
3327 if not rev:
3327 if not rev:
3328 rev = "tip"
3328 rev = "tip"
3329
3329
3330 remoterev = repo.lookup(rev)
3330 remoterev = repo.lookup(rev)
3331 if default or id:
3331 if default or id:
3332 output = [hexfunc(remoterev)]
3332 output = [hexfunc(remoterev)]
3333
3333
3334 def getbms():
3334 def getbms():
3335 bms = []
3335 bms = []
3336
3336
3337 if 'bookmarks' in repo.listkeys('namespaces'):
3337 if 'bookmarks' in repo.listkeys('namespaces'):
3338 hexremoterev = hex(remoterev)
3338 hexremoterev = hex(remoterev)
3339 bms = [bm for bm, bmr in repo.listkeys('bookmarks').iteritems()
3339 bms = [bm for bm, bmr in repo.listkeys('bookmarks').iteritems()
3340 if bmr == hexremoterev]
3340 if bmr == hexremoterev]
3341
3341
3342 return bms
3342 return bms
3343
3343
3344 if bookmarks:
3344 if bookmarks:
3345 output.extend(getbms())
3345 output.extend(getbms())
3346 elif default and not ui.quiet:
3346 elif default and not ui.quiet:
3347 # multiple bookmarks for a single parent separated by '/'
3347 # multiple bookmarks for a single parent separated by '/'
3348 bm = '/'.join(getbms())
3348 bm = '/'.join(getbms())
3349 if bm:
3349 if bm:
3350 output.append(bm)
3350 output.append(bm)
3351 else:
3351 else:
3352 if not rev:
3352 if not rev:
3353 ctx = repo[None]
3353 ctx = repo[None]
3354 parents = ctx.parents()
3354 parents = ctx.parents()
3355 changed = ""
3355 changed = ""
3356 if default or id or num:
3356 if default or id or num:
3357 changed = util.any(repo.status()) and "+" or ""
3357 changed = util.any(repo.status()) and "+" or ""
3358 if default or id:
3358 if default or id:
3359 output = ["%s%s" %
3359 output = ["%s%s" %
3360 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3360 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3361 if num:
3361 if num:
3362 output.append("%s%s" %
3362 output.append("%s%s" %
3363 ('+'.join([str(p.rev()) for p in parents]), changed))
3363 ('+'.join([str(p.rev()) for p in parents]), changed))
3364 else:
3364 else:
3365 ctx = scmutil.revsingle(repo, rev)
3365 ctx = scmutil.revsingle(repo, rev)
3366 if default or id:
3366 if default or id:
3367 output = [hexfunc(ctx.node())]
3367 output = [hexfunc(ctx.node())]
3368 if num:
3368 if num:
3369 output.append(str(ctx.rev()))
3369 output.append(str(ctx.rev()))
3370
3370
3371 if default and not ui.quiet:
3371 if default and not ui.quiet:
3372 b = ctx.branch()
3372 b = ctx.branch()
3373 if b != 'default':
3373 if b != 'default':
3374 output.append("(%s)" % b)
3374 output.append("(%s)" % b)
3375
3375
3376 # multiple tags for a single parent separated by '/'
3376 # multiple tags for a single parent separated by '/'
3377 t = '/'.join(ctx.tags())
3377 t = '/'.join(ctx.tags())
3378 if t:
3378 if t:
3379 output.append(t)
3379 output.append(t)
3380
3380
3381 # multiple bookmarks for a single parent separated by '/'
3381 # multiple bookmarks for a single parent separated by '/'
3382 bm = '/'.join(ctx.bookmarks())
3382 bm = '/'.join(ctx.bookmarks())
3383 if bm:
3383 if bm:
3384 output.append(bm)
3384 output.append(bm)
3385 else:
3385 else:
3386 if branch:
3386 if branch:
3387 output.append(ctx.branch())
3387 output.append(ctx.branch())
3388
3388
3389 if tags:
3389 if tags:
3390 output.extend(ctx.tags())
3390 output.extend(ctx.tags())
3391
3391
3392 if bookmarks:
3392 if bookmarks:
3393 output.extend(ctx.bookmarks())
3393 output.extend(ctx.bookmarks())
3394
3394
3395 ui.write("%s\n" % ' '.join(output))
3395 ui.write("%s\n" % ' '.join(output))
3396
3396
3397 @command('import|patch',
3397 @command('import|patch',
3398 [('p', 'strip', 1,
3398 [('p', 'strip', 1,
3399 _('directory strip option for patch. This has the same '
3399 _('directory strip option for patch. This has the same '
3400 'meaning as the corresponding patch option'), _('NUM')),
3400 'meaning as the corresponding patch option'), _('NUM')),
3401 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3401 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3402 ('e', 'edit', False, _('invoke editor on commit messages')),
3402 ('e', 'edit', False, _('invoke editor on commit messages')),
3403 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3403 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3404 ('', 'no-commit', None,
3404 ('', 'no-commit', None,
3405 _("don't commit, just update the working directory")),
3405 _("don't commit, just update the working directory")),
3406 ('', 'bypass', None,
3406 ('', 'bypass', None,
3407 _("apply patch without touching the working directory")),
3407 _("apply patch without touching the working directory")),
3408 ('', 'exact', None,
3408 ('', 'exact', None,
3409 _('apply patch to the nodes from which it was generated')),
3409 _('apply patch to the nodes from which it was generated')),
3410 ('', 'import-branch', None,
3410 ('', 'import-branch', None,
3411 _('use any branch information in patch (implied by --exact)'))] +
3411 _('use any branch information in patch (implied by --exact)'))] +
3412 commitopts + commitopts2 + similarityopts,
3412 commitopts + commitopts2 + similarityopts,
3413 _('[OPTION]... PATCH...'))
3413 _('[OPTION]... PATCH...'))
3414 def import_(ui, repo, patch1=None, *patches, **opts):
3414 def import_(ui, repo, patch1=None, *patches, **opts):
3415 """import an ordered set of patches
3415 """import an ordered set of patches
3416
3416
3417 Import a list of patches and commit them individually (unless
3417 Import a list of patches and commit them individually (unless
3418 --no-commit is specified).
3418 --no-commit is specified).
3419
3419
3420 If there are outstanding changes in the working directory, import
3420 If there are outstanding changes in the working directory, import
3421 will abort unless given the -f/--force flag.
3421 will abort unless given the -f/--force flag.
3422
3422
3423 You can import a patch straight from a mail message. Even patches
3423 You can import a patch straight from a mail message. Even patches
3424 as attachments work (to use the body part, it must have type
3424 as attachments work (to use the body part, it must have type
3425 text/plain or text/x-patch). From and Subject headers of email
3425 text/plain or text/x-patch). From and Subject headers of email
3426 message are used as default committer and commit message. All
3426 message are used as default committer and commit message. All
3427 text/plain body parts before first diff are added to commit
3427 text/plain body parts before first diff are added to commit
3428 message.
3428 message.
3429
3429
3430 If the imported patch was generated by :hg:`export`, user and
3430 If the imported patch was generated by :hg:`export`, user and
3431 description from patch override values from message headers and
3431 description from patch override values from message headers and
3432 body. Values given on command line with -m/--message and -u/--user
3432 body. Values given on command line with -m/--message and -u/--user
3433 override these.
3433 override these.
3434
3434
3435 If --exact is specified, import will set the working directory to
3435 If --exact is specified, import will set the working directory to
3436 the parent of each patch before applying it, and will abort if the
3436 the parent of each patch before applying it, and will abort if the
3437 resulting changeset has a different ID than the one recorded in
3437 resulting changeset has a different ID than the one recorded in
3438 the patch. This may happen due to character set problems or other
3438 the patch. This may happen due to character set problems or other
3439 deficiencies in the text patch format.
3439 deficiencies in the text patch format.
3440
3440
3441 Use --bypass to apply and commit patches directly to the
3441 Use --bypass to apply and commit patches directly to the
3442 repository, not touching the working directory. Without --exact,
3442 repository, not touching the working directory. Without --exact,
3443 patches will be applied on top of the working directory parent
3443 patches will be applied on top of the working directory parent
3444 revision.
3444 revision.
3445
3445
3446 With -s/--similarity, hg will attempt to discover renames and
3446 With -s/--similarity, hg will attempt to discover renames and
3447 copies in the patch in the same way as 'addremove'.
3447 copies in the patch in the same way as 'addremove'.
3448
3448
3449 To read a patch from standard input, use "-" as the patch name. If
3449 To read a patch from standard input, use "-" as the patch name. If
3450 a URL is specified, the patch will be downloaded from it.
3450 a URL is specified, the patch will be downloaded from it.
3451 See :hg:`help dates` for a list of formats valid for -d/--date.
3451 See :hg:`help dates` for a list of formats valid for -d/--date.
3452
3452
3453 .. container:: verbose
3453 .. container:: verbose
3454
3454
3455 Examples:
3455 Examples:
3456
3456
3457 - import a traditional patch from a website and detect renames::
3457 - import a traditional patch from a website and detect renames::
3458
3458
3459 hg import -s 80 http://example.com/bugfix.patch
3459 hg import -s 80 http://example.com/bugfix.patch
3460
3460
3461 - import a changeset from an hgweb server::
3461 - import a changeset from an hgweb server::
3462
3462
3463 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3463 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3464
3464
3465 - import all the patches in an Unix-style mbox::
3465 - import all the patches in an Unix-style mbox::
3466
3466
3467 hg import incoming-patches.mbox
3467 hg import incoming-patches.mbox
3468
3468
3469 - attempt to exactly restore an exported changeset (not always
3469 - attempt to exactly restore an exported changeset (not always
3470 possible)::
3470 possible)::
3471
3471
3472 hg import --exact proposed-fix.patch
3472 hg import --exact proposed-fix.patch
3473
3473
3474 Returns 0 on success.
3474 Returns 0 on success.
3475 """
3475 """
3476
3476
3477 if not patch1:
3477 if not patch1:
3478 raise util.Abort(_('need at least one patch to import'))
3478 raise util.Abort(_('need at least one patch to import'))
3479
3479
3480 patches = (patch1,) + patches
3480 patches = (patch1,) + patches
3481
3481
3482 date = opts.get('date')
3482 date = opts.get('date')
3483 if date:
3483 if date:
3484 opts['date'] = util.parsedate(date)
3484 opts['date'] = util.parsedate(date)
3485
3485
3486 editor = cmdutil.commiteditor
3486 editor = cmdutil.commiteditor
3487 if opts.get('edit'):
3487 if opts.get('edit'):
3488 editor = cmdutil.commitforceeditor
3488 editor = cmdutil.commitforceeditor
3489
3489
3490 update = not opts.get('bypass')
3490 update = not opts.get('bypass')
3491 if not update and opts.get('no_commit'):
3491 if not update and opts.get('no_commit'):
3492 raise util.Abort(_('cannot use --no-commit with --bypass'))
3492 raise util.Abort(_('cannot use --no-commit with --bypass'))
3493 try:
3493 try:
3494 sim = float(opts.get('similarity') or 0)
3494 sim = float(opts.get('similarity') or 0)
3495 except ValueError:
3495 except ValueError:
3496 raise util.Abort(_('similarity must be a number'))
3496 raise util.Abort(_('similarity must be a number'))
3497 if sim < 0 or sim > 100:
3497 if sim < 0 or sim > 100:
3498 raise util.Abort(_('similarity must be between 0 and 100'))
3498 raise util.Abort(_('similarity must be between 0 and 100'))
3499 if sim and not update:
3499 if sim and not update:
3500 raise util.Abort(_('cannot use --similarity with --bypass'))
3500 raise util.Abort(_('cannot use --similarity with --bypass'))
3501
3501
3502 if (opts.get('exact') or not opts.get('force')) and update:
3502 if (opts.get('exact') or not opts.get('force')) and update:
3503 cmdutil.bailifchanged(repo)
3503 cmdutil.bailifchanged(repo)
3504
3504
3505 base = opts["base"]
3505 base = opts["base"]
3506 strip = opts["strip"]
3506 strip = opts["strip"]
3507 wlock = lock = tr = None
3507 wlock = lock = tr = None
3508 msgs = []
3508 msgs = []
3509
3509
3510 def checkexact(repo, n, nodeid):
3510 def checkexact(repo, n, nodeid):
3511 if opts.get('exact') and hex(n) != nodeid:
3511 if opts.get('exact') and hex(n) != nodeid:
3512 repo.rollback()
3512 repo.rollback()
3513 raise util.Abort(_('patch is damaged or loses information'))
3513 raise util.Abort(_('patch is damaged or loses information'))
3514
3514
3515 def tryone(ui, hunk, parents):
3515 def tryone(ui, hunk, parents):
3516 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3516 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3517 patch.extract(ui, hunk)
3517 patch.extract(ui, hunk)
3518
3518
3519 if not tmpname:
3519 if not tmpname:
3520 return (None, None)
3520 return (None, None)
3521 msg = _('applied to working directory')
3521 msg = _('applied to working directory')
3522
3522
3523 try:
3523 try:
3524 cmdline_message = cmdutil.logmessage(ui, opts)
3524 cmdline_message = cmdutil.logmessage(ui, opts)
3525 if cmdline_message:
3525 if cmdline_message:
3526 # pickup the cmdline msg
3526 # pickup the cmdline msg
3527 message = cmdline_message
3527 message = cmdline_message
3528 elif message:
3528 elif message:
3529 # pickup the patch msg
3529 # pickup the patch msg
3530 message = message.strip()
3530 message = message.strip()
3531 else:
3531 else:
3532 # launch the editor
3532 # launch the editor
3533 message = None
3533 message = None
3534 ui.debug('message:\n%s\n' % message)
3534 ui.debug('message:\n%s\n' % message)
3535
3535
3536 if len(parents) == 1:
3536 if len(parents) == 1:
3537 parents.append(repo[nullid])
3537 parents.append(repo[nullid])
3538 if opts.get('exact'):
3538 if opts.get('exact'):
3539 if not nodeid or not p1:
3539 if not nodeid or not p1:
3540 raise util.Abort(_('not a Mercurial patch'))
3540 raise util.Abort(_('not a Mercurial patch'))
3541 p1 = repo[p1]
3541 p1 = repo[p1]
3542 p2 = repo[p2 or nullid]
3542 p2 = repo[p2 or nullid]
3543 elif p2:
3543 elif p2:
3544 try:
3544 try:
3545 p1 = repo[p1]
3545 p1 = repo[p1]
3546 p2 = repo[p2]
3546 p2 = repo[p2]
3547 # Without any options, consider p2 only if the
3547 # Without any options, consider p2 only if the
3548 # patch is being applied on top of the recorded
3548 # patch is being applied on top of the recorded
3549 # first parent.
3549 # first parent.
3550 if p1 != parents[0]:
3550 if p1 != parents[0]:
3551 p1 = parents[0]
3551 p1 = parents[0]
3552 p2 = repo[nullid]
3552 p2 = repo[nullid]
3553 except error.RepoError:
3553 except error.RepoError:
3554 p1, p2 = parents
3554 p1, p2 = parents
3555 else:
3555 else:
3556 p1, p2 = parents
3556 p1, p2 = parents
3557
3557
3558 n = None
3558 n = None
3559 if update:
3559 if update:
3560 if p1 != parents[0]:
3560 if p1 != parents[0]:
3561 hg.clean(repo, p1.node())
3561 hg.clean(repo, p1.node())
3562 if p2 != parents[1]:
3562 if p2 != parents[1]:
3563 repo.dirstate.setparents(p1.node(), p2.node())
3563 repo.dirstate.setparents(p1.node(), p2.node())
3564
3564
3565 if opts.get('exact') or opts.get('import_branch'):
3565 if opts.get('exact') or opts.get('import_branch'):
3566 repo.dirstate.setbranch(branch or 'default')
3566 repo.dirstate.setbranch(branch or 'default')
3567
3567
3568 files = set()
3568 files = set()
3569 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3569 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3570 eolmode=None, similarity=sim / 100.0)
3570 eolmode=None, similarity=sim / 100.0)
3571 files = list(files)
3571 files = list(files)
3572 if opts.get('no_commit'):
3572 if opts.get('no_commit'):
3573 if message:
3573 if message:
3574 msgs.append(message)
3574 msgs.append(message)
3575 else:
3575 else:
3576 if opts.get('exact') or p2:
3576 if opts.get('exact') or p2:
3577 # If you got here, you either use --force and know what
3577 # If you got here, you either use --force and know what
3578 # you are doing or used --exact or a merge patch while
3578 # you are doing or used --exact or a merge patch while
3579 # being updated to its first parent.
3579 # being updated to its first parent.
3580 m = None
3580 m = None
3581 else:
3581 else:
3582 m = scmutil.matchfiles(repo, files or [])
3582 m = scmutil.matchfiles(repo, files or [])
3583 n = repo.commit(message, opts.get('user') or user,
3583 n = repo.commit(message, opts.get('user') or user,
3584 opts.get('date') or date, match=m,
3584 opts.get('date') or date, match=m,
3585 editor=editor)
3585 editor=editor)
3586 checkexact(repo, n, nodeid)
3586 checkexact(repo, n, nodeid)
3587 else:
3587 else:
3588 if opts.get('exact') or opts.get('import_branch'):
3588 if opts.get('exact') or opts.get('import_branch'):
3589 branch = branch or 'default'
3589 branch = branch or 'default'
3590 else:
3590 else:
3591 branch = p1.branch()
3591 branch = p1.branch()
3592 store = patch.filestore()
3592 store = patch.filestore()
3593 try:
3593 try:
3594 files = set()
3594 files = set()
3595 try:
3595 try:
3596 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3596 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3597 files, eolmode=None)
3597 files, eolmode=None)
3598 except patch.PatchError, e:
3598 except patch.PatchError, e:
3599 raise util.Abort(str(e))
3599 raise util.Abort(str(e))
3600 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3600 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3601 message,
3601 message,
3602 opts.get('user') or user,
3602 opts.get('user') or user,
3603 opts.get('date') or date,
3603 opts.get('date') or date,
3604 branch, files, store,
3604 branch, files, store,
3605 editor=cmdutil.commiteditor)
3605 editor=cmdutil.commiteditor)
3606 repo.savecommitmessage(memctx.description())
3606 repo.savecommitmessage(memctx.description())
3607 n = memctx.commit()
3607 n = memctx.commit()
3608 checkexact(repo, n, nodeid)
3608 checkexact(repo, n, nodeid)
3609 finally:
3609 finally:
3610 store.close()
3610 store.close()
3611 if n:
3611 if n:
3612 # i18n: refers to a short changeset id
3612 # i18n: refers to a short changeset id
3613 msg = _('created %s') % short(n)
3613 msg = _('created %s') % short(n)
3614 return (msg, n)
3614 return (msg, n)
3615 finally:
3615 finally:
3616 os.unlink(tmpname)
3616 os.unlink(tmpname)
3617
3617
3618 try:
3618 try:
3619 try:
3619 try:
3620 wlock = repo.wlock()
3620 wlock = repo.wlock()
3621 lock = repo.lock()
3621 lock = repo.lock()
3622 tr = repo.transaction('import')
3622 tr = repo.transaction('import')
3623 parents = repo.parents()
3623 parents = repo.parents()
3624 for patchurl in patches:
3624 for patchurl in patches:
3625 if patchurl == '-':
3625 if patchurl == '-':
3626 ui.status(_('applying patch from stdin\n'))
3626 ui.status(_('applying patch from stdin\n'))
3627 patchfile = ui.fin
3627 patchfile = ui.fin
3628 patchurl = 'stdin' # for error message
3628 patchurl = 'stdin' # for error message
3629 else:
3629 else:
3630 patchurl = os.path.join(base, patchurl)
3630 patchurl = os.path.join(base, patchurl)
3631 ui.status(_('applying %s\n') % patchurl)
3631 ui.status(_('applying %s\n') % patchurl)
3632 patchfile = url.open(ui, patchurl)
3632 patchfile = url.open(ui, patchurl)
3633
3633
3634 haspatch = False
3634 haspatch = False
3635 for hunk in patch.split(patchfile):
3635 for hunk in patch.split(patchfile):
3636 (msg, node) = tryone(ui, hunk, parents)
3636 (msg, node) = tryone(ui, hunk, parents)
3637 if msg:
3637 if msg:
3638 haspatch = True
3638 haspatch = True
3639 ui.note(msg + '\n')
3639 ui.note(msg + '\n')
3640 if update or opts.get('exact'):
3640 if update or opts.get('exact'):
3641 parents = repo.parents()
3641 parents = repo.parents()
3642 else:
3642 else:
3643 parents = [repo[node]]
3643 parents = [repo[node]]
3644
3644
3645 if not haspatch:
3645 if not haspatch:
3646 raise util.Abort(_('%s: no diffs found') % patchurl)
3646 raise util.Abort(_('%s: no diffs found') % patchurl)
3647
3647
3648 tr.close()
3648 tr.close()
3649 if msgs:
3649 if msgs:
3650 repo.savecommitmessage('\n* * *\n'.join(msgs))
3650 repo.savecommitmessage('\n* * *\n'.join(msgs))
3651 except:
3651 except:
3652 # wlock.release() indirectly calls dirstate.write(): since
3652 # wlock.release() indirectly calls dirstate.write(): since
3653 # we're crashing, we do not want to change the working dir
3653 # we're crashing, we do not want to change the working dir
3654 # parent after all, so make sure it writes nothing
3654 # parent after all, so make sure it writes nothing
3655 repo.dirstate.invalidate()
3655 repo.dirstate.invalidate()
3656 raise
3656 raise
3657 finally:
3657 finally:
3658 if tr:
3658 if tr:
3659 tr.release()
3659 tr.release()
3660 release(lock, wlock)
3660 release(lock, wlock)
3661
3661
3662 @command('incoming|in',
3662 @command('incoming|in',
3663 [('f', 'force', None,
3663 [('f', 'force', None,
3664 _('run even if remote repository is unrelated')),
3664 _('run even if remote repository is unrelated')),
3665 ('n', 'newest-first', None, _('show newest record first')),
3665 ('n', 'newest-first', None, _('show newest record first')),
3666 ('', 'bundle', '',
3666 ('', 'bundle', '',
3667 _('file to store the bundles into'), _('FILE')),
3667 _('file to store the bundles into'), _('FILE')),
3668 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3668 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3669 ('B', 'bookmarks', False, _("compare bookmarks")),
3669 ('B', 'bookmarks', False, _("compare bookmarks")),
3670 ('b', 'branch', [],
3670 ('b', 'branch', [],
3671 _('a specific branch you would like to pull'), _('BRANCH')),
3671 _('a specific branch you would like to pull'), _('BRANCH')),
3672 ] + logopts + remoteopts + subrepoopts,
3672 ] + logopts + remoteopts + subrepoopts,
3673 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3673 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3674 def incoming(ui, repo, source="default", **opts):
3674 def incoming(ui, repo, source="default", **opts):
3675 """show new changesets found in source
3675 """show new changesets found in source
3676
3676
3677 Show new changesets found in the specified path/URL or the default
3677 Show new changesets found in the specified path/URL or the default
3678 pull location. These are the changesets that would have been pulled
3678 pull location. These are the changesets that would have been pulled
3679 if a pull at the time you issued this command.
3679 if a pull at the time you issued this command.
3680
3680
3681 For remote repository, using --bundle avoids downloading the
3681 For remote repository, using --bundle avoids downloading the
3682 changesets twice if the incoming is followed by a pull.
3682 changesets twice if the incoming is followed by a pull.
3683
3683
3684 See pull for valid source format details.
3684 See pull for valid source format details.
3685
3685
3686 Returns 0 if there are incoming changes, 1 otherwise.
3686 Returns 0 if there are incoming changes, 1 otherwise.
3687 """
3687 """
3688 if opts.get('bundle') and opts.get('subrepos'):
3688 if opts.get('bundle') and opts.get('subrepos'):
3689 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3689 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3690
3690
3691 if opts.get('bookmarks'):
3691 if opts.get('bookmarks'):
3692 source, branches = hg.parseurl(ui.expandpath(source),
3692 source, branches = hg.parseurl(ui.expandpath(source),
3693 opts.get('branch'))
3693 opts.get('branch'))
3694 other = hg.peer(repo, opts, source)
3694 other = hg.peer(repo, opts, source)
3695 if 'bookmarks' not in other.listkeys('namespaces'):
3695 if 'bookmarks' not in other.listkeys('namespaces'):
3696 ui.warn(_("remote doesn't support bookmarks\n"))
3696 ui.warn(_("remote doesn't support bookmarks\n"))
3697 return 0
3697 return 0
3698 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3698 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3699 return bookmarks.diff(ui, repo, other)
3699 return bookmarks.diff(ui, repo, other)
3700
3700
3701 repo._subtoppath = ui.expandpath(source)
3701 repo._subtoppath = ui.expandpath(source)
3702 try:
3702 try:
3703 return hg.incoming(ui, repo, source, opts)
3703 return hg.incoming(ui, repo, source, opts)
3704 finally:
3704 finally:
3705 del repo._subtoppath
3705 del repo._subtoppath
3706
3706
3707
3707
3708 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3708 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3709 def init(ui, dest=".", **opts):
3709 def init(ui, dest=".", **opts):
3710 """create a new repository in the given directory
3710 """create a new repository in the given directory
3711
3711
3712 Initialize a new repository in the given directory. If the given
3712 Initialize a new repository in the given directory. If the given
3713 directory does not exist, it will be created.
3713 directory does not exist, it will be created.
3714
3714
3715 If no directory is given, the current directory is used.
3715 If no directory is given, the current directory is used.
3716
3716
3717 It is possible to specify an ``ssh://`` URL as the destination.
3717 It is possible to specify an ``ssh://`` URL as the destination.
3718 See :hg:`help urls` for more information.
3718 See :hg:`help urls` for more information.
3719
3719
3720 Returns 0 on success.
3720 Returns 0 on success.
3721 """
3721 """
3722 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3722 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3723
3723
3724 @command('locate',
3724 @command('locate',
3725 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3725 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3726 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3726 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3727 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3727 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3728 ] + walkopts,
3728 ] + walkopts,
3729 _('[OPTION]... [PATTERN]...'))
3729 _('[OPTION]... [PATTERN]...'))
3730 def locate(ui, repo, *pats, **opts):
3730 def locate(ui, repo, *pats, **opts):
3731 """locate files matching specific patterns
3731 """locate files matching specific patterns
3732
3732
3733 Print files under Mercurial control in the working directory whose
3733 Print files under Mercurial control in the working directory whose
3734 names match the given patterns.
3734 names match the given patterns.
3735
3735
3736 By default, this command searches all directories in the working
3736 By default, this command searches all directories in the working
3737 directory. To search just the current directory and its
3737 directory. To search just the current directory and its
3738 subdirectories, use "--include .".
3738 subdirectories, use "--include .".
3739
3739
3740 If no patterns are given to match, this command prints the names
3740 If no patterns are given to match, this command prints the names
3741 of all files under Mercurial control in the working directory.
3741 of all files under Mercurial control in the working directory.
3742
3742
3743 If you want to feed the output of this command into the "xargs"
3743 If you want to feed the output of this command into the "xargs"
3744 command, use the -0 option to both this command and "xargs". This
3744 command, use the -0 option to both this command and "xargs". This
3745 will avoid the problem of "xargs" treating single filenames that
3745 will avoid the problem of "xargs" treating single filenames that
3746 contain whitespace as multiple filenames.
3746 contain whitespace as multiple filenames.
3747
3747
3748 Returns 0 if a match is found, 1 otherwise.
3748 Returns 0 if a match is found, 1 otherwise.
3749 """
3749 """
3750 end = opts.get('print0') and '\0' or '\n'
3750 end = opts.get('print0') and '\0' or '\n'
3751 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3751 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3752
3752
3753 ret = 1
3753 ret = 1
3754 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3754 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3755 m.bad = lambda x, y: False
3755 m.bad = lambda x, y: False
3756 for abs in repo[rev].walk(m):
3756 for abs in repo[rev].walk(m):
3757 if not rev and abs not in repo.dirstate:
3757 if not rev and abs not in repo.dirstate:
3758 continue
3758 continue
3759 if opts.get('fullpath'):
3759 if opts.get('fullpath'):
3760 ui.write(repo.wjoin(abs), end)
3760 ui.write(repo.wjoin(abs), end)
3761 else:
3761 else:
3762 ui.write(((pats and m.rel(abs)) or abs), end)
3762 ui.write(((pats and m.rel(abs)) or abs), end)
3763 ret = 0
3763 ret = 0
3764
3764
3765 return ret
3765 return ret
3766
3766
3767 @command('^log|history',
3767 @command('^log|history',
3768 [('f', 'follow', None,
3768 [('f', 'follow', None,
3769 _('follow changeset history, or file history across copies and renames')),
3769 _('follow changeset history, or file history across copies and renames')),
3770 ('', 'follow-first', None,
3770 ('', 'follow-first', None,
3771 _('only follow the first parent of merge changesets (DEPRECATED)')),
3771 _('only follow the first parent of merge changesets (DEPRECATED)')),
3772 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3772 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3773 ('C', 'copies', None, _('show copied files')),
3773 ('C', 'copies', None, _('show copied files')),
3774 ('k', 'keyword', [],
3774 ('k', 'keyword', [],
3775 _('do case-insensitive search for a given text'), _('TEXT')),
3775 _('do case-insensitive search for a given text'), _('TEXT')),
3776 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3776 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3777 ('', 'removed', None, _('include revisions where files were removed')),
3777 ('', 'removed', None, _('include revisions where files were removed')),
3778 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3778 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3779 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3779 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3780 ('', 'only-branch', [],
3780 ('', 'only-branch', [],
3781 _('show only changesets within the given named branch (DEPRECATED)'),
3781 _('show only changesets within the given named branch (DEPRECATED)'),
3782 _('BRANCH')),
3782 _('BRANCH')),
3783 ('b', 'branch', [],
3783 ('b', 'branch', [],
3784 _('show changesets within the given named branch'), _('BRANCH')),
3784 _('show changesets within the given named branch'), _('BRANCH')),
3785 ('P', 'prune', [],
3785 ('P', 'prune', [],
3786 _('do not display revision or any of its ancestors'), _('REV')),
3786 _('do not display revision or any of its ancestors'), _('REV')),
3787 ('', 'hidden', False, _('show hidden changesets (DEPRECATED)')),
3787 ('', 'hidden', False, _('show hidden changesets (DEPRECATED)')),
3788 ] + logopts + walkopts,
3788 ] + logopts + walkopts,
3789 _('[OPTION]... [FILE]'))
3789 _('[OPTION]... [FILE]'))
3790 def log(ui, repo, *pats, **opts):
3790 def log(ui, repo, *pats, **opts):
3791 """show revision history of entire repository or files
3791 """show revision history of entire repository or files
3792
3792
3793 Print the revision history of the specified files or the entire
3793 Print the revision history of the specified files or the entire
3794 project.
3794 project.
3795
3795
3796 If no revision range is specified, the default is ``tip:0`` unless
3796 If no revision range is specified, the default is ``tip:0`` unless
3797 --follow is set, in which case the working directory parent is
3797 --follow is set, in which case the working directory parent is
3798 used as the starting revision.
3798 used as the starting revision.
3799
3799
3800 File history is shown without following rename or copy history of
3800 File history is shown without following rename or copy history of
3801 files. Use -f/--follow with a filename to follow history across
3801 files. Use -f/--follow with a filename to follow history across
3802 renames and copies. --follow without a filename will only show
3802 renames and copies. --follow without a filename will only show
3803 ancestors or descendants of the starting revision.
3803 ancestors or descendants of the starting revision.
3804
3804
3805 By default this command prints revision number and changeset id,
3805 By default this command prints revision number and changeset id,
3806 tags, non-trivial parents, user, date and time, and a summary for
3806 tags, non-trivial parents, user, date and time, and a summary for
3807 each commit. When the -v/--verbose switch is used, the list of
3807 each commit. When the -v/--verbose switch is used, the list of
3808 changed files and full commit message are shown.
3808 changed files and full commit message are shown.
3809
3809
3810 .. note::
3810 .. note::
3811 log -p/--patch may generate unexpected diff output for merge
3811 log -p/--patch may generate unexpected diff output for merge
3812 changesets, as it will only compare the merge changeset against
3812 changesets, as it will only compare the merge changeset against
3813 its first parent. Also, only files different from BOTH parents
3813 its first parent. Also, only files different from BOTH parents
3814 will appear in files:.
3814 will appear in files:.
3815
3815
3816 .. note::
3816 .. note::
3817 for performance reasons, log FILE may omit duplicate changes
3817 for performance reasons, log FILE may omit duplicate changes
3818 made on branches and will not show deletions. To see all
3818 made on branches and will not show deletions. To see all
3819 changes including duplicates and deletions, use the --removed
3819 changes including duplicates and deletions, use the --removed
3820 switch.
3820 switch.
3821
3821
3822 .. container:: verbose
3822 .. container:: verbose
3823
3823
3824 Some examples:
3824 Some examples:
3825
3825
3826 - changesets with full descriptions and file lists::
3826 - changesets with full descriptions and file lists::
3827
3827
3828 hg log -v
3828 hg log -v
3829
3829
3830 - changesets ancestral to the working directory::
3830 - changesets ancestral to the working directory::
3831
3831
3832 hg log -f
3832 hg log -f
3833
3833
3834 - last 10 commits on the current branch::
3834 - last 10 commits on the current branch::
3835
3835
3836 hg log -l 10 -b .
3836 hg log -l 10 -b .
3837
3837
3838 - changesets showing all modifications of a file, including removals::
3838 - changesets showing all modifications of a file, including removals::
3839
3839
3840 hg log --removed file.c
3840 hg log --removed file.c
3841
3841
3842 - all changesets that touch a directory, with diffs, excluding merges::
3842 - all changesets that touch a directory, with diffs, excluding merges::
3843
3843
3844 hg log -Mp lib/
3844 hg log -Mp lib/
3845
3845
3846 - all revision numbers that match a keyword::
3846 - all revision numbers that match a keyword::
3847
3847
3848 hg log -k bug --template "{rev}\\n"
3848 hg log -k bug --template "{rev}\\n"
3849
3849
3850 - check if a given changeset is included is a tagged release::
3850 - check if a given changeset is included is a tagged release::
3851
3851
3852 hg log -r "a21ccf and ancestor(1.9)"
3852 hg log -r "a21ccf and ancestor(1.9)"
3853
3853
3854 - find all changesets by some user in a date range::
3854 - find all changesets by some user in a date range::
3855
3855
3856 hg log -k alice -d "may 2008 to jul 2008"
3856 hg log -k alice -d "may 2008 to jul 2008"
3857
3857
3858 - summary of all changesets after the last tag::
3858 - summary of all changesets after the last tag::
3859
3859
3860 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3860 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3861
3861
3862 See :hg:`help dates` for a list of formats valid for -d/--date.
3862 See :hg:`help dates` for a list of formats valid for -d/--date.
3863
3863
3864 See :hg:`help revisions` and :hg:`help revsets` for more about
3864 See :hg:`help revisions` and :hg:`help revsets` for more about
3865 specifying revisions.
3865 specifying revisions.
3866
3866
3867 Returns 0 on success.
3867 Returns 0 on success.
3868 """
3868 """
3869
3869
3870 matchfn = scmutil.match(repo[None], pats, opts)
3870 matchfn = scmutil.match(repo[None], pats, opts)
3871 limit = cmdutil.loglimit(opts)
3871 limit = cmdutil.loglimit(opts)
3872 count = 0
3872 count = 0
3873
3873
3874 endrev = None
3874 endrev = None
3875 if opts.get('copies') and opts.get('rev'):
3875 if opts.get('copies') and opts.get('rev'):
3876 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
3876 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
3877
3877
3878 df = False
3878 df = False
3879 if opts["date"]:
3879 if opts["date"]:
3880 df = util.matchdate(opts["date"])
3880 df = util.matchdate(opts["date"])
3881
3881
3882 branches = opts.get('branch', []) + opts.get('only_branch', [])
3882 branches = opts.get('branch', []) + opts.get('only_branch', [])
3883 opts['branch'] = [repo.lookupbranch(b) for b in branches]
3883 opts['branch'] = [repo.lookupbranch(b) for b in branches]
3884
3884
3885 displayer = cmdutil.show_changeset(ui, repo, opts, True)
3885 displayer = cmdutil.show_changeset(ui, repo, opts, True)
3886 def prep(ctx, fns):
3886 def prep(ctx, fns):
3887 rev = ctx.rev()
3887 rev = ctx.rev()
3888 parents = [p for p in repo.changelog.parentrevs(rev)
3888 parents = [p for p in repo.changelog.parentrevs(rev)
3889 if p != nullrev]
3889 if p != nullrev]
3890 if opts.get('no_merges') and len(parents) == 2:
3890 if opts.get('no_merges') and len(parents) == 2:
3891 return
3891 return
3892 if opts.get('only_merges') and len(parents) != 2:
3892 if opts.get('only_merges') and len(parents) != 2:
3893 return
3893 return
3894 if opts.get('branch') and ctx.branch() not in opts['branch']:
3894 if opts.get('branch') and ctx.branch() not in opts['branch']:
3895 return
3895 return
3896 if not opts.get('hidden') and ctx.hidden():
3896 if not opts.get('hidden') and ctx.hidden():
3897 return
3897 return
3898 if df and not df(ctx.date()[0]):
3898 if df and not df(ctx.date()[0]):
3899 return
3899 return
3900
3900
3901 lower = encoding.lower
3901 lower = encoding.lower
3902 if opts.get('user'):
3902 if opts.get('user'):
3903 luser = lower(ctx.user())
3903 luser = lower(ctx.user())
3904 for k in [lower(x) for x in opts['user']]:
3904 for k in [lower(x) for x in opts['user']]:
3905 if (k in luser):
3905 if (k in luser):
3906 break
3906 break
3907 else:
3907 else:
3908 return
3908 return
3909 if opts.get('keyword'):
3909 if opts.get('keyword'):
3910 luser = lower(ctx.user())
3910 luser = lower(ctx.user())
3911 ldesc = lower(ctx.description())
3911 ldesc = lower(ctx.description())
3912 lfiles = lower(" ".join(ctx.files()))
3912 lfiles = lower(" ".join(ctx.files()))
3913 for k in [lower(x) for x in opts['keyword']]:
3913 for k in [lower(x) for x in opts['keyword']]:
3914 if (k in luser or k in ldesc or k in lfiles):
3914 if (k in luser or k in ldesc or k in lfiles):
3915 break
3915 break
3916 else:
3916 else:
3917 return
3917 return
3918
3918
3919 copies = None
3919 copies = None
3920 if opts.get('copies') and rev:
3920 if opts.get('copies') and rev:
3921 copies = []
3921 copies = []
3922 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3922 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3923 for fn in ctx.files():
3923 for fn in ctx.files():
3924 rename = getrenamed(fn, rev)
3924 rename = getrenamed(fn, rev)
3925 if rename:
3925 if rename:
3926 copies.append((fn, rename[0]))
3926 copies.append((fn, rename[0]))
3927
3927
3928 revmatchfn = None
3928 revmatchfn = None
3929 if opts.get('patch') or opts.get('stat'):
3929 if opts.get('patch') or opts.get('stat'):
3930 if opts.get('follow') or opts.get('follow_first'):
3930 if opts.get('follow') or opts.get('follow_first'):
3931 # note: this might be wrong when following through merges
3931 # note: this might be wrong when following through merges
3932 revmatchfn = scmutil.match(repo[None], fns, default='path')
3932 revmatchfn = scmutil.match(repo[None], fns, default='path')
3933 else:
3933 else:
3934 revmatchfn = matchfn
3934 revmatchfn = matchfn
3935
3935
3936 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3936 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3937
3937
3938 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3938 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3939 if count == limit:
3939 if count == limit:
3940 break
3940 break
3941 if displayer.flush(ctx.rev()):
3941 if displayer.flush(ctx.rev()):
3942 count += 1
3942 count += 1
3943 displayer.close()
3943 displayer.close()
3944
3944
3945 @command('manifest',
3945 @command('manifest',
3946 [('r', 'rev', '', _('revision to display'), _('REV')),
3946 [('r', 'rev', '', _('revision to display'), _('REV')),
3947 ('', 'all', False, _("list files from all revisions"))],
3947 ('', 'all', False, _("list files from all revisions"))],
3948 _('[-r REV]'))
3948 _('[-r REV]'))
3949 def manifest(ui, repo, node=None, rev=None, **opts):
3949 def manifest(ui, repo, node=None, rev=None, **opts):
3950 """output the current or given revision of the project manifest
3950 """output the current or given revision of the project manifest
3951
3951
3952 Print a list of version controlled files for the given revision.
3952 Print a list of version controlled files for the given revision.
3953 If no revision is given, the first parent of the working directory
3953 If no revision is given, the first parent of the working directory
3954 is used, or the null revision if no revision is checked out.
3954 is used, or the null revision if no revision is checked out.
3955
3955
3956 With -v, print file permissions, symlink and executable bits.
3956 With -v, print file permissions, symlink and executable bits.
3957 With --debug, print file revision hashes.
3957 With --debug, print file revision hashes.
3958
3958
3959 If option --all is specified, the list of all files from all revisions
3959 If option --all is specified, the list of all files from all revisions
3960 is printed. This includes deleted and renamed files.
3960 is printed. This includes deleted and renamed files.
3961
3961
3962 Returns 0 on success.
3962 Returns 0 on success.
3963 """
3963 """
3964 if opts.get('all'):
3964 if opts.get('all'):
3965 if rev or node:
3965 if rev or node:
3966 raise util.Abort(_("can't specify a revision with --all"))
3966 raise util.Abort(_("can't specify a revision with --all"))
3967
3967
3968 res = []
3968 res = []
3969 prefix = "data/"
3969 prefix = "data/"
3970 suffix = ".i"
3970 suffix = ".i"
3971 plen = len(prefix)
3971 plen = len(prefix)
3972 slen = len(suffix)
3972 slen = len(suffix)
3973 lock = repo.lock()
3973 lock = repo.lock()
3974 try:
3974 try:
3975 for fn, b, size in repo.store.datafiles():
3975 for fn, b, size in repo.store.datafiles():
3976 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3976 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3977 res.append(fn[plen:-slen])
3977 res.append(fn[plen:-slen])
3978 finally:
3978 finally:
3979 lock.release()
3979 lock.release()
3980 for f in sorted(res):
3980 for f in sorted(res):
3981 ui.write("%s\n" % f)
3981 ui.write("%s\n" % f)
3982 return
3982 return
3983
3983
3984 if rev and node:
3984 if rev and node:
3985 raise util.Abort(_("please specify just one revision"))
3985 raise util.Abort(_("please specify just one revision"))
3986
3986
3987 if not node:
3987 if not node:
3988 node = rev
3988 node = rev
3989
3989
3990 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
3990 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
3991 ctx = scmutil.revsingle(repo, node)
3991 ctx = scmutil.revsingle(repo, node)
3992 for f in ctx:
3992 for f in ctx:
3993 if ui.debugflag:
3993 if ui.debugflag:
3994 ui.write("%40s " % hex(ctx.manifest()[f]))
3994 ui.write("%40s " % hex(ctx.manifest()[f]))
3995 if ui.verbose:
3995 if ui.verbose:
3996 ui.write(decor[ctx.flags(f)])
3996 ui.write(decor[ctx.flags(f)])
3997 ui.write("%s\n" % f)
3997 ui.write("%s\n" % f)
3998
3998
3999 @command('^merge',
3999 @command('^merge',
4000 [('f', 'force', None, _('force a merge with outstanding changes')),
4000 [('f', 'force', None, _('force a merge with outstanding changes')),
4001 ('r', 'rev', '', _('revision to merge'), _('REV')),
4001 ('r', 'rev', '', _('revision to merge'), _('REV')),
4002 ('P', 'preview', None,
4002 ('P', 'preview', None,
4003 _('review revisions to merge (no merge is performed)'))
4003 _('review revisions to merge (no merge is performed)'))
4004 ] + mergetoolopts,
4004 ] + mergetoolopts,
4005 _('[-P] [-f] [[-r] REV]'))
4005 _('[-P] [-f] [[-r] REV]'))
4006 def merge(ui, repo, node=None, **opts):
4006 def merge(ui, repo, node=None, **opts):
4007 """merge working directory with another revision
4007 """merge working directory with another revision
4008
4008
4009 The current working directory is updated with all changes made in
4009 The current working directory is updated with all changes made in
4010 the requested revision since the last common predecessor revision.
4010 the requested revision since the last common predecessor revision.
4011
4011
4012 Files that changed between either parent are marked as changed for
4012 Files that changed between either parent are marked as changed for
4013 the next commit and a commit must be performed before any further
4013 the next commit and a commit must be performed before any further
4014 updates to the repository are allowed. The next commit will have
4014 updates to the repository are allowed. The next commit will have
4015 two parents.
4015 two parents.
4016
4016
4017 ``--tool`` can be used to specify the merge tool used for file
4017 ``--tool`` can be used to specify the merge tool used for file
4018 merges. It overrides the HGMERGE environment variable and your
4018 merges. It overrides the HGMERGE environment variable and your
4019 configuration files. See :hg:`help merge-tools` for options.
4019 configuration files. See :hg:`help merge-tools` for options.
4020
4020
4021 If no revision is specified, the working directory's parent is a
4021 If no revision is specified, the working directory's parent is a
4022 head revision, and the current branch contains exactly one other
4022 head revision, and the current branch contains exactly one other
4023 head, the other head is merged with by default. Otherwise, an
4023 head, the other head is merged with by default. Otherwise, an
4024 explicit revision with which to merge with must be provided.
4024 explicit revision with which to merge with must be provided.
4025
4025
4026 :hg:`resolve` must be used to resolve unresolved files.
4026 :hg:`resolve` must be used to resolve unresolved files.
4027
4027
4028 To undo an uncommitted merge, use :hg:`update --clean .` which
4028 To undo an uncommitted merge, use :hg:`update --clean .` which
4029 will check out a clean copy of the original merge parent, losing
4029 will check out a clean copy of the original merge parent, losing
4030 all changes.
4030 all changes.
4031
4031
4032 Returns 0 on success, 1 if there are unresolved files.
4032 Returns 0 on success, 1 if there are unresolved files.
4033 """
4033 """
4034
4034
4035 if opts.get('rev') and node:
4035 if opts.get('rev') and node:
4036 raise util.Abort(_("please specify just one revision"))
4036 raise util.Abort(_("please specify just one revision"))
4037 if not node:
4037 if not node:
4038 node = opts.get('rev')
4038 node = opts.get('rev')
4039
4039
4040 if not node:
4040 if not node:
4041 branch = repo[None].branch()
4041 branch = repo[None].branch()
4042 bheads = repo.branchheads(branch)
4042 bheads = repo.branchheads(branch)
4043 if len(bheads) > 2:
4043 if len(bheads) > 2:
4044 raise util.Abort(_("branch '%s' has %d heads - "
4044 raise util.Abort(_("branch '%s' has %d heads - "
4045 "please merge with an explicit rev")
4045 "please merge with an explicit rev")
4046 % (branch, len(bheads)),
4046 % (branch, len(bheads)),
4047 hint=_("run 'hg heads .' to see heads"))
4047 hint=_("run 'hg heads .' to see heads"))
4048
4048
4049 parent = repo.dirstate.p1()
4049 parent = repo.dirstate.p1()
4050 if len(bheads) == 1:
4050 if len(bheads) == 1:
4051 if len(repo.heads()) > 1:
4051 if len(repo.heads()) > 1:
4052 raise util.Abort(_("branch '%s' has one head - "
4052 raise util.Abort(_("branch '%s' has one head - "
4053 "please merge with an explicit rev")
4053 "please merge with an explicit rev")
4054 % branch,
4054 % branch,
4055 hint=_("run 'hg heads' to see all heads"))
4055 hint=_("run 'hg heads' to see all heads"))
4056 msg, hint = _('nothing to merge'), None
4056 msg, hint = _('nothing to merge'), None
4057 if parent != repo.lookup(branch):
4057 if parent != repo.lookup(branch):
4058 hint = _("use 'hg update' instead")
4058 hint = _("use 'hg update' instead")
4059 raise util.Abort(msg, hint=hint)
4059 raise util.Abort(msg, hint=hint)
4060
4060
4061 if parent not in bheads:
4061 if parent not in bheads:
4062 raise util.Abort(_('working directory not at a head revision'),
4062 raise util.Abort(_('working directory not at a head revision'),
4063 hint=_("use 'hg update' or merge with an "
4063 hint=_("use 'hg update' or merge with an "
4064 "explicit revision"))
4064 "explicit revision"))
4065 node = parent == bheads[0] and bheads[-1] or bheads[0]
4065 node = parent == bheads[0] and bheads[-1] or bheads[0]
4066 else:
4066 else:
4067 node = scmutil.revsingle(repo, node).node()
4067 node = scmutil.revsingle(repo, node).node()
4068
4068
4069 if opts.get('preview'):
4069 if opts.get('preview'):
4070 # find nodes that are ancestors of p2 but not of p1
4070 # find nodes that are ancestors of p2 but not of p1
4071 p1 = repo.lookup('.')
4071 p1 = repo.lookup('.')
4072 p2 = repo.lookup(node)
4072 p2 = repo.lookup(node)
4073 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4073 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4074
4074
4075 displayer = cmdutil.show_changeset(ui, repo, opts)
4075 displayer = cmdutil.show_changeset(ui, repo, opts)
4076 for node in nodes:
4076 for node in nodes:
4077 displayer.show(repo[node])
4077 displayer.show(repo[node])
4078 displayer.close()
4078 displayer.close()
4079 return 0
4079 return 0
4080
4080
4081 try:
4081 try:
4082 # ui.forcemerge is an internal variable, do not document
4082 # ui.forcemerge is an internal variable, do not document
4083 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4083 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4084 return hg.merge(repo, node, force=opts.get('force'))
4084 return hg.merge(repo, node, force=opts.get('force'))
4085 finally:
4085 finally:
4086 ui.setconfig('ui', 'forcemerge', '')
4086 ui.setconfig('ui', 'forcemerge', '')
4087
4087
4088 @command('outgoing|out',
4088 @command('outgoing|out',
4089 [('f', 'force', None, _('run even when the destination is unrelated')),
4089 [('f', 'force', None, _('run even when the destination is unrelated')),
4090 ('r', 'rev', [],
4090 ('r', 'rev', [],
4091 _('a changeset intended to be included in the destination'), _('REV')),
4091 _('a changeset intended to be included in the destination'), _('REV')),
4092 ('n', 'newest-first', None, _('show newest record first')),
4092 ('n', 'newest-first', None, _('show newest record first')),
4093 ('B', 'bookmarks', False, _('compare bookmarks')),
4093 ('B', 'bookmarks', False, _('compare bookmarks')),
4094 ('b', 'branch', [], _('a specific branch you would like to push'),
4094 ('b', 'branch', [], _('a specific branch you would like to push'),
4095 _('BRANCH')),
4095 _('BRANCH')),
4096 ] + logopts + remoteopts + subrepoopts,
4096 ] + logopts + remoteopts + subrepoopts,
4097 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4097 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4098 def outgoing(ui, repo, dest=None, **opts):
4098 def outgoing(ui, repo, dest=None, **opts):
4099 """show changesets not found in the destination
4099 """show changesets not found in the destination
4100
4100
4101 Show changesets not found in the specified destination repository
4101 Show changesets not found in the specified destination repository
4102 or the default push location. These are the changesets that would
4102 or the default push location. These are the changesets that would
4103 be pushed if a push was requested.
4103 be pushed if a push was requested.
4104
4104
4105 See pull for details of valid destination formats.
4105 See pull for details of valid destination formats.
4106
4106
4107 Returns 0 if there are outgoing changes, 1 otherwise.
4107 Returns 0 if there are outgoing changes, 1 otherwise.
4108 """
4108 """
4109
4109
4110 if opts.get('bookmarks'):
4110 if opts.get('bookmarks'):
4111 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4111 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4112 dest, branches = hg.parseurl(dest, opts.get('branch'))
4112 dest, branches = hg.parseurl(dest, opts.get('branch'))
4113 other = hg.peer(repo, opts, dest)
4113 other = hg.peer(repo, opts, dest)
4114 if 'bookmarks' not in other.listkeys('namespaces'):
4114 if 'bookmarks' not in other.listkeys('namespaces'):
4115 ui.warn(_("remote doesn't support bookmarks\n"))
4115 ui.warn(_("remote doesn't support bookmarks\n"))
4116 return 0
4116 return 0
4117 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4117 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4118 return bookmarks.diff(ui, other, repo)
4118 return bookmarks.diff(ui, other, repo)
4119
4119
4120 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4120 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4121 try:
4121 try:
4122 return hg.outgoing(ui, repo, dest, opts)
4122 return hg.outgoing(ui, repo, dest, opts)
4123 finally:
4123 finally:
4124 del repo._subtoppath
4124 del repo._subtoppath
4125
4125
4126 @command('parents',
4126 @command('parents',
4127 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4127 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4128 ] + templateopts,
4128 ] + templateopts,
4129 _('[-r REV] [FILE]'))
4129 _('[-r REV] [FILE]'))
4130 def parents(ui, repo, file_=None, **opts):
4130 def parents(ui, repo, file_=None, **opts):
4131 """show the parents of the working directory or revision
4131 """show the parents of the working directory or revision
4132
4132
4133 Print the working directory's parent revisions. If a revision is
4133 Print the working directory's parent revisions. If a revision is
4134 given via -r/--rev, the parent of that revision will be printed.
4134 given via -r/--rev, the parent of that revision will be printed.
4135 If a file argument is given, the revision in which the file was
4135 If a file argument is given, the revision in which the file was
4136 last changed (before the working directory revision or the
4136 last changed (before the working directory revision or the
4137 argument to --rev if given) is printed.
4137 argument to --rev if given) is printed.
4138
4138
4139 Returns 0 on success.
4139 Returns 0 on success.
4140 """
4140 """
4141
4141
4142 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4142 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4143
4143
4144 if file_:
4144 if file_:
4145 m = scmutil.match(ctx, (file_,), opts)
4145 m = scmutil.match(ctx, (file_,), opts)
4146 if m.anypats() or len(m.files()) != 1:
4146 if m.anypats() or len(m.files()) != 1:
4147 raise util.Abort(_('can only specify an explicit filename'))
4147 raise util.Abort(_('can only specify an explicit filename'))
4148 file_ = m.files()[0]
4148 file_ = m.files()[0]
4149 filenodes = []
4149 filenodes = []
4150 for cp in ctx.parents():
4150 for cp in ctx.parents():
4151 if not cp:
4151 if not cp:
4152 continue
4152 continue
4153 try:
4153 try:
4154 filenodes.append(cp.filenode(file_))
4154 filenodes.append(cp.filenode(file_))
4155 except error.LookupError:
4155 except error.LookupError:
4156 pass
4156 pass
4157 if not filenodes:
4157 if not filenodes:
4158 raise util.Abort(_("'%s' not found in manifest!") % file_)
4158 raise util.Abort(_("'%s' not found in manifest!") % file_)
4159 fl = repo.file(file_)
4159 fl = repo.file(file_)
4160 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
4160 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
4161 else:
4161 else:
4162 p = [cp.node() for cp in ctx.parents()]
4162 p = [cp.node() for cp in ctx.parents()]
4163
4163
4164 displayer = cmdutil.show_changeset(ui, repo, opts)
4164 displayer = cmdutil.show_changeset(ui, repo, opts)
4165 for n in p:
4165 for n in p:
4166 if n != nullid:
4166 if n != nullid:
4167 displayer.show(repo[n])
4167 displayer.show(repo[n])
4168 displayer.close()
4168 displayer.close()
4169
4169
4170 @command('paths', [], _('[NAME]'))
4170 @command('paths', [], _('[NAME]'))
4171 def paths(ui, repo, search=None):
4171 def paths(ui, repo, search=None):
4172 """show aliases for remote repositories
4172 """show aliases for remote repositories
4173
4173
4174 Show definition of symbolic path name NAME. If no name is given,
4174 Show definition of symbolic path name NAME. If no name is given,
4175 show definition of all available names.
4175 show definition of all available names.
4176
4176
4177 Option -q/--quiet suppresses all output when searching for NAME
4177 Option -q/--quiet suppresses all output when searching for NAME
4178 and shows only the path names when listing all definitions.
4178 and shows only the path names when listing all definitions.
4179
4179
4180 Path names are defined in the [paths] section of your
4180 Path names are defined in the [paths] section of your
4181 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4181 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4182 repository, ``.hg/hgrc`` is used, too.
4182 repository, ``.hg/hgrc`` is used, too.
4183
4183
4184 The path names ``default`` and ``default-push`` have a special
4184 The path names ``default`` and ``default-push`` have a special
4185 meaning. When performing a push or pull operation, they are used
4185 meaning. When performing a push or pull operation, they are used
4186 as fallbacks if no location is specified on the command-line.
4186 as fallbacks if no location is specified on the command-line.
4187 When ``default-push`` is set, it will be used for push and
4187 When ``default-push`` is set, it will be used for push and
4188 ``default`` will be used for pull; otherwise ``default`` is used
4188 ``default`` will be used for pull; otherwise ``default`` is used
4189 as the fallback for both. When cloning a repository, the clone
4189 as the fallback for both. When cloning a repository, the clone
4190 source is written as ``default`` in ``.hg/hgrc``. Note that
4190 source is written as ``default`` in ``.hg/hgrc``. Note that
4191 ``default`` and ``default-push`` apply to all inbound (e.g.
4191 ``default`` and ``default-push`` apply to all inbound (e.g.
4192 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4192 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4193 :hg:`bundle`) operations.
4193 :hg:`bundle`) operations.
4194
4194
4195 See :hg:`help urls` for more information.
4195 See :hg:`help urls` for more information.
4196
4196
4197 Returns 0 on success.
4197 Returns 0 on success.
4198 """
4198 """
4199 if search:
4199 if search:
4200 for name, path in ui.configitems("paths"):
4200 for name, path in ui.configitems("paths"):
4201 if name == search:
4201 if name == search:
4202 ui.status("%s\n" % util.hidepassword(path))
4202 ui.status("%s\n" % util.hidepassword(path))
4203 return
4203 return
4204 if not ui.quiet:
4204 if not ui.quiet:
4205 ui.warn(_("not found!\n"))
4205 ui.warn(_("not found!\n"))
4206 return 1
4206 return 1
4207 else:
4207 else:
4208 for name, path in ui.configitems("paths"):
4208 for name, path in ui.configitems("paths"):
4209 if ui.quiet:
4209 if ui.quiet:
4210 ui.write("%s\n" % name)
4210 ui.write("%s\n" % name)
4211 else:
4211 else:
4212 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4212 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4213
4213
4214 def postincoming(ui, repo, modheads, optupdate, checkout):
4214 def postincoming(ui, repo, modheads, optupdate, checkout):
4215 if modheads == 0:
4215 if modheads == 0:
4216 return
4216 return
4217 if optupdate:
4217 if optupdate:
4218 try:
4218 try:
4219 return hg.update(repo, checkout)
4219 return hg.update(repo, checkout)
4220 except util.Abort, inst:
4220 except util.Abort, inst:
4221 ui.warn(_("not updating: %s\n" % str(inst)))
4221 ui.warn(_("not updating: %s\n" % str(inst)))
4222 return 0
4222 return 0
4223 if modheads > 1:
4223 if modheads > 1:
4224 currentbranchheads = len(repo.branchheads())
4224 currentbranchheads = len(repo.branchheads())
4225 if currentbranchheads == modheads:
4225 if currentbranchheads == modheads:
4226 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4226 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4227 elif currentbranchheads > 1:
4227 elif currentbranchheads > 1:
4228 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to merge)\n"))
4228 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to merge)\n"))
4229 else:
4229 else:
4230 ui.status(_("(run 'hg heads' to see heads)\n"))
4230 ui.status(_("(run 'hg heads' to see heads)\n"))
4231 else:
4231 else:
4232 ui.status(_("(run 'hg update' to get a working copy)\n"))
4232 ui.status(_("(run 'hg update' to get a working copy)\n"))
4233
4233
4234 @command('^pull',
4234 @command('^pull',
4235 [('u', 'update', None,
4235 [('u', 'update', None,
4236 _('update to new branch head if changesets were pulled')),
4236 _('update to new branch head if changesets were pulled')),
4237 ('f', 'force', None, _('run even when remote repository is unrelated')),
4237 ('f', 'force', None, _('run even when remote repository is unrelated')),
4238 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4238 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4239 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4239 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4240 ('b', 'branch', [], _('a specific branch you would like to pull'),
4240 ('b', 'branch', [], _('a specific branch you would like to pull'),
4241 _('BRANCH')),
4241 _('BRANCH')),
4242 ] + remoteopts,
4242 ] + remoteopts,
4243 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4243 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4244 def pull(ui, repo, source="default", **opts):
4244 def pull(ui, repo, source="default", **opts):
4245 """pull changes from the specified source
4245 """pull changes from the specified source
4246
4246
4247 Pull changes from a remote repository to a local one.
4247 Pull changes from a remote repository to a local one.
4248
4248
4249 This finds all changes from the repository at the specified path
4249 This finds all changes from the repository at the specified path
4250 or URL and adds them to a local repository (the current one unless
4250 or URL and adds them to a local repository (the current one unless
4251 -R is specified). By default, this does not update the copy of the
4251 -R is specified). By default, this does not update the copy of the
4252 project in the working directory.
4252 project in the working directory.
4253
4253
4254 Use :hg:`incoming` if you want to see what would have been added
4254 Use :hg:`incoming` if you want to see what would have been added
4255 by a pull at the time you issued this command. If you then decide
4255 by a pull at the time you issued this command. If you then decide
4256 to add those changes to the repository, you should use :hg:`pull
4256 to add those changes to the repository, you should use :hg:`pull
4257 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4257 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4258
4258
4259 If SOURCE is omitted, the 'default' path will be used.
4259 If SOURCE is omitted, the 'default' path will be used.
4260 See :hg:`help urls` for more information.
4260 See :hg:`help urls` for more information.
4261
4261
4262 Returns 0 on success, 1 if an update had unresolved files.
4262 Returns 0 on success, 1 if an update had unresolved files.
4263 """
4263 """
4264 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4264 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4265 other = hg.peer(repo, opts, source)
4265 other = hg.peer(repo, opts, source)
4266 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4266 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4267 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4267 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4268
4268
4269 if opts.get('bookmark'):
4269 if opts.get('bookmark'):
4270 if not revs:
4270 if not revs:
4271 revs = []
4271 revs = []
4272 rb = other.listkeys('bookmarks')
4272 rb = other.listkeys('bookmarks')
4273 for b in opts['bookmark']:
4273 for b in opts['bookmark']:
4274 if b not in rb:
4274 if b not in rb:
4275 raise util.Abort(_('remote bookmark %s not found!') % b)
4275 raise util.Abort(_('remote bookmark %s not found!') % b)
4276 revs.append(rb[b])
4276 revs.append(rb[b])
4277
4277
4278 if revs:
4278 if revs:
4279 try:
4279 try:
4280 revs = [other.lookup(rev) for rev in revs]
4280 revs = [other.lookup(rev) for rev in revs]
4281 except error.CapabilityError:
4281 except error.CapabilityError:
4282 err = _("other repository doesn't support revision lookup, "
4282 err = _("other repository doesn't support revision lookup, "
4283 "so a rev cannot be specified.")
4283 "so a rev cannot be specified.")
4284 raise util.Abort(err)
4284 raise util.Abort(err)
4285
4285
4286 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4286 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4287 bookmarks.updatefromremote(ui, repo, other, source)
4287 bookmarks.updatefromremote(ui, repo, other, source)
4288 if checkout:
4288 if checkout:
4289 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4289 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4290 repo._subtoppath = source
4290 repo._subtoppath = source
4291 try:
4291 try:
4292 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4292 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4293
4293
4294 finally:
4294 finally:
4295 del repo._subtoppath
4295 del repo._subtoppath
4296
4296
4297 # update specified bookmarks
4297 # update specified bookmarks
4298 if opts.get('bookmark'):
4298 if opts.get('bookmark'):
4299 for b in opts['bookmark']:
4299 for b in opts['bookmark']:
4300 # explicit pull overrides local bookmark if any
4300 # explicit pull overrides local bookmark if any
4301 ui.status(_("importing bookmark %s\n") % b)
4301 ui.status(_("importing bookmark %s\n") % b)
4302 repo._bookmarks[b] = repo[rb[b]].node()
4302 repo._bookmarks[b] = repo[rb[b]].node()
4303 bookmarks.write(repo)
4303 bookmarks.write(repo)
4304
4304
4305 return ret
4305 return ret
4306
4306
4307 @command('^push',
4307 @command('^push',
4308 [('f', 'force', None, _('force push')),
4308 [('f', 'force', None, _('force push')),
4309 ('r', 'rev', [],
4309 ('r', 'rev', [],
4310 _('a changeset intended to be included in the destination'),
4310 _('a changeset intended to be included in the destination'),
4311 _('REV')),
4311 _('REV')),
4312 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4312 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4313 ('b', 'branch', [],
4313 ('b', 'branch', [],
4314 _('a specific branch you would like to push'), _('BRANCH')),
4314 _('a specific branch you would like to push'), _('BRANCH')),
4315 ('', 'new-branch', False, _('allow pushing a new branch')),
4315 ('', 'new-branch', False, _('allow pushing a new branch')),
4316 ] + remoteopts,
4316 ] + remoteopts,
4317 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4317 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4318 def push(ui, repo, dest=None, **opts):
4318 def push(ui, repo, dest=None, **opts):
4319 """push changes to the specified destination
4319 """push changes to the specified destination
4320
4320
4321 Push changesets from the local repository to the specified
4321 Push changesets from the local repository to the specified
4322 destination.
4322 destination.
4323
4323
4324 This operation is symmetrical to pull: it is identical to a pull
4324 This operation is symmetrical to pull: it is identical to a pull
4325 in the destination repository from the current one.
4325 in the destination repository from the current one.
4326
4326
4327 By default, push will not allow creation of new heads at the
4327 By default, push will not allow creation of new heads at the
4328 destination, since multiple heads would make it unclear which head
4328 destination, since multiple heads would make it unclear which head
4329 to use. In this situation, it is recommended to pull and merge
4329 to use. In this situation, it is recommended to pull and merge
4330 before pushing.
4330 before pushing.
4331
4331
4332 Use --new-branch if you want to allow push to create a new named
4332 Use --new-branch if you want to allow push to create a new named
4333 branch that is not present at the destination. This allows you to
4333 branch that is not present at the destination. This allows you to
4334 only create a new branch without forcing other changes.
4334 only create a new branch without forcing other changes.
4335
4335
4336 Use -f/--force to override the default behavior and push all
4336 Use -f/--force to override the default behavior and push all
4337 changesets on all branches.
4337 changesets on all branches.
4338
4338
4339 If -r/--rev is used, the specified revision and all its ancestors
4339 If -r/--rev is used, the specified revision and all its ancestors
4340 will be pushed to the remote repository.
4340 will be pushed to the remote repository.
4341
4341
4342 Please see :hg:`help urls` for important details about ``ssh://``
4342 Please see :hg:`help urls` for important details about ``ssh://``
4343 URLs. If DESTINATION is omitted, a default path will be used.
4343 URLs. If DESTINATION is omitted, a default path will be used.
4344
4344
4345 Returns 0 if push was successful, 1 if nothing to push.
4345 Returns 0 if push was successful, 1 if nothing to push.
4346 """
4346 """
4347
4347
4348 if opts.get('bookmark'):
4348 if opts.get('bookmark'):
4349 for b in opts['bookmark']:
4349 for b in opts['bookmark']:
4350 # translate -B options to -r so changesets get pushed
4350 # translate -B options to -r so changesets get pushed
4351 if b in repo._bookmarks:
4351 if b in repo._bookmarks:
4352 opts.setdefault('rev', []).append(b)
4352 opts.setdefault('rev', []).append(b)
4353 else:
4353 else:
4354 # if we try to push a deleted bookmark, translate it to null
4354 # if we try to push a deleted bookmark, translate it to null
4355 # this lets simultaneous -r, -b options continue working
4355 # this lets simultaneous -r, -b options continue working
4356 opts.setdefault('rev', []).append("null")
4356 opts.setdefault('rev', []).append("null")
4357
4357
4358 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4358 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4359 dest, branches = hg.parseurl(dest, opts.get('branch'))
4359 dest, branches = hg.parseurl(dest, opts.get('branch'))
4360 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4360 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4361 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4361 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4362 other = hg.peer(repo, opts, dest)
4362 other = hg.peer(repo, opts, dest)
4363 if revs:
4363 if revs:
4364 revs = [repo.lookup(rev) for rev in revs]
4364 revs = [repo.lookup(rev) for rev in revs]
4365
4365
4366 repo._subtoppath = dest
4366 repo._subtoppath = dest
4367 try:
4367 try:
4368 # push subrepos depth-first for coherent ordering
4368 # push subrepos depth-first for coherent ordering
4369 c = repo['']
4369 c = repo['']
4370 subs = c.substate # only repos that are committed
4370 subs = c.substate # only repos that are committed
4371 for s in sorted(subs):
4371 for s in sorted(subs):
4372 if not c.sub(s).push(opts):
4372 if not c.sub(s).push(opts):
4373 return False
4373 return False
4374 finally:
4374 finally:
4375 del repo._subtoppath
4375 del repo._subtoppath
4376 result = repo.push(other, opts.get('force'), revs=revs,
4376 result = repo.push(other, opts.get('force'), revs=revs,
4377 newbranch=opts.get('new_branch'))
4377 newbranch=opts.get('new_branch'))
4378
4378
4379 result = (result == 0)
4379 result = (result == 0)
4380
4380
4381 if opts.get('bookmark'):
4381 if opts.get('bookmark'):
4382 rb = other.listkeys('bookmarks')
4382 rb = other.listkeys('bookmarks')
4383 for b in opts['bookmark']:
4383 for b in opts['bookmark']:
4384 # explicit push overrides remote bookmark if any
4384 # explicit push overrides remote bookmark if any
4385 if b in repo._bookmarks:
4385 if b in repo._bookmarks:
4386 ui.status(_("exporting bookmark %s\n") % b)
4386 ui.status(_("exporting bookmark %s\n") % b)
4387 new = repo[b].hex()
4387 new = repo[b].hex()
4388 elif b in rb:
4388 elif b in rb:
4389 ui.status(_("deleting remote bookmark %s\n") % b)
4389 ui.status(_("deleting remote bookmark %s\n") % b)
4390 new = '' # delete
4390 new = '' # delete
4391 else:
4391 else:
4392 ui.warn(_('bookmark %s does not exist on the local '
4392 ui.warn(_('bookmark %s does not exist on the local '
4393 'or remote repository!\n') % b)
4393 'or remote repository!\n') % b)
4394 return 2
4394 return 2
4395 old = rb.get(b, '')
4395 old = rb.get(b, '')
4396 r = other.pushkey('bookmarks', b, old, new)
4396 r = other.pushkey('bookmarks', b, old, new)
4397 if not r:
4397 if not r:
4398 ui.warn(_('updating bookmark %s failed!\n') % b)
4398 ui.warn(_('updating bookmark %s failed!\n') % b)
4399 if not result:
4399 if not result:
4400 result = 2
4400 result = 2
4401
4401
4402 return result
4402 return result
4403
4403
4404 @command('recover', [])
4404 @command('recover', [])
4405 def recover(ui, repo):
4405 def recover(ui, repo):
4406 """roll back an interrupted transaction
4406 """roll back an interrupted transaction
4407
4407
4408 Recover from an interrupted commit or pull.
4408 Recover from an interrupted commit or pull.
4409
4409
4410 This command tries to fix the repository status after an
4410 This command tries to fix the repository status after an
4411 interrupted operation. It should only be necessary when Mercurial
4411 interrupted operation. It should only be necessary when Mercurial
4412 suggests it.
4412 suggests it.
4413
4413
4414 Returns 0 if successful, 1 if nothing to recover or verify fails.
4414 Returns 0 if successful, 1 if nothing to recover or verify fails.
4415 """
4415 """
4416 if repo.recover():
4416 if repo.recover():
4417 return hg.verify(repo)
4417 return hg.verify(repo)
4418 return 1
4418 return 1
4419
4419
4420 @command('^remove|rm',
4420 @command('^remove|rm',
4421 [('A', 'after', None, _('record delete for missing files')),
4421 [('A', 'after', None, _('record delete for missing files')),
4422 ('f', 'force', None,
4422 ('f', 'force', None,
4423 _('remove (and delete) file even if added or modified')),
4423 _('remove (and delete) file even if added or modified')),
4424 ] + walkopts,
4424 ] + walkopts,
4425 _('[OPTION]... FILE...'))
4425 _('[OPTION]... FILE...'))
4426 def remove(ui, repo, *pats, **opts):
4426 def remove(ui, repo, *pats, **opts):
4427 """remove the specified files on the next commit
4427 """remove the specified files on the next commit
4428
4428
4429 Schedule the indicated files for removal from the current branch.
4429 Schedule the indicated files for removal from the current branch.
4430
4430
4431 This command schedules the files to be removed at the next commit.
4431 This command schedules the files to be removed at the next commit.
4432 To undo a remove before that, see :hg:`revert`. To undo added
4432 To undo a remove before that, see :hg:`revert`. To undo added
4433 files, see :hg:`forget`.
4433 files, see :hg:`forget`.
4434
4434
4435 .. container:: verbose
4435 .. container:: verbose
4436
4436
4437 -A/--after can be used to remove only files that have already
4437 -A/--after can be used to remove only files that have already
4438 been deleted, -f/--force can be used to force deletion, and -Af
4438 been deleted, -f/--force can be used to force deletion, and -Af
4439 can be used to remove files from the next revision without
4439 can be used to remove files from the next revision without
4440 deleting them from the working directory.
4440 deleting them from the working directory.
4441
4441
4442 The following table details the behavior of remove for different
4442 The following table details the behavior of remove for different
4443 file states (columns) and option combinations (rows). The file
4443 file states (columns) and option combinations (rows). The file
4444 states are Added [A], Clean [C], Modified [M] and Missing [!]
4444 states are Added [A], Clean [C], Modified [M] and Missing [!]
4445 (as reported by :hg:`status`). The actions are Warn, Remove
4445 (as reported by :hg:`status`). The actions are Warn, Remove
4446 (from branch) and Delete (from disk):
4446 (from branch) and Delete (from disk):
4447
4447
4448 ======= == == == ==
4448 ======= == == == ==
4449 A C M !
4449 A C M !
4450 ======= == == == ==
4450 ======= == == == ==
4451 none W RD W R
4451 none W RD W R
4452 -f R RD RD R
4452 -f R RD RD R
4453 -A W W W R
4453 -A W W W R
4454 -Af R R R R
4454 -Af R R R R
4455 ======= == == == ==
4455 ======= == == == ==
4456
4456
4457 Note that remove never deletes files in Added [A] state from the
4457 Note that remove never deletes files in Added [A] state from the
4458 working directory, not even if option --force is specified.
4458 working directory, not even if option --force is specified.
4459
4459
4460 Returns 0 on success, 1 if any warnings encountered.
4460 Returns 0 on success, 1 if any warnings encountered.
4461 """
4461 """
4462
4462
4463 ret = 0
4463 ret = 0
4464 after, force = opts.get('after'), opts.get('force')
4464 after, force = opts.get('after'), opts.get('force')
4465 if not pats and not after:
4465 if not pats and not after:
4466 raise util.Abort(_('no files specified'))
4466 raise util.Abort(_('no files specified'))
4467
4467
4468 m = scmutil.match(repo[None], pats, opts)
4468 m = scmutil.match(repo[None], pats, opts)
4469 s = repo.status(match=m, clean=True)
4469 s = repo.status(match=m, clean=True)
4470 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4470 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4471
4471
4472 for f in m.files():
4472 for f in m.files():
4473 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
4473 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
4474 if os.path.exists(m.rel(f)):
4474 if os.path.exists(m.rel(f)):
4475 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4475 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4476 ret = 1
4476 ret = 1
4477
4477
4478 if force:
4478 if force:
4479 list = modified + deleted + clean + added
4479 list = modified + deleted + clean + added
4480 elif after:
4480 elif after:
4481 list = deleted
4481 list = deleted
4482 for f in modified + added + clean:
4482 for f in modified + added + clean:
4483 ui.warn(_('not removing %s: file still exists (use -f'
4483 ui.warn(_('not removing %s: file still exists (use -f'
4484 ' to force removal)\n') % m.rel(f))
4484 ' to force removal)\n') % m.rel(f))
4485 ret = 1
4485 ret = 1
4486 else:
4486 else:
4487 list = deleted + clean
4487 list = deleted + clean
4488 for f in modified:
4488 for f in modified:
4489 ui.warn(_('not removing %s: file is modified (use -f'
4489 ui.warn(_('not removing %s: file is modified (use -f'
4490 ' to force removal)\n') % m.rel(f))
4490 ' to force removal)\n') % m.rel(f))
4491 ret = 1
4491 ret = 1
4492 for f in added:
4492 for f in added:
4493 ui.warn(_('not removing %s: file has been marked for add'
4493 ui.warn(_('not removing %s: file has been marked for add'
4494 ' (use forget to undo)\n') % m.rel(f))
4494 ' (use forget to undo)\n') % m.rel(f))
4495 ret = 1
4495 ret = 1
4496
4496
4497 for f in sorted(list):
4497 for f in sorted(list):
4498 if ui.verbose or not m.exact(f):
4498 if ui.verbose or not m.exact(f):
4499 ui.status(_('removing %s\n') % m.rel(f))
4499 ui.status(_('removing %s\n') % m.rel(f))
4500
4500
4501 wlock = repo.wlock()
4501 wlock = repo.wlock()
4502 try:
4502 try:
4503 if not after:
4503 if not after:
4504 for f in list:
4504 for f in list:
4505 if f in added:
4505 if f in added:
4506 continue # we never unlink added files on remove
4506 continue # we never unlink added files on remove
4507 try:
4507 try:
4508 util.unlinkpath(repo.wjoin(f))
4508 util.unlinkpath(repo.wjoin(f))
4509 except OSError, inst:
4509 except OSError, inst:
4510 if inst.errno != errno.ENOENT:
4510 if inst.errno != errno.ENOENT:
4511 raise
4511 raise
4512 repo[None].forget(list)
4512 repo[None].forget(list)
4513 finally:
4513 finally:
4514 wlock.release()
4514 wlock.release()
4515
4515
4516 return ret
4516 return ret
4517
4517
4518 @command('rename|move|mv',
4518 @command('rename|move|mv',
4519 [('A', 'after', None, _('record a rename that has already occurred')),
4519 [('A', 'after', None, _('record a rename that has already occurred')),
4520 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4520 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4521 ] + walkopts + dryrunopts,
4521 ] + walkopts + dryrunopts,
4522 _('[OPTION]... SOURCE... DEST'))
4522 _('[OPTION]... SOURCE... DEST'))
4523 def rename(ui, repo, *pats, **opts):
4523 def rename(ui, repo, *pats, **opts):
4524 """rename files; equivalent of copy + remove
4524 """rename files; equivalent of copy + remove
4525
4525
4526 Mark dest as copies of sources; mark sources for deletion. If dest
4526 Mark dest as copies of sources; mark sources for deletion. If dest
4527 is a directory, copies are put in that directory. If dest is a
4527 is a directory, copies are put in that directory. If dest is a
4528 file, there can only be one source.
4528 file, there can only be one source.
4529
4529
4530 By default, this command copies the contents of files as they
4530 By default, this command copies the contents of files as they
4531 exist in the working directory. If invoked with -A/--after, the
4531 exist in the working directory. If invoked with -A/--after, the
4532 operation is recorded, but no copying is performed.
4532 operation is recorded, but no copying is performed.
4533
4533
4534 This command takes effect at the next commit. To undo a rename
4534 This command takes effect at the next commit. To undo a rename
4535 before that, see :hg:`revert`.
4535 before that, see :hg:`revert`.
4536
4536
4537 Returns 0 on success, 1 if errors are encountered.
4537 Returns 0 on success, 1 if errors are encountered.
4538 """
4538 """
4539 wlock = repo.wlock(False)
4539 wlock = repo.wlock(False)
4540 try:
4540 try:
4541 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4541 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4542 finally:
4542 finally:
4543 wlock.release()
4543 wlock.release()
4544
4544
4545 @command('resolve',
4545 @command('resolve',
4546 [('a', 'all', None, _('select all unresolved files')),
4546 [('a', 'all', None, _('select all unresolved files')),
4547 ('l', 'list', None, _('list state of files needing merge')),
4547 ('l', 'list', None, _('list state of files needing merge')),
4548 ('m', 'mark', None, _('mark files as resolved')),
4548 ('m', 'mark', None, _('mark files as resolved')),
4549 ('u', 'unmark', None, _('mark files as unresolved')),
4549 ('u', 'unmark', None, _('mark files as unresolved')),
4550 ('n', 'no-status', None, _('hide status prefix'))]
4550 ('n', 'no-status', None, _('hide status prefix'))]
4551 + mergetoolopts + walkopts,
4551 + mergetoolopts + walkopts,
4552 _('[OPTION]... [FILE]...'))
4552 _('[OPTION]... [FILE]...'))
4553 def resolve(ui, repo, *pats, **opts):
4553 def resolve(ui, repo, *pats, **opts):
4554 """redo merges or set/view the merge status of files
4554 """redo merges or set/view the merge status of files
4555
4555
4556 Merges with unresolved conflicts are often the result of
4556 Merges with unresolved conflicts are often the result of
4557 non-interactive merging using the ``internal:merge`` configuration
4557 non-interactive merging using the ``internal:merge`` configuration
4558 setting, or a command-line merge tool like ``diff3``. The resolve
4558 setting, or a command-line merge tool like ``diff3``. The resolve
4559 command is used to manage the files involved in a merge, after
4559 command is used to manage the files involved in a merge, after
4560 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4560 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4561 working directory must have two parents).
4561 working directory must have two parents).
4562
4562
4563 The resolve command can be used in the following ways:
4563 The resolve command can be used in the following ways:
4564
4564
4565 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4565 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4566 files, discarding any previous merge attempts. Re-merging is not
4566 files, discarding any previous merge attempts. Re-merging is not
4567 performed for files already marked as resolved. Use ``--all/-a``
4567 performed for files already marked as resolved. Use ``--all/-a``
4568 to select all unresolved files. ``--tool`` can be used to specify
4568 to select all unresolved files. ``--tool`` can be used to specify
4569 the merge tool used for the given files. It overrides the HGMERGE
4569 the merge tool used for the given files. It overrides the HGMERGE
4570 environment variable and your configuration files. Previous file
4570 environment variable and your configuration files. Previous file
4571 contents are saved with a ``.orig`` suffix.
4571 contents are saved with a ``.orig`` suffix.
4572
4572
4573 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4573 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4574 (e.g. after having manually fixed-up the files). The default is
4574 (e.g. after having manually fixed-up the files). The default is
4575 to mark all unresolved files.
4575 to mark all unresolved files.
4576
4576
4577 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4577 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4578 default is to mark all resolved files.
4578 default is to mark all resolved files.
4579
4579
4580 - :hg:`resolve -l`: list files which had or still have conflicts.
4580 - :hg:`resolve -l`: list files which had or still have conflicts.
4581 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4581 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4582
4582
4583 Note that Mercurial will not let you commit files with unresolved
4583 Note that Mercurial will not let you commit files with unresolved
4584 merge conflicts. You must use :hg:`resolve -m ...` before you can
4584 merge conflicts. You must use :hg:`resolve -m ...` before you can
4585 commit after a conflicting merge.
4585 commit after a conflicting merge.
4586
4586
4587 Returns 0 on success, 1 if any files fail a resolve attempt.
4587 Returns 0 on success, 1 if any files fail a resolve attempt.
4588 """
4588 """
4589
4589
4590 all, mark, unmark, show, nostatus = \
4590 all, mark, unmark, show, nostatus = \
4591 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4591 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4592
4592
4593 if (show and (mark or unmark)) or (mark and unmark):
4593 if (show and (mark or unmark)) or (mark and unmark):
4594 raise util.Abort(_("too many options specified"))
4594 raise util.Abort(_("too many options specified"))
4595 if pats and all:
4595 if pats and all:
4596 raise util.Abort(_("can't specify --all and patterns"))
4596 raise util.Abort(_("can't specify --all and patterns"))
4597 if not (all or pats or show or mark or unmark):
4597 if not (all or pats or show or mark or unmark):
4598 raise util.Abort(_('no files or directories specified; '
4598 raise util.Abort(_('no files or directories specified; '
4599 'use --all to remerge all files'))
4599 'use --all to remerge all files'))
4600
4600
4601 ms = mergemod.mergestate(repo)
4601 ms = mergemod.mergestate(repo)
4602 m = scmutil.match(repo[None], pats, opts)
4602 m = scmutil.match(repo[None], pats, opts)
4603 ret = 0
4603 ret = 0
4604
4604
4605 for f in ms:
4605 for f in ms:
4606 if m(f):
4606 if m(f):
4607 if show:
4607 if show:
4608 if nostatus:
4608 if nostatus:
4609 ui.write("%s\n" % f)
4609 ui.write("%s\n" % f)
4610 else:
4610 else:
4611 ui.write("%s %s\n" % (ms[f].upper(), f),
4611 ui.write("%s %s\n" % (ms[f].upper(), f),
4612 label='resolve.' +
4612 label='resolve.' +
4613 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4613 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4614 elif mark:
4614 elif mark:
4615 ms.mark(f, "r")
4615 ms.mark(f, "r")
4616 elif unmark:
4616 elif unmark:
4617 ms.mark(f, "u")
4617 ms.mark(f, "u")
4618 else:
4618 else:
4619 wctx = repo[None]
4619 wctx = repo[None]
4620 mctx = wctx.parents()[-1]
4620 mctx = wctx.parents()[-1]
4621
4621
4622 # backup pre-resolve (merge uses .orig for its own purposes)
4622 # backup pre-resolve (merge uses .orig for its own purposes)
4623 a = repo.wjoin(f)
4623 a = repo.wjoin(f)
4624 util.copyfile(a, a + ".resolve")
4624 util.copyfile(a, a + ".resolve")
4625
4625
4626 try:
4626 try:
4627 # resolve file
4627 # resolve file
4628 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4628 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4629 if ms.resolve(f, wctx, mctx):
4629 if ms.resolve(f, wctx, mctx):
4630 ret = 1
4630 ret = 1
4631 finally:
4631 finally:
4632 ui.setconfig('ui', 'forcemerge', '')
4632 ui.setconfig('ui', 'forcemerge', '')
4633
4633
4634 # replace filemerge's .orig file with our resolve file
4634 # replace filemerge's .orig file with our resolve file
4635 util.rename(a + ".resolve", a + ".orig")
4635 util.rename(a + ".resolve", a + ".orig")
4636
4636
4637 ms.commit()
4637 ms.commit()
4638 return ret
4638 return ret
4639
4639
4640 @command('revert',
4640 @command('revert',
4641 [('a', 'all', None, _('revert all changes when no arguments given')),
4641 [('a', 'all', None, _('revert all changes when no arguments given')),
4642 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4642 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4643 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4643 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4644 ('C', 'no-backup', None, _('do not save backup copies of files')),
4644 ('C', 'no-backup', None, _('do not save backup copies of files')),
4645 ] + walkopts + dryrunopts,
4645 ] + walkopts + dryrunopts,
4646 _('[OPTION]... [-r REV] [NAME]...'))
4646 _('[OPTION]... [-r REV] [NAME]...'))
4647 def revert(ui, repo, *pats, **opts):
4647 def revert(ui, repo, *pats, **opts):
4648 """restore files to their checkout state
4648 """restore files to their checkout state
4649
4649
4650 .. note::
4650 .. note::
4651 To check out earlier revisions, you should use :hg:`update REV`.
4651 To check out earlier revisions, you should use :hg:`update REV`.
4652 To cancel a merge (and lose your changes), use :hg:`update --clean .`.
4652 To cancel a merge (and lose your changes), use :hg:`update --clean .`.
4653
4653
4654 With no revision specified, revert the specified files or directories
4654 With no revision specified, revert the specified files or directories
4655 to the contents they had in the parent of the working directory.
4655 to the contents they had in the parent of the working directory.
4656 This restores the contents of files to an unmodified
4656 This restores the contents of files to an unmodified
4657 state and unschedules adds, removes, copies, and renames. If the
4657 state and unschedules adds, removes, copies, and renames. If the
4658 working directory has two parents, you must explicitly specify a
4658 working directory has two parents, you must explicitly specify a
4659 revision.
4659 revision.
4660
4660
4661 Using the -r/--rev or -d/--date options, revert the given files or
4661 Using the -r/--rev or -d/--date options, revert the given files or
4662 directories to their states as of a specific revision. Because
4662 directories to their states as of a specific revision. Because
4663 revert does not change the working directory parents, this will
4663 revert does not change the working directory parents, this will
4664 cause these files to appear modified. This can be helpful to "back
4664 cause these files to appear modified. This can be helpful to "back
4665 out" some or all of an earlier change. See :hg:`backout` for a
4665 out" some or all of an earlier change. See :hg:`backout` for a
4666 related method.
4666 related method.
4667
4667
4668 Modified files are saved with a .orig suffix before reverting.
4668 Modified files are saved with a .orig suffix before reverting.
4669 To disable these backups, use --no-backup.
4669 To disable these backups, use --no-backup.
4670
4670
4671 See :hg:`help dates` for a list of formats valid for -d/--date.
4671 See :hg:`help dates` for a list of formats valid for -d/--date.
4672
4672
4673 Returns 0 on success.
4673 Returns 0 on success.
4674 """
4674 """
4675
4675
4676 if opts.get("date"):
4676 if opts.get("date"):
4677 if opts.get("rev"):
4677 if opts.get("rev"):
4678 raise util.Abort(_("you can't specify a revision and a date"))
4678 raise util.Abort(_("you can't specify a revision and a date"))
4679 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4679 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4680
4680
4681 parent, p2 = repo.dirstate.parents()
4681 parent, p2 = repo.dirstate.parents()
4682 if not opts.get('rev') and p2 != nullid:
4682 if not opts.get('rev') and p2 != nullid:
4683 # revert after merge is a trap for new users (issue2915)
4683 # revert after merge is a trap for new users (issue2915)
4684 raise util.Abort(_('uncommitted merge with no revision specified'),
4684 raise util.Abort(_('uncommitted merge with no revision specified'),
4685 hint=_('use "hg update" or see "hg help revert"'))
4685 hint=_('use "hg update" or see "hg help revert"'))
4686
4686
4687 ctx = scmutil.revsingle(repo, opts.get('rev'))
4687 ctx = scmutil.revsingle(repo, opts.get('rev'))
4688 node = ctx.node()
4688 node = ctx.node()
4689
4689
4690 if not pats and not opts.get('all'):
4690 if not pats and not opts.get('all'):
4691 msg = _("no files or directories specified")
4691 msg = _("no files or directories specified")
4692 if p2 != nullid:
4692 if p2 != nullid:
4693 hint = _("uncommitted merge, use --all to discard all changes,"
4693 hint = _("uncommitted merge, use --all to discard all changes,"
4694 " or 'hg update -C .' to abort the merge")
4694 " or 'hg update -C .' to abort the merge")
4695 raise util.Abort(msg, hint=hint)
4695 raise util.Abort(msg, hint=hint)
4696 dirty = util.any(repo.status())
4696 dirty = util.any(repo.status())
4697 if node != parent:
4697 if node != parent:
4698 if dirty:
4698 if dirty:
4699 hint = _("uncommitted changes, use --all to discard all"
4699 hint = _("uncommitted changes, use --all to discard all"
4700 " changes, or 'hg update %s' to update") % ctx.rev()
4700 " changes, or 'hg update %s' to update") % ctx.rev()
4701 else:
4701 else:
4702 hint = _("use --all to revert all files,"
4702 hint = _("use --all to revert all files,"
4703 " or 'hg update %s' to update") % ctx.rev()
4703 " or 'hg update %s' to update") % ctx.rev()
4704 elif dirty:
4704 elif dirty:
4705 hint = _("uncommitted changes, use --all to discard all changes")
4705 hint = _("uncommitted changes, use --all to discard all changes")
4706 else:
4706 else:
4707 hint = _("use --all to revert all files")
4707 hint = _("use --all to revert all files")
4708 raise util.Abort(msg, hint=hint)
4708 raise util.Abort(msg, hint=hint)
4709
4709
4710 mf = ctx.manifest()
4710 mf = ctx.manifest()
4711 if node == parent:
4711 if node == parent:
4712 pmf = mf
4712 pmf = mf
4713 else:
4713 else:
4714 pmf = None
4714 pmf = None
4715
4715
4716 # need all matching names in dirstate and manifest of target rev,
4716 # need all matching names in dirstate and manifest of target rev,
4717 # so have to walk both. do not print errors if files exist in one
4717 # so have to walk both. do not print errors if files exist in one
4718 # but not other.
4718 # but not other.
4719
4719
4720 names = {}
4720 names = {}
4721
4721
4722 wlock = repo.wlock()
4722 wlock = repo.wlock()
4723 try:
4723 try:
4724 # walk dirstate.
4724 # walk dirstate.
4725
4725
4726 m = scmutil.match(repo[None], pats, opts)
4726 m = scmutil.match(repo[None], pats, opts)
4727 m.bad = lambda x, y: False
4727 m.bad = lambda x, y: False
4728 for abs in repo.walk(m):
4728 for abs in repo.walk(m):
4729 names[abs] = m.rel(abs), m.exact(abs)
4729 names[abs] = m.rel(abs), m.exact(abs)
4730
4730
4731 # walk target manifest.
4731 # walk target manifest.
4732
4732
4733 def badfn(path, msg):
4733 def badfn(path, msg):
4734 if path in names:
4734 if path in names:
4735 return
4735 return
4736 if path in repo[node].substate:
4736 if path in repo[node].substate:
4737 ui.warn("%s: %s\n" % (m.rel(path),
4737 ui.warn("%s: %s\n" % (m.rel(path),
4738 'reverting subrepos is unsupported'))
4738 'reverting subrepos is unsupported'))
4739 return
4739 return
4740 path_ = path + '/'
4740 path_ = path + '/'
4741 for f in names:
4741 for f in names:
4742 if f.startswith(path_):
4742 if f.startswith(path_):
4743 return
4743 return
4744 ui.warn("%s: %s\n" % (m.rel(path), msg))
4744 ui.warn("%s: %s\n" % (m.rel(path), msg))
4745
4745
4746 m = scmutil.match(repo[node], pats, opts)
4746 m = scmutil.match(repo[node], pats, opts)
4747 m.bad = badfn
4747 m.bad = badfn
4748 for abs in repo[node].walk(m):
4748 for abs in repo[node].walk(m):
4749 if abs not in names:
4749 if abs not in names:
4750 names[abs] = m.rel(abs), m.exact(abs)
4750 names[abs] = m.rel(abs), m.exact(abs)
4751
4751
4752 m = scmutil.matchfiles(repo, names)
4752 m = scmutil.matchfiles(repo, names)
4753 changes = repo.status(match=m)[:4]
4753 changes = repo.status(match=m)[:4]
4754 modified, added, removed, deleted = map(set, changes)
4754 modified, added, removed, deleted = map(set, changes)
4755
4755
4756 # if f is a rename, also revert the source
4756 # if f is a rename, also revert the source
4757 cwd = repo.getcwd()
4757 cwd = repo.getcwd()
4758 for f in added:
4758 for f in added:
4759 src = repo.dirstate.copied(f)
4759 src = repo.dirstate.copied(f)
4760 if src and src not in names and repo.dirstate[src] == 'r':
4760 if src and src not in names and repo.dirstate[src] == 'r':
4761 removed.add(src)
4761 removed.add(src)
4762 names[src] = (repo.pathto(src, cwd), True)
4762 names[src] = (repo.pathto(src, cwd), True)
4763
4763
4764 def removeforget(abs):
4764 def removeforget(abs):
4765 if repo.dirstate[abs] == 'a':
4765 if repo.dirstate[abs] == 'a':
4766 return _('forgetting %s\n')
4766 return _('forgetting %s\n')
4767 return _('removing %s\n')
4767 return _('removing %s\n')
4768
4768
4769 revert = ([], _('reverting %s\n'))
4769 revert = ([], _('reverting %s\n'))
4770 add = ([], _('adding %s\n'))
4770 add = ([], _('adding %s\n'))
4771 remove = ([], removeforget)
4771 remove = ([], removeforget)
4772 undelete = ([], _('undeleting %s\n'))
4772 undelete = ([], _('undeleting %s\n'))
4773
4773
4774 disptable = (
4774 disptable = (
4775 # dispatch table:
4775 # dispatch table:
4776 # file state
4776 # file state
4777 # action if in target manifest
4777 # action if in target manifest
4778 # action if not in target manifest
4778 # action if not in target manifest
4779 # make backup if in target manifest
4779 # make backup if in target manifest
4780 # make backup if not in target manifest
4780 # make backup if not in target manifest
4781 (modified, revert, remove, True, True),
4781 (modified, revert, remove, True, True),
4782 (added, revert, remove, True, False),
4782 (added, revert, remove, True, False),
4783 (removed, undelete, None, False, False),
4783 (removed, undelete, None, False, False),
4784 (deleted, revert, remove, False, False),
4784 (deleted, revert, remove, False, False),
4785 )
4785 )
4786
4786
4787 for abs, (rel, exact) in sorted(names.items()):
4787 for abs, (rel, exact) in sorted(names.items()):
4788 mfentry = mf.get(abs)
4788 mfentry = mf.get(abs)
4789 target = repo.wjoin(abs)
4789 target = repo.wjoin(abs)
4790 def handle(xlist, dobackup):
4790 def handle(xlist, dobackup):
4791 xlist[0].append(abs)
4791 xlist[0].append(abs)
4792 if (dobackup and not opts.get('no_backup') and
4792 if (dobackup and not opts.get('no_backup') and
4793 os.path.lexists(target)):
4793 os.path.lexists(target)):
4794 bakname = "%s.orig" % rel
4794 bakname = "%s.orig" % rel
4795 ui.note(_('saving current version of %s as %s\n') %
4795 ui.note(_('saving current version of %s as %s\n') %
4796 (rel, bakname))
4796 (rel, bakname))
4797 if not opts.get('dry_run'):
4797 if not opts.get('dry_run'):
4798 util.rename(target, bakname)
4798 util.rename(target, bakname)
4799 if ui.verbose or not exact:
4799 if ui.verbose or not exact:
4800 msg = xlist[1]
4800 msg = xlist[1]
4801 if not isinstance(msg, basestring):
4801 if not isinstance(msg, basestring):
4802 msg = msg(abs)
4802 msg = msg(abs)
4803 ui.status(msg % rel)
4803 ui.status(msg % rel)
4804 for table, hitlist, misslist, backuphit, backupmiss in disptable:
4804 for table, hitlist, misslist, backuphit, backupmiss in disptable:
4805 if abs not in table:
4805 if abs not in table:
4806 continue
4806 continue
4807 # file has changed in dirstate
4807 # file has changed in dirstate
4808 if mfentry:
4808 if mfentry:
4809 handle(hitlist, backuphit)
4809 handle(hitlist, backuphit)
4810 elif misslist is not None:
4810 elif misslist is not None:
4811 handle(misslist, backupmiss)
4811 handle(misslist, backupmiss)
4812 break
4812 break
4813 else:
4813 else:
4814 if abs not in repo.dirstate:
4814 if abs not in repo.dirstate:
4815 if mfentry:
4815 if mfentry:
4816 handle(add, True)
4816 handle(add, True)
4817 elif exact:
4817 elif exact:
4818 ui.warn(_('file not managed: %s\n') % rel)
4818 ui.warn(_('file not managed: %s\n') % rel)
4819 continue
4819 continue
4820 # file has not changed in dirstate
4820 # file has not changed in dirstate
4821 if node == parent:
4821 if node == parent:
4822 if exact:
4822 if exact:
4823 ui.warn(_('no changes needed to %s\n') % rel)
4823 ui.warn(_('no changes needed to %s\n') % rel)
4824 continue
4824 continue
4825 if pmf is None:
4825 if pmf is None:
4826 # only need parent manifest in this unlikely case,
4826 # only need parent manifest in this unlikely case,
4827 # so do not read by default
4827 # so do not read by default
4828 pmf = repo[parent].manifest()
4828 pmf = repo[parent].manifest()
4829 if abs in pmf and mfentry:
4829 if abs in pmf and mfentry:
4830 # if version of file is same in parent and target
4830 # if version of file is same in parent and target
4831 # manifests, do nothing
4831 # manifests, do nothing
4832 if (pmf[abs] != mfentry or
4832 if (pmf[abs] != mfentry or
4833 pmf.flags(abs) != mf.flags(abs)):
4833 pmf.flags(abs) != mf.flags(abs)):
4834 handle(revert, False)
4834 handle(revert, False)
4835 else:
4835 else:
4836 handle(remove, False)
4836 handle(remove, False)
4837
4837
4838 if not opts.get('dry_run'):
4838 if not opts.get('dry_run'):
4839 def checkout(f):
4839 def checkout(f):
4840 fc = ctx[f]
4840 fc = ctx[f]
4841 repo.wwrite(f, fc.data(), fc.flags())
4841 repo.wwrite(f, fc.data(), fc.flags())
4842
4842
4843 audit_path = scmutil.pathauditor(repo.root)
4843 audit_path = scmutil.pathauditor(repo.root)
4844 for f in remove[0]:
4844 for f in remove[0]:
4845 if repo.dirstate[f] == 'a':
4845 if repo.dirstate[f] == 'a':
4846 repo.dirstate.drop(f)
4846 repo.dirstate.drop(f)
4847 continue
4847 continue
4848 audit_path(f)
4848 audit_path(f)
4849 try:
4849 try:
4850 util.unlinkpath(repo.wjoin(f))
4850 util.unlinkpath(repo.wjoin(f))
4851 except OSError:
4851 except OSError:
4852 pass
4852 pass
4853 repo.dirstate.remove(f)
4853 repo.dirstate.remove(f)
4854
4854
4855 normal = None
4855 normal = None
4856 if node == parent:
4856 if node == parent:
4857 # We're reverting to our parent. If possible, we'd like status
4857 # We're reverting to our parent. If possible, we'd like status
4858 # to report the file as clean. We have to use normallookup for
4858 # to report the file as clean. We have to use normallookup for
4859 # merges to avoid losing information about merged/dirty files.
4859 # merges to avoid losing information about merged/dirty files.
4860 if p2 != nullid:
4860 if p2 != nullid:
4861 normal = repo.dirstate.normallookup
4861 normal = repo.dirstate.normallookup
4862 else:
4862 else:
4863 normal = repo.dirstate.normal
4863 normal = repo.dirstate.normal
4864 for f in revert[0]:
4864 for f in revert[0]:
4865 checkout(f)
4865 checkout(f)
4866 if normal:
4866 if normal:
4867 normal(f)
4867 normal(f)
4868
4868
4869 for f in add[0]:
4869 for f in add[0]:
4870 checkout(f)
4870 checkout(f)
4871 repo.dirstate.add(f)
4871 repo.dirstate.add(f)
4872
4872
4873 normal = repo.dirstate.normallookup
4873 normal = repo.dirstate.normallookup
4874 if node == parent and p2 == nullid:
4874 if node == parent and p2 == nullid:
4875 normal = repo.dirstate.normal
4875 normal = repo.dirstate.normal
4876 for f in undelete[0]:
4876 for f in undelete[0]:
4877 checkout(f)
4877 checkout(f)
4878 normal(f)
4878 normal(f)
4879
4879
4880 finally:
4880 finally:
4881 wlock.release()
4881 wlock.release()
4882
4882
4883 @command('rollback', dryrunopts +
4883 @command('rollback', dryrunopts +
4884 [('f', 'force', False, _('ignore safety measures'))])
4884 [('f', 'force', False, _('ignore safety measures'))])
4885 def rollback(ui, repo, **opts):
4885 def rollback(ui, repo, **opts):
4886 """roll back the last transaction (dangerous)
4886 """roll back the last transaction (dangerous)
4887
4887
4888 This command should be used with care. There is only one level of
4888 This command should be used with care. There is only one level of
4889 rollback, and there is no way to undo a rollback. It will also
4889 rollback, and there is no way to undo a rollback. It will also
4890 restore the dirstate at the time of the last transaction, losing
4890 restore the dirstate at the time of the last transaction, losing
4891 any dirstate changes since that time. This command does not alter
4891 any dirstate changes since that time. This command does not alter
4892 the working directory.
4892 the working directory.
4893
4893
4894 Transactions are used to encapsulate the effects of all commands
4894 Transactions are used to encapsulate the effects of all commands
4895 that create new changesets or propagate existing changesets into a
4895 that create new changesets or propagate existing changesets into a
4896 repository. For example, the following commands are transactional,
4896 repository. For example, the following commands are transactional,
4897 and their effects can be rolled back:
4897 and their effects can be rolled back:
4898
4898
4899 - commit
4899 - commit
4900 - import
4900 - import
4901 - pull
4901 - pull
4902 - push (with this repository as the destination)
4902 - push (with this repository as the destination)
4903 - unbundle
4903 - unbundle
4904
4904
4905 To avoid permanent data loss, rollback will refuse to rollback a
4905 To avoid permanent data loss, rollback will refuse to rollback a
4906 commit transaction if it isn't checked out. Use --force to
4906 commit transaction if it isn't checked out. Use --force to
4907 override this protection.
4907 override this protection.
4908
4908
4909 This command is not intended for use on public repositories. Once
4909 This command is not intended for use on public repositories. Once
4910 changes are visible for pull by other users, rolling a transaction
4910 changes are visible for pull by other users, rolling a transaction
4911 back locally is ineffective (someone else may already have pulled
4911 back locally is ineffective (someone else may already have pulled
4912 the changes). Furthermore, a race is possible with readers of the
4912 the changes). Furthermore, a race is possible with readers of the
4913 repository; for example an in-progress pull from the repository
4913 repository; for example an in-progress pull from the repository
4914 may fail if a rollback is performed.
4914 may fail if a rollback is performed.
4915
4915
4916 Returns 0 on success, 1 if no rollback data is available.
4916 Returns 0 on success, 1 if no rollback data is available.
4917 """
4917 """
4918 return repo.rollback(dryrun=opts.get('dry_run'),
4918 return repo.rollback(dryrun=opts.get('dry_run'),
4919 force=opts.get('force'))
4919 force=opts.get('force'))
4920
4920
4921 @command('root', [])
4921 @command('root', [])
4922 def root(ui, repo):
4922 def root(ui, repo):
4923 """print the root (top) of the current working directory
4923 """print the root (top) of the current working directory
4924
4924
4925 Print the root directory of the current repository.
4925 Print the root directory of the current repository.
4926
4926
4927 Returns 0 on success.
4927 Returns 0 on success.
4928 """
4928 """
4929 ui.write(repo.root + "\n")
4929 ui.write(repo.root + "\n")
4930
4930
4931 @command('^serve',
4931 @command('^serve',
4932 [('A', 'accesslog', '', _('name of access log file to write to'),
4932 [('A', 'accesslog', '', _('name of access log file to write to'),
4933 _('FILE')),
4933 _('FILE')),
4934 ('d', 'daemon', None, _('run server in background')),
4934 ('d', 'daemon', None, _('run server in background')),
4935 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
4935 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
4936 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4936 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4937 # use string type, then we can check if something was passed
4937 # use string type, then we can check if something was passed
4938 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4938 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4939 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4939 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4940 _('ADDR')),
4940 _('ADDR')),
4941 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4941 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4942 _('PREFIX')),
4942 _('PREFIX')),
4943 ('n', 'name', '',
4943 ('n', 'name', '',
4944 _('name to show in web pages (default: working directory)'), _('NAME')),
4944 _('name to show in web pages (default: working directory)'), _('NAME')),
4945 ('', 'web-conf', '',
4945 ('', 'web-conf', '',
4946 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
4946 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
4947 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4947 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4948 _('FILE')),
4948 _('FILE')),
4949 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4949 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4950 ('', 'stdio', None, _('for remote clients')),
4950 ('', 'stdio', None, _('for remote clients')),
4951 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
4951 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
4952 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4952 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4953 ('', 'style', '', _('template style to use'), _('STYLE')),
4953 ('', 'style', '', _('template style to use'), _('STYLE')),
4954 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4954 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4955 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
4955 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
4956 _('[OPTION]...'))
4956 _('[OPTION]...'))
4957 def serve(ui, repo, **opts):
4957 def serve(ui, repo, **opts):
4958 """start stand-alone webserver
4958 """start stand-alone webserver
4959
4959
4960 Start a local HTTP repository browser and pull server. You can use
4960 Start a local HTTP repository browser and pull server. You can use
4961 this for ad-hoc sharing and browsing of repositories. It is
4961 this for ad-hoc sharing and browsing of repositories. It is
4962 recommended to use a real web server to serve a repository for
4962 recommended to use a real web server to serve a repository for
4963 longer periods of time.
4963 longer periods of time.
4964
4964
4965 Please note that the server does not implement access control.
4965 Please note that the server does not implement access control.
4966 This means that, by default, anybody can read from the server and
4966 This means that, by default, anybody can read from the server and
4967 nobody can write to it by default. Set the ``web.allow_push``
4967 nobody can write to it by default. Set the ``web.allow_push``
4968 option to ``*`` to allow everybody to push to the server. You
4968 option to ``*`` to allow everybody to push to the server. You
4969 should use a real web server if you need to authenticate users.
4969 should use a real web server if you need to authenticate users.
4970
4970
4971 By default, the server logs accesses to stdout and errors to
4971 By default, the server logs accesses to stdout and errors to
4972 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4972 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4973 files.
4973 files.
4974
4974
4975 To have the server choose a free port number to listen on, specify
4975 To have the server choose a free port number to listen on, specify
4976 a port number of 0; in this case, the server will print the port
4976 a port number of 0; in this case, the server will print the port
4977 number it uses.
4977 number it uses.
4978
4978
4979 Returns 0 on success.
4979 Returns 0 on success.
4980 """
4980 """
4981
4981
4982 if opts["stdio"] and opts["cmdserver"]:
4982 if opts["stdio"] and opts["cmdserver"]:
4983 raise util.Abort(_("cannot use --stdio with --cmdserver"))
4983 raise util.Abort(_("cannot use --stdio with --cmdserver"))
4984
4984
4985 def checkrepo():
4985 def checkrepo():
4986 if repo is None:
4986 if repo is None:
4987 raise error.RepoError(_("There is no Mercurial repository here"
4987 raise error.RepoError(_("There is no Mercurial repository here"
4988 " (.hg not found)"))
4988 " (.hg not found)"))
4989
4989
4990 if opts["stdio"]:
4990 if opts["stdio"]:
4991 checkrepo()
4991 checkrepo()
4992 s = sshserver.sshserver(ui, repo)
4992 s = sshserver.sshserver(ui, repo)
4993 s.serve_forever()
4993 s.serve_forever()
4994
4994
4995 if opts["cmdserver"]:
4995 if opts["cmdserver"]:
4996 checkrepo()
4996 checkrepo()
4997 s = commandserver.server(ui, repo, opts["cmdserver"])
4997 s = commandserver.server(ui, repo, opts["cmdserver"])
4998 return s.serve()
4998 return s.serve()
4999
4999
5000 # this way we can check if something was given in the command-line
5000 # this way we can check if something was given in the command-line
5001 if opts.get('port'):
5001 if opts.get('port'):
5002 opts['port'] = util.getport(opts.get('port'))
5002 opts['port'] = util.getport(opts.get('port'))
5003
5003
5004 baseui = repo and repo.baseui or ui
5004 baseui = repo and repo.baseui or ui
5005 optlist = ("name templates style address port prefix ipv6"
5005 optlist = ("name templates style address port prefix ipv6"
5006 " accesslog errorlog certificate encoding")
5006 " accesslog errorlog certificate encoding")
5007 for o in optlist.split():
5007 for o in optlist.split():
5008 val = opts.get(o, '')
5008 val = opts.get(o, '')
5009 if val in (None, ''): # should check against default options instead
5009 if val in (None, ''): # should check against default options instead
5010 continue
5010 continue
5011 baseui.setconfig("web", o, val)
5011 baseui.setconfig("web", o, val)
5012 if repo and repo.ui != baseui:
5012 if repo and repo.ui != baseui:
5013 repo.ui.setconfig("web", o, val)
5013 repo.ui.setconfig("web", o, val)
5014
5014
5015 o = opts.get('web_conf') or opts.get('webdir_conf')
5015 o = opts.get('web_conf') or opts.get('webdir_conf')
5016 if not o:
5016 if not o:
5017 if not repo:
5017 if not repo:
5018 raise error.RepoError(_("There is no Mercurial repository"
5018 raise error.RepoError(_("There is no Mercurial repository"
5019 " here (.hg not found)"))
5019 " here (.hg not found)"))
5020 o = repo.root
5020 o = repo.root
5021
5021
5022 app = hgweb.hgweb(o, baseui=ui)
5022 app = hgweb.hgweb(o, baseui=ui)
5023
5023
5024 class service(object):
5024 class service(object):
5025 def init(self):
5025 def init(self):
5026 util.setsignalhandler()
5026 util.setsignalhandler()
5027 self.httpd = hgweb.server.create_server(ui, app)
5027 self.httpd = hgweb.server.create_server(ui, app)
5028
5028
5029 if opts['port'] and not ui.verbose:
5029 if opts['port'] and not ui.verbose:
5030 return
5030 return
5031
5031
5032 if self.httpd.prefix:
5032 if self.httpd.prefix:
5033 prefix = self.httpd.prefix.strip('/') + '/'
5033 prefix = self.httpd.prefix.strip('/') + '/'
5034 else:
5034 else:
5035 prefix = ''
5035 prefix = ''
5036
5036
5037 port = ':%d' % self.httpd.port
5037 port = ':%d' % self.httpd.port
5038 if port == ':80':
5038 if port == ':80':
5039 port = ''
5039 port = ''
5040
5040
5041 bindaddr = self.httpd.addr
5041 bindaddr = self.httpd.addr
5042 if bindaddr == '0.0.0.0':
5042 if bindaddr == '0.0.0.0':
5043 bindaddr = '*'
5043 bindaddr = '*'
5044 elif ':' in bindaddr: # IPv6
5044 elif ':' in bindaddr: # IPv6
5045 bindaddr = '[%s]' % bindaddr
5045 bindaddr = '[%s]' % bindaddr
5046
5046
5047 fqaddr = self.httpd.fqaddr
5047 fqaddr = self.httpd.fqaddr
5048 if ':' in fqaddr:
5048 if ':' in fqaddr:
5049 fqaddr = '[%s]' % fqaddr
5049 fqaddr = '[%s]' % fqaddr
5050 if opts['port']:
5050 if opts['port']:
5051 write = ui.status
5051 write = ui.status
5052 else:
5052 else:
5053 write = ui.write
5053 write = ui.write
5054 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5054 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5055 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5055 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5056
5056
5057 def run(self):
5057 def run(self):
5058 self.httpd.serve_forever()
5058 self.httpd.serve_forever()
5059
5059
5060 service = service()
5060 service = service()
5061
5061
5062 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5062 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5063
5063
5064 @command('showconfig|debugconfig',
5064 @command('showconfig|debugconfig',
5065 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5065 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5066 _('[-u] [NAME]...'))
5066 _('[-u] [NAME]...'))
5067 def showconfig(ui, repo, *values, **opts):
5067 def showconfig(ui, repo, *values, **opts):
5068 """show combined config settings from all hgrc files
5068 """show combined config settings from all hgrc files
5069
5069
5070 With no arguments, print names and values of all config items.
5070 With no arguments, print names and values of all config items.
5071
5071
5072 With one argument of the form section.name, print just the value
5072 With one argument of the form section.name, print just the value
5073 of that config item.
5073 of that config item.
5074
5074
5075 With multiple arguments, print names and values of all config
5075 With multiple arguments, print names and values of all config
5076 items with matching section names.
5076 items with matching section names.
5077
5077
5078 With --debug, the source (filename and line number) is printed
5078 With --debug, the source (filename and line number) is printed
5079 for each config item.
5079 for each config item.
5080
5080
5081 Returns 0 on success.
5081 Returns 0 on success.
5082 """
5082 """
5083
5083
5084 for f in scmutil.rcpath():
5084 for f in scmutil.rcpath():
5085 ui.debug('read config from: %s\n' % f)
5085 ui.debug('read config from: %s\n' % f)
5086 untrusted = bool(opts.get('untrusted'))
5086 untrusted = bool(opts.get('untrusted'))
5087 if values:
5087 if values:
5088 sections = [v for v in values if '.' not in v]
5088 sections = [v for v in values if '.' not in v]
5089 items = [v for v in values if '.' in v]
5089 items = [v for v in values if '.' in v]
5090 if len(items) > 1 or items and sections:
5090 if len(items) > 1 or items and sections:
5091 raise util.Abort(_('only one config item permitted'))
5091 raise util.Abort(_('only one config item permitted'))
5092 for section, name, value in ui.walkconfig(untrusted=untrusted):
5092 for section, name, value in ui.walkconfig(untrusted=untrusted):
5093 value = str(value).replace('\n', '\\n')
5093 value = str(value).replace('\n', '\\n')
5094 sectname = section + '.' + name
5094 sectname = section + '.' + name
5095 if values:
5095 if values:
5096 for v in values:
5096 for v in values:
5097 if v == section:
5097 if v == section:
5098 ui.debug('%s: ' %
5098 ui.debug('%s: ' %
5099 ui.configsource(section, name, untrusted))
5099 ui.configsource(section, name, untrusted))
5100 ui.write('%s=%s\n' % (sectname, value))
5100 ui.write('%s=%s\n' % (sectname, value))
5101 elif v == sectname:
5101 elif v == sectname:
5102 ui.debug('%s: ' %
5102 ui.debug('%s: ' %
5103 ui.configsource(section, name, untrusted))
5103 ui.configsource(section, name, untrusted))
5104 ui.write(value, '\n')
5104 ui.write(value, '\n')
5105 else:
5105 else:
5106 ui.debug('%s: ' %
5106 ui.debug('%s: ' %
5107 ui.configsource(section, name, untrusted))
5107 ui.configsource(section, name, untrusted))
5108 ui.write('%s=%s\n' % (sectname, value))
5108 ui.write('%s=%s\n' % (sectname, value))
5109
5109
5110 @command('^status|st',
5110 @command('^status|st',
5111 [('A', 'all', None, _('show status of all files')),
5111 [('A', 'all', None, _('show status of all files')),
5112 ('m', 'modified', None, _('show only modified files')),
5112 ('m', 'modified', None, _('show only modified files')),
5113 ('a', 'added', None, _('show only added files')),
5113 ('a', 'added', None, _('show only added files')),
5114 ('r', 'removed', None, _('show only removed files')),
5114 ('r', 'removed', None, _('show only removed files')),
5115 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5115 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5116 ('c', 'clean', None, _('show only files without changes')),
5116 ('c', 'clean', None, _('show only files without changes')),
5117 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5117 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5118 ('i', 'ignored', None, _('show only ignored files')),
5118 ('i', 'ignored', None, _('show only ignored files')),
5119 ('n', 'no-status', None, _('hide status prefix')),
5119 ('n', 'no-status', None, _('hide status prefix')),
5120 ('C', 'copies', None, _('show source of copied files')),
5120 ('C', 'copies', None, _('show source of copied files')),
5121 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5121 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5122 ('', 'rev', [], _('show difference from revision'), _('REV')),
5122 ('', 'rev', [], _('show difference from revision'), _('REV')),
5123 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5123 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5124 ] + walkopts + subrepoopts,
5124 ] + walkopts + subrepoopts,
5125 _('[OPTION]... [FILE]...'))
5125 _('[OPTION]... [FILE]...'))
5126 def status(ui, repo, *pats, **opts):
5126 def status(ui, repo, *pats, **opts):
5127 """show changed files in the working directory
5127 """show changed files in the working directory
5128
5128
5129 Show status of files in the repository. If names are given, only
5129 Show status of files in the repository. If names are given, only
5130 files that match are shown. Files that are clean or ignored or
5130 files that match are shown. Files that are clean or ignored or
5131 the source of a copy/move operation, are not listed unless
5131 the source of a copy/move operation, are not listed unless
5132 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5132 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5133 Unless options described with "show only ..." are given, the
5133 Unless options described with "show only ..." are given, the
5134 options -mardu are used.
5134 options -mardu are used.
5135
5135
5136 Option -q/--quiet hides untracked (unknown and ignored) files
5136 Option -q/--quiet hides untracked (unknown and ignored) files
5137 unless explicitly requested with -u/--unknown or -i/--ignored.
5137 unless explicitly requested with -u/--unknown or -i/--ignored.
5138
5138
5139 .. note::
5139 .. note::
5140 status may appear to disagree with diff if permissions have
5140 status may appear to disagree with diff if permissions have
5141 changed or a merge has occurred. The standard diff format does
5141 changed or a merge has occurred. The standard diff format does
5142 not report permission changes and diff only reports changes
5142 not report permission changes and diff only reports changes
5143 relative to one merge parent.
5143 relative to one merge parent.
5144
5144
5145 If one revision is given, it is used as the base revision.
5145 If one revision is given, it is used as the base revision.
5146 If two revisions are given, the differences between them are
5146 If two revisions are given, the differences between them are
5147 shown. The --change option can also be used as a shortcut to list
5147 shown. The --change option can also be used as a shortcut to list
5148 the changed files of a revision from its first parent.
5148 the changed files of a revision from its first parent.
5149
5149
5150 The codes used to show the status of files are::
5150 The codes used to show the status of files are::
5151
5151
5152 M = modified
5152 M = modified
5153 A = added
5153 A = added
5154 R = removed
5154 R = removed
5155 C = clean
5155 C = clean
5156 ! = missing (deleted by non-hg command, but still tracked)
5156 ! = missing (deleted by non-hg command, but still tracked)
5157 ? = not tracked
5157 ? = not tracked
5158 I = ignored
5158 I = ignored
5159 = origin of the previous file listed as A (added)
5159 = origin of the previous file listed as A (added)
5160
5160
5161 .. container:: verbose
5161 .. container:: verbose
5162
5162
5163 Examples:
5163 Examples:
5164
5164
5165 - show changes in the working directory relative to a
5165 - show changes in the working directory relative to a
5166 changeset::
5166 changeset::
5167
5167
5168 hg status --rev 9353
5168 hg status --rev 9353
5169
5169
5170 - show all changes including copies in an existing changeset::
5170 - show all changes including copies in an existing changeset::
5171
5171
5172 hg status --copies --change 9353
5172 hg status --copies --change 9353
5173
5173
5174 - get a NUL separated list of added files, suitable for xargs::
5174 - get a NUL separated list of added files, suitable for xargs::
5175
5175
5176 hg status -an0
5176 hg status -an0
5177
5177
5178 Returns 0 on success.
5178 Returns 0 on success.
5179 """
5179 """
5180
5180
5181 revs = opts.get('rev')
5181 revs = opts.get('rev')
5182 change = opts.get('change')
5182 change = opts.get('change')
5183
5183
5184 if revs and change:
5184 if revs and change:
5185 msg = _('cannot specify --rev and --change at the same time')
5185 msg = _('cannot specify --rev and --change at the same time')
5186 raise util.Abort(msg)
5186 raise util.Abort(msg)
5187 elif change:
5187 elif change:
5188 node2 = scmutil.revsingle(repo, change, None).node()
5188 node2 = scmutil.revsingle(repo, change, None).node()
5189 node1 = repo[node2].p1().node()
5189 node1 = repo[node2].p1().node()
5190 else:
5190 else:
5191 node1, node2 = scmutil.revpair(repo, revs)
5191 node1, node2 = scmutil.revpair(repo, revs)
5192
5192
5193 cwd = (pats and repo.getcwd()) or ''
5193 cwd = (pats and repo.getcwd()) or ''
5194 end = opts.get('print0') and '\0' or '\n'
5194 end = opts.get('print0') and '\0' or '\n'
5195 copy = {}
5195 copy = {}
5196 states = 'modified added removed deleted unknown ignored clean'.split()
5196 states = 'modified added removed deleted unknown ignored clean'.split()
5197 show = [k for k in states if opts.get(k)]
5197 show = [k for k in states if opts.get(k)]
5198 if opts.get('all'):
5198 if opts.get('all'):
5199 show += ui.quiet and (states[:4] + ['clean']) or states
5199 show += ui.quiet and (states[:4] + ['clean']) or states
5200 if not show:
5200 if not show:
5201 show = ui.quiet and states[:4] or states[:5]
5201 show = ui.quiet and states[:4] or states[:5]
5202
5202
5203 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5203 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5204 'ignored' in show, 'clean' in show, 'unknown' in show,
5204 'ignored' in show, 'clean' in show, 'unknown' in show,
5205 opts.get('subrepos'))
5205 opts.get('subrepos'))
5206 changestates = zip(states, 'MAR!?IC', stat)
5206 changestates = zip(states, 'MAR!?IC', stat)
5207
5207
5208 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5208 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5209 ctx1 = repo[node1]
5209 copy = copies.pathcopies(repo[node1], repo[node2])
5210 ctx2 = repo[node2]
5211 added = stat[1]
5212 if node2 is None:
5213 added = stat[0] + stat[1] # merged?
5214
5215 for k, v in copies.pathcopies(ctx1, ctx2).iteritems():
5216 if k in added:
5217 copy[k] = v
5218 elif v in added:
5219 copy[v] = k
5220
5210
5221 for state, char, files in changestates:
5211 for state, char, files in changestates:
5222 if state in show:
5212 if state in show:
5223 format = "%s %%s%s" % (char, end)
5213 format = "%s %%s%s" % (char, end)
5224 if opts.get('no_status'):
5214 if opts.get('no_status'):
5225 format = "%%s%s" % end
5215 format = "%%s%s" % end
5226
5216
5227 for f in files:
5217 for f in files:
5228 ui.write(format % repo.pathto(f, cwd),
5218 ui.write(format % repo.pathto(f, cwd),
5229 label='status.' + state)
5219 label='status.' + state)
5230 if f in copy:
5220 if f in copy:
5231 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
5221 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
5232 label='status.copied')
5222 label='status.copied')
5233
5223
5234 @command('^summary|sum',
5224 @command('^summary|sum',
5235 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5225 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5236 def summary(ui, repo, **opts):
5226 def summary(ui, repo, **opts):
5237 """summarize working directory state
5227 """summarize working directory state
5238
5228
5239 This generates a brief summary of the working directory state,
5229 This generates a brief summary of the working directory state,
5240 including parents, branch, commit status, and available updates.
5230 including parents, branch, commit status, and available updates.
5241
5231
5242 With the --remote option, this will check the default paths for
5232 With the --remote option, this will check the default paths for
5243 incoming and outgoing changes. This can be time-consuming.
5233 incoming and outgoing changes. This can be time-consuming.
5244
5234
5245 Returns 0 on success.
5235 Returns 0 on success.
5246 """
5236 """
5247
5237
5248 ctx = repo[None]
5238 ctx = repo[None]
5249 parents = ctx.parents()
5239 parents = ctx.parents()
5250 pnode = parents[0].node()
5240 pnode = parents[0].node()
5251 marks = []
5241 marks = []
5252
5242
5253 for p in parents:
5243 for p in parents:
5254 # label with log.changeset (instead of log.parent) since this
5244 # label with log.changeset (instead of log.parent) since this
5255 # shows a working directory parent *changeset*:
5245 # shows a working directory parent *changeset*:
5256 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5246 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5257 label='log.changeset')
5247 label='log.changeset')
5258 ui.write(' '.join(p.tags()), label='log.tag')
5248 ui.write(' '.join(p.tags()), label='log.tag')
5259 if p.bookmarks():
5249 if p.bookmarks():
5260 marks.extend(p.bookmarks())
5250 marks.extend(p.bookmarks())
5261 if p.rev() == -1:
5251 if p.rev() == -1:
5262 if not len(repo):
5252 if not len(repo):
5263 ui.write(_(' (empty repository)'))
5253 ui.write(_(' (empty repository)'))
5264 else:
5254 else:
5265 ui.write(_(' (no revision checked out)'))
5255 ui.write(_(' (no revision checked out)'))
5266 ui.write('\n')
5256 ui.write('\n')
5267 if p.description():
5257 if p.description():
5268 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5258 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5269 label='log.summary')
5259 label='log.summary')
5270
5260
5271 branch = ctx.branch()
5261 branch = ctx.branch()
5272 bheads = repo.branchheads(branch)
5262 bheads = repo.branchheads(branch)
5273 m = _('branch: %s\n') % branch
5263 m = _('branch: %s\n') % branch
5274 if branch != 'default':
5264 if branch != 'default':
5275 ui.write(m, label='log.branch')
5265 ui.write(m, label='log.branch')
5276 else:
5266 else:
5277 ui.status(m, label='log.branch')
5267 ui.status(m, label='log.branch')
5278
5268
5279 if marks:
5269 if marks:
5280 current = repo._bookmarkcurrent
5270 current = repo._bookmarkcurrent
5281 ui.write(_('bookmarks:'), label='log.bookmark')
5271 ui.write(_('bookmarks:'), label='log.bookmark')
5282 if current is not None:
5272 if current is not None:
5283 try:
5273 try:
5284 marks.remove(current)
5274 marks.remove(current)
5285 ui.write(' *' + current, label='bookmarks.current')
5275 ui.write(' *' + current, label='bookmarks.current')
5286 except ValueError:
5276 except ValueError:
5287 # current bookmark not in parent ctx marks
5277 # current bookmark not in parent ctx marks
5288 pass
5278 pass
5289 for m in marks:
5279 for m in marks:
5290 ui.write(' ' + m, label='log.bookmark')
5280 ui.write(' ' + m, label='log.bookmark')
5291 ui.write('\n', label='log.bookmark')
5281 ui.write('\n', label='log.bookmark')
5292
5282
5293 st = list(repo.status(unknown=True))[:6]
5283 st = list(repo.status(unknown=True))[:6]
5294
5284
5295 c = repo.dirstate.copies()
5285 c = repo.dirstate.copies()
5296 copied, renamed = [], []
5286 copied, renamed = [], []
5297 for d, s in c.iteritems():
5287 for d, s in c.iteritems():
5298 if s in st[2]:
5288 if s in st[2]:
5299 st[2].remove(s)
5289 st[2].remove(s)
5300 renamed.append(d)
5290 renamed.append(d)
5301 else:
5291 else:
5302 copied.append(d)
5292 copied.append(d)
5303 if d in st[1]:
5293 if d in st[1]:
5304 st[1].remove(d)
5294 st[1].remove(d)
5305 st.insert(3, renamed)
5295 st.insert(3, renamed)
5306 st.insert(4, copied)
5296 st.insert(4, copied)
5307
5297
5308 ms = mergemod.mergestate(repo)
5298 ms = mergemod.mergestate(repo)
5309 st.append([f for f in ms if ms[f] == 'u'])
5299 st.append([f for f in ms if ms[f] == 'u'])
5310
5300
5311 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5301 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5312 st.append(subs)
5302 st.append(subs)
5313
5303
5314 labels = [ui.label(_('%d modified'), 'status.modified'),
5304 labels = [ui.label(_('%d modified'), 'status.modified'),
5315 ui.label(_('%d added'), 'status.added'),
5305 ui.label(_('%d added'), 'status.added'),
5316 ui.label(_('%d removed'), 'status.removed'),
5306 ui.label(_('%d removed'), 'status.removed'),
5317 ui.label(_('%d renamed'), 'status.copied'),
5307 ui.label(_('%d renamed'), 'status.copied'),
5318 ui.label(_('%d copied'), 'status.copied'),
5308 ui.label(_('%d copied'), 'status.copied'),
5319 ui.label(_('%d deleted'), 'status.deleted'),
5309 ui.label(_('%d deleted'), 'status.deleted'),
5320 ui.label(_('%d unknown'), 'status.unknown'),
5310 ui.label(_('%d unknown'), 'status.unknown'),
5321 ui.label(_('%d ignored'), 'status.ignored'),
5311 ui.label(_('%d ignored'), 'status.ignored'),
5322 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5312 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5323 ui.label(_('%d subrepos'), 'status.modified')]
5313 ui.label(_('%d subrepos'), 'status.modified')]
5324 t = []
5314 t = []
5325 for s, l in zip(st, labels):
5315 for s, l in zip(st, labels):
5326 if s:
5316 if s:
5327 t.append(l % len(s))
5317 t.append(l % len(s))
5328
5318
5329 t = ', '.join(t)
5319 t = ', '.join(t)
5330 cleanworkdir = False
5320 cleanworkdir = False
5331
5321
5332 if len(parents) > 1:
5322 if len(parents) > 1:
5333 t += _(' (merge)')
5323 t += _(' (merge)')
5334 elif branch != parents[0].branch():
5324 elif branch != parents[0].branch():
5335 t += _(' (new branch)')
5325 t += _(' (new branch)')
5336 elif (parents[0].extra().get('close') and
5326 elif (parents[0].extra().get('close') and
5337 pnode in repo.branchheads(branch, closed=True)):
5327 pnode in repo.branchheads(branch, closed=True)):
5338 t += _(' (head closed)')
5328 t += _(' (head closed)')
5339 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5329 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5340 t += _(' (clean)')
5330 t += _(' (clean)')
5341 cleanworkdir = True
5331 cleanworkdir = True
5342 elif pnode not in bheads:
5332 elif pnode not in bheads:
5343 t += _(' (new branch head)')
5333 t += _(' (new branch head)')
5344
5334
5345 if cleanworkdir:
5335 if cleanworkdir:
5346 ui.status(_('commit: %s\n') % t.strip())
5336 ui.status(_('commit: %s\n') % t.strip())
5347 else:
5337 else:
5348 ui.write(_('commit: %s\n') % t.strip())
5338 ui.write(_('commit: %s\n') % t.strip())
5349
5339
5350 # all ancestors of branch heads - all ancestors of parent = new csets
5340 # all ancestors of branch heads - all ancestors of parent = new csets
5351 new = [0] * len(repo)
5341 new = [0] * len(repo)
5352 cl = repo.changelog
5342 cl = repo.changelog
5353 for a in [cl.rev(n) for n in bheads]:
5343 for a in [cl.rev(n) for n in bheads]:
5354 new[a] = 1
5344 new[a] = 1
5355 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
5345 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
5356 new[a] = 1
5346 new[a] = 1
5357 for a in [p.rev() for p in parents]:
5347 for a in [p.rev() for p in parents]:
5358 if a >= 0:
5348 if a >= 0:
5359 new[a] = 0
5349 new[a] = 0
5360 for a in cl.ancestors(*[p.rev() for p in parents]):
5350 for a in cl.ancestors(*[p.rev() for p in parents]):
5361 new[a] = 0
5351 new[a] = 0
5362 new = sum(new)
5352 new = sum(new)
5363
5353
5364 if new == 0:
5354 if new == 0:
5365 ui.status(_('update: (current)\n'))
5355 ui.status(_('update: (current)\n'))
5366 elif pnode not in bheads:
5356 elif pnode not in bheads:
5367 ui.write(_('update: %d new changesets (update)\n') % new)
5357 ui.write(_('update: %d new changesets (update)\n') % new)
5368 else:
5358 else:
5369 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5359 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5370 (new, len(bheads)))
5360 (new, len(bheads)))
5371
5361
5372 if opts.get('remote'):
5362 if opts.get('remote'):
5373 t = []
5363 t = []
5374 source, branches = hg.parseurl(ui.expandpath('default'))
5364 source, branches = hg.parseurl(ui.expandpath('default'))
5375 other = hg.peer(repo, {}, source)
5365 other = hg.peer(repo, {}, source)
5376 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
5366 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
5377 ui.debug('comparing with %s\n' % util.hidepassword(source))
5367 ui.debug('comparing with %s\n' % util.hidepassword(source))
5378 repo.ui.pushbuffer()
5368 repo.ui.pushbuffer()
5379 commoninc = discovery.findcommonincoming(repo, other)
5369 commoninc = discovery.findcommonincoming(repo, other)
5380 _common, incoming, _rheads = commoninc
5370 _common, incoming, _rheads = commoninc
5381 repo.ui.popbuffer()
5371 repo.ui.popbuffer()
5382 if incoming:
5372 if incoming:
5383 t.append(_('1 or more incoming'))
5373 t.append(_('1 or more incoming'))
5384
5374
5385 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5375 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5386 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5376 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5387 if source != dest:
5377 if source != dest:
5388 other = hg.peer(repo, {}, dest)
5378 other = hg.peer(repo, {}, dest)
5389 commoninc = None
5379 commoninc = None
5390 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5380 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5391 repo.ui.pushbuffer()
5381 repo.ui.pushbuffer()
5392 common, outheads = discovery.findcommonoutgoing(repo, other,
5382 common, outheads = discovery.findcommonoutgoing(repo, other,
5393 commoninc=commoninc)
5383 commoninc=commoninc)
5394 repo.ui.popbuffer()
5384 repo.ui.popbuffer()
5395 o = repo.changelog.findmissing(common=common, heads=outheads)
5385 o = repo.changelog.findmissing(common=common, heads=outheads)
5396 if o:
5386 if o:
5397 t.append(_('%d outgoing') % len(o))
5387 t.append(_('%d outgoing') % len(o))
5398 if 'bookmarks' in other.listkeys('namespaces'):
5388 if 'bookmarks' in other.listkeys('namespaces'):
5399 lmarks = repo.listkeys('bookmarks')
5389 lmarks = repo.listkeys('bookmarks')
5400 rmarks = other.listkeys('bookmarks')
5390 rmarks = other.listkeys('bookmarks')
5401 diff = set(rmarks) - set(lmarks)
5391 diff = set(rmarks) - set(lmarks)
5402 if len(diff) > 0:
5392 if len(diff) > 0:
5403 t.append(_('%d incoming bookmarks') % len(diff))
5393 t.append(_('%d incoming bookmarks') % len(diff))
5404 diff = set(lmarks) - set(rmarks)
5394 diff = set(lmarks) - set(rmarks)
5405 if len(diff) > 0:
5395 if len(diff) > 0:
5406 t.append(_('%d outgoing bookmarks') % len(diff))
5396 t.append(_('%d outgoing bookmarks') % len(diff))
5407
5397
5408 if t:
5398 if t:
5409 ui.write(_('remote: %s\n') % (', '.join(t)))
5399 ui.write(_('remote: %s\n') % (', '.join(t)))
5410 else:
5400 else:
5411 ui.status(_('remote: (synced)\n'))
5401 ui.status(_('remote: (synced)\n'))
5412
5402
5413 @command('tag',
5403 @command('tag',
5414 [('f', 'force', None, _('force tag')),
5404 [('f', 'force', None, _('force tag')),
5415 ('l', 'local', None, _('make the tag local')),
5405 ('l', 'local', None, _('make the tag local')),
5416 ('r', 'rev', '', _('revision to tag'), _('REV')),
5406 ('r', 'rev', '', _('revision to tag'), _('REV')),
5417 ('', 'remove', None, _('remove a tag')),
5407 ('', 'remove', None, _('remove a tag')),
5418 # -l/--local is already there, commitopts cannot be used
5408 # -l/--local is already there, commitopts cannot be used
5419 ('e', 'edit', None, _('edit commit message')),
5409 ('e', 'edit', None, _('edit commit message')),
5420 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5410 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5421 ] + commitopts2,
5411 ] + commitopts2,
5422 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5412 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5423 def tag(ui, repo, name1, *names, **opts):
5413 def tag(ui, repo, name1, *names, **opts):
5424 """add one or more tags for the current or given revision
5414 """add one or more tags for the current or given revision
5425
5415
5426 Name a particular revision using <name>.
5416 Name a particular revision using <name>.
5427
5417
5428 Tags are used to name particular revisions of the repository and are
5418 Tags are used to name particular revisions of the repository and are
5429 very useful to compare different revisions, to go back to significant
5419 very useful to compare different revisions, to go back to significant
5430 earlier versions or to mark branch points as releases, etc. Changing
5420 earlier versions or to mark branch points as releases, etc. Changing
5431 an existing tag is normally disallowed; use -f/--force to override.
5421 an existing tag is normally disallowed; use -f/--force to override.
5432
5422
5433 If no revision is given, the parent of the working directory is
5423 If no revision is given, the parent of the working directory is
5434 used, or tip if no revision is checked out.
5424 used, or tip if no revision is checked out.
5435
5425
5436 To facilitate version control, distribution, and merging of tags,
5426 To facilitate version control, distribution, and merging of tags,
5437 they are stored as a file named ".hgtags" which is managed similarly
5427 they are stored as a file named ".hgtags" which is managed similarly
5438 to other project files and can be hand-edited if necessary. This
5428 to other project files and can be hand-edited if necessary. This
5439 also means that tagging creates a new commit. The file
5429 also means that tagging creates a new commit. The file
5440 ".hg/localtags" is used for local tags (not shared among
5430 ".hg/localtags" is used for local tags (not shared among
5441 repositories).
5431 repositories).
5442
5432
5443 Tag commits are usually made at the head of a branch. If the parent
5433 Tag commits are usually made at the head of a branch. If the parent
5444 of the working directory is not a branch head, :hg:`tag` aborts; use
5434 of the working directory is not a branch head, :hg:`tag` aborts; use
5445 -f/--force to force the tag commit to be based on a non-head
5435 -f/--force to force the tag commit to be based on a non-head
5446 changeset.
5436 changeset.
5447
5437
5448 See :hg:`help dates` for a list of formats valid for -d/--date.
5438 See :hg:`help dates` for a list of formats valid for -d/--date.
5449
5439
5450 Since tag names have priority over branch names during revision
5440 Since tag names have priority over branch names during revision
5451 lookup, using an existing branch name as a tag name is discouraged.
5441 lookup, using an existing branch name as a tag name is discouraged.
5452
5442
5453 Returns 0 on success.
5443 Returns 0 on success.
5454 """
5444 """
5455
5445
5456 rev_ = "."
5446 rev_ = "."
5457 names = [t.strip() for t in (name1,) + names]
5447 names = [t.strip() for t in (name1,) + names]
5458 if len(names) != len(set(names)):
5448 if len(names) != len(set(names)):
5459 raise util.Abort(_('tag names must be unique'))
5449 raise util.Abort(_('tag names must be unique'))
5460 for n in names:
5450 for n in names:
5461 if n in ['tip', '.', 'null']:
5451 if n in ['tip', '.', 'null']:
5462 raise util.Abort(_("the name '%s' is reserved") % n)
5452 raise util.Abort(_("the name '%s' is reserved") % n)
5463 if not n:
5453 if not n:
5464 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
5454 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
5465 if opts.get('rev') and opts.get('remove'):
5455 if opts.get('rev') and opts.get('remove'):
5466 raise util.Abort(_("--rev and --remove are incompatible"))
5456 raise util.Abort(_("--rev and --remove are incompatible"))
5467 if opts.get('rev'):
5457 if opts.get('rev'):
5468 rev_ = opts['rev']
5458 rev_ = opts['rev']
5469 message = opts.get('message')
5459 message = opts.get('message')
5470 if opts.get('remove'):
5460 if opts.get('remove'):
5471 expectedtype = opts.get('local') and 'local' or 'global'
5461 expectedtype = opts.get('local') and 'local' or 'global'
5472 for n in names:
5462 for n in names:
5473 if not repo.tagtype(n):
5463 if not repo.tagtype(n):
5474 raise util.Abort(_("tag '%s' does not exist") % n)
5464 raise util.Abort(_("tag '%s' does not exist") % n)
5475 if repo.tagtype(n) != expectedtype:
5465 if repo.tagtype(n) != expectedtype:
5476 if expectedtype == 'global':
5466 if expectedtype == 'global':
5477 raise util.Abort(_("tag '%s' is not a global tag") % n)
5467 raise util.Abort(_("tag '%s' is not a global tag") % n)
5478 else:
5468 else:
5479 raise util.Abort(_("tag '%s' is not a local tag") % n)
5469 raise util.Abort(_("tag '%s' is not a local tag") % n)
5480 rev_ = nullid
5470 rev_ = nullid
5481 if not message:
5471 if not message:
5482 # we don't translate commit messages
5472 # we don't translate commit messages
5483 message = 'Removed tag %s' % ', '.join(names)
5473 message = 'Removed tag %s' % ', '.join(names)
5484 elif not opts.get('force'):
5474 elif not opts.get('force'):
5485 for n in names:
5475 for n in names:
5486 if n in repo.tags():
5476 if n in repo.tags():
5487 raise util.Abort(_("tag '%s' already exists "
5477 raise util.Abort(_("tag '%s' already exists "
5488 "(use -f to force)") % n)
5478 "(use -f to force)") % n)
5489 if not opts.get('local'):
5479 if not opts.get('local'):
5490 p1, p2 = repo.dirstate.parents()
5480 p1, p2 = repo.dirstate.parents()
5491 if p2 != nullid:
5481 if p2 != nullid:
5492 raise util.Abort(_('uncommitted merge'))
5482 raise util.Abort(_('uncommitted merge'))
5493 bheads = repo.branchheads()
5483 bheads = repo.branchheads()
5494 if not opts.get('force') and bheads and p1 not in bheads:
5484 if not opts.get('force') and bheads and p1 not in bheads:
5495 raise util.Abort(_('not at a branch head (use -f to force)'))
5485 raise util.Abort(_('not at a branch head (use -f to force)'))
5496 r = scmutil.revsingle(repo, rev_).node()
5486 r = scmutil.revsingle(repo, rev_).node()
5497
5487
5498 if not message:
5488 if not message:
5499 # we don't translate commit messages
5489 # we don't translate commit messages
5500 message = ('Added tag %s for changeset %s' %
5490 message = ('Added tag %s for changeset %s' %
5501 (', '.join(names), short(r)))
5491 (', '.join(names), short(r)))
5502
5492
5503 date = opts.get('date')
5493 date = opts.get('date')
5504 if date:
5494 if date:
5505 date = util.parsedate(date)
5495 date = util.parsedate(date)
5506
5496
5507 if opts.get('edit'):
5497 if opts.get('edit'):
5508 message = ui.edit(message, ui.username())
5498 message = ui.edit(message, ui.username())
5509
5499
5510 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5500 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5511
5501
5512 @command('tags', [], '')
5502 @command('tags', [], '')
5513 def tags(ui, repo):
5503 def tags(ui, repo):
5514 """list repository tags
5504 """list repository tags
5515
5505
5516 This lists both regular and local tags. When the -v/--verbose
5506 This lists both regular and local tags. When the -v/--verbose
5517 switch is used, a third column "local" is printed for local tags.
5507 switch is used, a third column "local" is printed for local tags.
5518
5508
5519 Returns 0 on success.
5509 Returns 0 on success.
5520 """
5510 """
5521
5511
5522 hexfunc = ui.debugflag and hex or short
5512 hexfunc = ui.debugflag and hex or short
5523 tagtype = ""
5513 tagtype = ""
5524
5514
5525 for t, n in reversed(repo.tagslist()):
5515 for t, n in reversed(repo.tagslist()):
5526 if ui.quiet:
5516 if ui.quiet:
5527 ui.write("%s\n" % t, label='tags.normal')
5517 ui.write("%s\n" % t, label='tags.normal')
5528 continue
5518 continue
5529
5519
5530 hn = hexfunc(n)
5520 hn = hexfunc(n)
5531 r = "%5d:%s" % (repo.changelog.rev(n), hn)
5521 r = "%5d:%s" % (repo.changelog.rev(n), hn)
5532 rev = ui.label(r, 'log.changeset')
5522 rev = ui.label(r, 'log.changeset')
5533 spaces = " " * (30 - encoding.colwidth(t))
5523 spaces = " " * (30 - encoding.colwidth(t))
5534
5524
5535 tag = ui.label(t, 'tags.normal')
5525 tag = ui.label(t, 'tags.normal')
5536 if ui.verbose:
5526 if ui.verbose:
5537 if repo.tagtype(t) == 'local':
5527 if repo.tagtype(t) == 'local':
5538 tagtype = " local"
5528 tagtype = " local"
5539 tag = ui.label(t, 'tags.local')
5529 tag = ui.label(t, 'tags.local')
5540 else:
5530 else:
5541 tagtype = ""
5531 tagtype = ""
5542 ui.write("%s%s %s%s\n" % (tag, spaces, rev, tagtype))
5532 ui.write("%s%s %s%s\n" % (tag, spaces, rev, tagtype))
5543
5533
5544 @command('tip',
5534 @command('tip',
5545 [('p', 'patch', None, _('show patch')),
5535 [('p', 'patch', None, _('show patch')),
5546 ('g', 'git', None, _('use git extended diff format')),
5536 ('g', 'git', None, _('use git extended diff format')),
5547 ] + templateopts,
5537 ] + templateopts,
5548 _('[-p] [-g]'))
5538 _('[-p] [-g]'))
5549 def tip(ui, repo, **opts):
5539 def tip(ui, repo, **opts):
5550 """show the tip revision
5540 """show the tip revision
5551
5541
5552 The tip revision (usually just called the tip) is the changeset
5542 The tip revision (usually just called the tip) is the changeset
5553 most recently added to the repository (and therefore the most
5543 most recently added to the repository (and therefore the most
5554 recently changed head).
5544 recently changed head).
5555
5545
5556 If you have just made a commit, that commit will be the tip. If
5546 If you have just made a commit, that commit will be the tip. If
5557 you have just pulled changes from another repository, the tip of
5547 you have just pulled changes from another repository, the tip of
5558 that repository becomes the current tip. The "tip" tag is special
5548 that repository becomes the current tip. The "tip" tag is special
5559 and cannot be renamed or assigned to a different changeset.
5549 and cannot be renamed or assigned to a different changeset.
5560
5550
5561 Returns 0 on success.
5551 Returns 0 on success.
5562 """
5552 """
5563 displayer = cmdutil.show_changeset(ui, repo, opts)
5553 displayer = cmdutil.show_changeset(ui, repo, opts)
5564 displayer.show(repo[len(repo) - 1])
5554 displayer.show(repo[len(repo) - 1])
5565 displayer.close()
5555 displayer.close()
5566
5556
5567 @command('unbundle',
5557 @command('unbundle',
5568 [('u', 'update', None,
5558 [('u', 'update', None,
5569 _('update to new branch head if changesets were unbundled'))],
5559 _('update to new branch head if changesets were unbundled'))],
5570 _('[-u] FILE...'))
5560 _('[-u] FILE...'))
5571 def unbundle(ui, repo, fname1, *fnames, **opts):
5561 def unbundle(ui, repo, fname1, *fnames, **opts):
5572 """apply one or more changegroup files
5562 """apply one or more changegroup files
5573
5563
5574 Apply one or more compressed changegroup files generated by the
5564 Apply one or more compressed changegroup files generated by the
5575 bundle command.
5565 bundle command.
5576
5566
5577 Returns 0 on success, 1 if an update has unresolved files.
5567 Returns 0 on success, 1 if an update has unresolved files.
5578 """
5568 """
5579 fnames = (fname1,) + fnames
5569 fnames = (fname1,) + fnames
5580
5570
5581 lock = repo.lock()
5571 lock = repo.lock()
5582 wc = repo['.']
5572 wc = repo['.']
5583 try:
5573 try:
5584 for fname in fnames:
5574 for fname in fnames:
5585 f = url.open(ui, fname)
5575 f = url.open(ui, fname)
5586 gen = changegroup.readbundle(f, fname)
5576 gen = changegroup.readbundle(f, fname)
5587 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
5577 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
5588 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5578 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5589 finally:
5579 finally:
5590 lock.release()
5580 lock.release()
5591 return postincoming(ui, repo, modheads, opts.get('update'), None)
5581 return postincoming(ui, repo, modheads, opts.get('update'), None)
5592
5582
5593 @command('^update|up|checkout|co',
5583 @command('^update|up|checkout|co',
5594 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5584 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5595 ('c', 'check', None,
5585 ('c', 'check', None,
5596 _('update across branches if no uncommitted changes')),
5586 _('update across branches if no uncommitted changes')),
5597 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5587 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5598 ('r', 'rev', '', _('revision'), _('REV'))],
5588 ('r', 'rev', '', _('revision'), _('REV'))],
5599 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5589 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5600 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5590 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5601 """update working directory (or switch revisions)
5591 """update working directory (or switch revisions)
5602
5592
5603 Update the repository's working directory to the specified
5593 Update the repository's working directory to the specified
5604 changeset. If no changeset is specified, update to the tip of the
5594 changeset. If no changeset is specified, update to the tip of the
5605 current named branch.
5595 current named branch.
5606
5596
5607 If the changeset is not a descendant of the working directory's
5597 If the changeset is not a descendant of the working directory's
5608 parent, the update is aborted. With the -c/--check option, the
5598 parent, the update is aborted. With the -c/--check option, the
5609 working directory is checked for uncommitted changes; if none are
5599 working directory is checked for uncommitted changes; if none are
5610 found, the working directory is updated to the specified
5600 found, the working directory is updated to the specified
5611 changeset.
5601 changeset.
5612
5602
5613 Update sets the working directory's parent revison to the specified
5603 Update sets the working directory's parent revison to the specified
5614 changeset (see :hg:`help parents`).
5604 changeset (see :hg:`help parents`).
5615
5605
5616 The following rules apply when the working directory contains
5606 The following rules apply when the working directory contains
5617 uncommitted changes:
5607 uncommitted changes:
5618
5608
5619 1. If neither -c/--check nor -C/--clean is specified, and if
5609 1. If neither -c/--check nor -C/--clean is specified, and if
5620 the requested changeset is an ancestor or descendant of
5610 the requested changeset is an ancestor or descendant of
5621 the working directory's parent, the uncommitted changes
5611 the working directory's parent, the uncommitted changes
5622 are merged into the requested changeset and the merged
5612 are merged into the requested changeset and the merged
5623 result is left uncommitted. If the requested changeset is
5613 result is left uncommitted. If the requested changeset is
5624 not an ancestor or descendant (that is, it is on another
5614 not an ancestor or descendant (that is, it is on another
5625 branch), the update is aborted and the uncommitted changes
5615 branch), the update is aborted and the uncommitted changes
5626 are preserved.
5616 are preserved.
5627
5617
5628 2. With the -c/--check option, the update is aborted and the
5618 2. With the -c/--check option, the update is aborted and the
5629 uncommitted changes are preserved.
5619 uncommitted changes are preserved.
5630
5620
5631 3. With the -C/--clean option, uncommitted changes are discarded and
5621 3. With the -C/--clean option, uncommitted changes are discarded and
5632 the working directory is updated to the requested changeset.
5622 the working directory is updated to the requested changeset.
5633
5623
5634 Use null as the changeset to remove the working directory (like
5624 Use null as the changeset to remove the working directory (like
5635 :hg:`clone -U`).
5625 :hg:`clone -U`).
5636
5626
5637 If you want to revert just one file to an older revision, use
5627 If you want to revert just one file to an older revision, use
5638 :hg:`revert [-r REV] NAME`.
5628 :hg:`revert [-r REV] NAME`.
5639
5629
5640 See :hg:`help dates` for a list of formats valid for -d/--date.
5630 See :hg:`help dates` for a list of formats valid for -d/--date.
5641
5631
5642 Returns 0 on success, 1 if there are unresolved files.
5632 Returns 0 on success, 1 if there are unresolved files.
5643 """
5633 """
5644 if rev and node:
5634 if rev and node:
5645 raise util.Abort(_("please specify just one revision"))
5635 raise util.Abort(_("please specify just one revision"))
5646
5636
5647 if rev is None or rev == '':
5637 if rev is None or rev == '':
5648 rev = node
5638 rev = node
5649
5639
5650 # if we defined a bookmark, we have to remember the original bookmark name
5640 # if we defined a bookmark, we have to remember the original bookmark name
5651 brev = rev
5641 brev = rev
5652 rev = scmutil.revsingle(repo, rev, rev).rev()
5642 rev = scmutil.revsingle(repo, rev, rev).rev()
5653
5643
5654 if check and clean:
5644 if check and clean:
5655 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5645 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5656
5646
5657 if check:
5647 if check:
5658 # we could use dirty() but we can ignore merge and branch trivia
5648 # we could use dirty() but we can ignore merge and branch trivia
5659 c = repo[None]
5649 c = repo[None]
5660 if c.modified() or c.added() or c.removed():
5650 if c.modified() or c.added() or c.removed():
5661 raise util.Abort(_("uncommitted local changes"))
5651 raise util.Abort(_("uncommitted local changes"))
5662
5652
5663 if date:
5653 if date:
5664 if rev is not None:
5654 if rev is not None:
5665 raise util.Abort(_("you can't specify a revision and a date"))
5655 raise util.Abort(_("you can't specify a revision and a date"))
5666 rev = cmdutil.finddate(ui, repo, date)
5656 rev = cmdutil.finddate(ui, repo, date)
5667
5657
5668 if clean or check:
5658 if clean or check:
5669 ret = hg.clean(repo, rev)
5659 ret = hg.clean(repo, rev)
5670 else:
5660 else:
5671 ret = hg.update(repo, rev)
5661 ret = hg.update(repo, rev)
5672
5662
5673 if brev in repo._bookmarks:
5663 if brev in repo._bookmarks:
5674 bookmarks.setcurrent(repo, brev)
5664 bookmarks.setcurrent(repo, brev)
5675
5665
5676 return ret
5666 return ret
5677
5667
5678 @command('verify', [])
5668 @command('verify', [])
5679 def verify(ui, repo):
5669 def verify(ui, repo):
5680 """verify the integrity of the repository
5670 """verify the integrity of the repository
5681
5671
5682 Verify the integrity of the current repository.
5672 Verify the integrity of the current repository.
5683
5673
5684 This will perform an extensive check of the repository's
5674 This will perform an extensive check of the repository's
5685 integrity, validating the hashes and checksums of each entry in
5675 integrity, validating the hashes and checksums of each entry in
5686 the changelog, manifest, and tracked files, as well as the
5676 the changelog, manifest, and tracked files, as well as the
5687 integrity of their crosslinks and indices.
5677 integrity of their crosslinks and indices.
5688
5678
5689 Returns 0 on success, 1 if errors are encountered.
5679 Returns 0 on success, 1 if errors are encountered.
5690 """
5680 """
5691 return hg.verify(repo)
5681 return hg.verify(repo)
5692
5682
5693 @command('version', [])
5683 @command('version', [])
5694 def version_(ui):
5684 def version_(ui):
5695 """output version and copyright information"""
5685 """output version and copyright information"""
5696 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5686 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5697 % util.version())
5687 % util.version())
5698 ui.status(_(
5688 ui.status(_(
5699 "(see http://mercurial.selenic.com for more information)\n"
5689 "(see http://mercurial.selenic.com for more information)\n"
5700 "\nCopyright (C) 2005-2011 Matt Mackall and others\n"
5690 "\nCopyright (C) 2005-2011 Matt Mackall and others\n"
5701 "This is free software; see the source for copying conditions. "
5691 "This is free software; see the source for copying conditions. "
5702 "There is NO\nwarranty; "
5692 "There is NO\nwarranty; "
5703 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5693 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5704 ))
5694 ))
5705
5695
5706 norepo = ("clone init version help debugcommands debugcomplete"
5696 norepo = ("clone init version help debugcommands debugcomplete"
5707 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5697 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5708 " debugknown debuggetbundle debugbundle")
5698 " debugknown debuggetbundle debugbundle")
5709 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5699 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5710 " debugdata debugindex debugindexdot debugrevlog")
5700 " debugdata debugindex debugindexdot debugrevlog")
@@ -1,270 +1,351 b''
1 # copies.py - copy detection for Mercurial
1 # copies.py - copy detection for Mercurial
2 #
2 #
3 # Copyright 2008 Matt Mackall <mpm@selenic.com>
3 # Copyright 2008 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 import util
8 import util
9 import heapq
9 import heapq
10
10
11 def _nonoverlap(d1, d2, d3):
11 def _nonoverlap(d1, d2, d3):
12 "Return list of elements in d1 not in d2 or d3"
12 "Return list of elements in d1 not in d2 or d3"
13 return sorted([d for d in d1 if d not in d3 and d not in d2])
13 return sorted([d for d in d1 if d not in d3 and d not in d2])
14
14
15 def _dirname(f):
15 def _dirname(f):
16 s = f.rfind("/")
16 s = f.rfind("/")
17 if s == -1:
17 if s == -1:
18 return ""
18 return ""
19 return f[:s]
19 return f[:s]
20
20
21 def _dirs(files):
21 def _dirs(files):
22 d = set()
22 d = set()
23 for f in files:
23 for f in files:
24 f = _dirname(f)
24 f = _dirname(f)
25 while f not in d:
25 while f not in d:
26 d.add(f)
26 d.add(f)
27 f = _dirname(f)
27 f = _dirname(f)
28 return d
28 return d
29
29
30 def _findlimit(repo, a, b):
30 def _findlimit(repo, a, b):
31 """Find the earliest revision that's an ancestor of a or b but not both,
31 """Find the earliest revision that's an ancestor of a or b but not both,
32 None if no such revision exists.
32 None if no such revision exists.
33 """
33 """
34 # basic idea:
34 # basic idea:
35 # - mark a and b with different sides
35 # - mark a and b with different sides
36 # - if a parent's children are all on the same side, the parent is
36 # - if a parent's children are all on the same side, the parent is
37 # on that side, otherwise it is on no side
37 # on that side, otherwise it is on no side
38 # - walk the graph in topological order with the help of a heap;
38 # - walk the graph in topological order with the help of a heap;
39 # - add unseen parents to side map
39 # - add unseen parents to side map
40 # - clear side of any parent that has children on different sides
40 # - clear side of any parent that has children on different sides
41 # - track number of interesting revs that might still be on a side
41 # - track number of interesting revs that might still be on a side
42 # - track the lowest interesting rev seen
42 # - track the lowest interesting rev seen
43 # - quit when interesting revs is zero
43 # - quit when interesting revs is zero
44
44
45 cl = repo.changelog
45 cl = repo.changelog
46 working = len(cl) # pseudo rev for the working directory
46 working = len(cl) # pseudo rev for the working directory
47 if a is None:
47 if a is None:
48 a = working
48 a = working
49 if b is None:
49 if b is None:
50 b = working
50 b = working
51
51
52 side = {a: -1, b: 1}
52 side = {a: -1, b: 1}
53 visit = [-a, -b]
53 visit = [-a, -b]
54 heapq.heapify(visit)
54 heapq.heapify(visit)
55 interesting = len(visit)
55 interesting = len(visit)
56 hascommonancestor = False
56 hascommonancestor = False
57 limit = working
57 limit = working
58
58
59 while interesting:
59 while interesting:
60 r = -heapq.heappop(visit)
60 r = -heapq.heappop(visit)
61 if r == working:
61 if r == working:
62 parents = [cl.rev(p) for p in repo.dirstate.parents()]
62 parents = [cl.rev(p) for p in repo.dirstate.parents()]
63 else:
63 else:
64 parents = cl.parentrevs(r)
64 parents = cl.parentrevs(r)
65 for p in parents:
65 for p in parents:
66 if p < 0:
66 if p < 0:
67 continue
67 continue
68 if p not in side:
68 if p not in side:
69 # first time we see p; add it to visit
69 # first time we see p; add it to visit
70 side[p] = side[r]
70 side[p] = side[r]
71 if side[p]:
71 if side[p]:
72 interesting += 1
72 interesting += 1
73 heapq.heappush(visit, -p)
73 heapq.heappush(visit, -p)
74 elif side[p] and side[p] != side[r]:
74 elif side[p] and side[p] != side[r]:
75 # p was interesting but now we know better
75 # p was interesting but now we know better
76 side[p] = 0
76 side[p] = 0
77 interesting -= 1
77 interesting -= 1
78 hascommonancestor = True
78 hascommonancestor = True
79 if side[r]:
79 if side[r]:
80 limit = r # lowest rev visited
80 limit = r # lowest rev visited
81 interesting -= 1
81 interesting -= 1
82
82
83 if not hascommonancestor:
83 if not hascommonancestor:
84 return None
84 return None
85 return limit
85 return limit
86
86
87 def pathcopies(c1, c2):
87 def _chain(src, dst, a, b):
88 return mergecopies(c1._repo, c1, c2, c1._repo["null"], False)[0]
88 '''chain two sets of copies a->b'''
89 t = a.copy()
90 for k, v in b.iteritems():
91 if v in t:
92 # found a chain
93 if t[v] != k:
94 # file wasn't renamed back to itself
95 t[k] = t[v]
96 if v not in dst:
97 # chain was a rename, not a copy
98 del t[v]
99 if v in src:
100 # file is a copy of an existing file
101 t[k] = v
102 return t
103
104 def _tracefile(fctx, actx):
105 '''return file context that is the ancestor of fctx present in actx'''
106 stop = actx.rev()
107 am = actx.manifest()
108
109 for f in fctx.ancestors():
110 if am.get(f.path(), None) == f.filenode():
111 return f
112 if f.rev() < stop:
113 return None
114
115 def _dirstatecopies(d):
116 ds = d._repo.dirstate
117 c = ds.copies().copy()
118 for k in c.keys():
119 if ds[k] not in 'anm':
120 del c[k]
121 return c
122
123 def _forwardcopies(a, b):
124 '''find {dst@b: src@a} copy mapping where a is an ancestor of b'''
125
126 # check for working copy
127 w = None
128 if b.rev() is None:
129 w = b
130 b = w.p1()
131 if a == b:
132 # short-circuit to avoid issues with merge states
133 return _dirstatecopies(w)
134
135 # find where new files came from
136 # we currently don't try to find where old files went, too expensive
137 # this means we can miss a case like 'hg rm b; hg cp a b'
138 cm = {}
139 for f in b:
140 if f not in a:
141 ofctx = _tracefile(b[f], a)
142 if ofctx:
143 cm[f] = ofctx.path()
144
145 # combine copies from dirstate if necessary
146 if w is not None:
147 cm = _chain(a, w, cm, _dirstatecopies(w))
148
149 return cm
150
151 def _backwardcopies(a, b):
152 # because the forward mapping is 1:n, we can lose renames here
153 # in particular, we find renames better than copies
154 f = _forwardcopies(b, a)
155 r = {}
156 for k, v in f.iteritems():
157 r[v] = k
158 return r
159
160 def pathcopies(x, y):
161 '''find {dst@y: src@x} copy mapping for directed compare'''
162 if x == y or not x or not y:
163 return {}
164 a = y.ancestor(x)
165 if a == x:
166 return _forwardcopies(x, y)
167 if a == y:
168 return _backwardcopies(x, y)
169 return _chain(x, y, _backwardcopies(x, a), _forwardcopies(a, y))
89
170
90 def mergecopies(repo, c1, c2, ca, checkdirs=True):
171 def mergecopies(repo, c1, c2, ca, checkdirs=True):
91 """
172 """
92 Find moves and copies between context c1 and c2
173 Find moves and copies between context c1 and c2
93 """
174 """
94 # avoid silly behavior for update from empty dir
175 # avoid silly behavior for update from empty dir
95 if not c1 or not c2 or c1 == c2:
176 if not c1 or not c2 or c1 == c2:
96 return {}, {}
177 return {}, {}
97
178
98 # avoid silly behavior for parent -> working dir
179 # avoid silly behavior for parent -> working dir
99 if c2.node() is None and c1.node() == repo.dirstate.p1():
180 if c2.node() is None and c1.node() == repo.dirstate.p1():
100 return repo.dirstate.copies(), {}
181 return repo.dirstate.copies(), {}
101
182
102 limit = _findlimit(repo, c1.rev(), c2.rev())
183 limit = _findlimit(repo, c1.rev(), c2.rev())
103 if limit is None:
184 if limit is None:
104 # no common ancestor, no copies
185 # no common ancestor, no copies
105 return {}, {}
186 return {}, {}
106 m1 = c1.manifest()
187 m1 = c1.manifest()
107 m2 = c2.manifest()
188 m2 = c2.manifest()
108 ma = ca.manifest()
189 ma = ca.manifest()
109
190
110 def makectx(f, n):
191 def makectx(f, n):
111 if len(n) != 20: # in a working context?
192 if len(n) != 20: # in a working context?
112 if c1.rev() is None:
193 if c1.rev() is None:
113 return c1.filectx(f)
194 return c1.filectx(f)
114 return c2.filectx(f)
195 return c2.filectx(f)
115 return repo.filectx(f, fileid=n)
196 return repo.filectx(f, fileid=n)
116
197
117 ctx = util.lrucachefunc(makectx)
198 ctx = util.lrucachefunc(makectx)
118 copy = {}
199 copy = {}
119 fullcopy = {}
200 fullcopy = {}
120 diverge = {}
201 diverge = {}
121
202
122 def related(f1, f2, limit):
203 def related(f1, f2, limit):
123 # Walk back to common ancestor to see if the two files originate
204 # Walk back to common ancestor to see if the two files originate
124 # from the same file. Since workingfilectx's rev() is None it messes
205 # from the same file. Since workingfilectx's rev() is None it messes
125 # up the integer comparison logic, hence the pre-step check for
206 # up the integer comparison logic, hence the pre-step check for
126 # None (f1 and f2 can only be workingfilectx's initially).
207 # None (f1 and f2 can only be workingfilectx's initially).
127
208
128 if f1 == f2:
209 if f1 == f2:
129 return f1 # a match
210 return f1 # a match
130
211
131 g1, g2 = f1.ancestors(), f2.ancestors()
212 g1, g2 = f1.ancestors(), f2.ancestors()
132 try:
213 try:
133 f1r, f2r = f1.rev(), f2.rev()
214 f1r, f2r = f1.rev(), f2.rev()
134
215
135 if f1r is None:
216 if f1r is None:
136 f1 = g1.next()
217 f1 = g1.next()
137 if f2r is None:
218 if f2r is None:
138 f2 = g2.next()
219 f2 = g2.next()
139
220
140 while True:
221 while True:
141 f1r, f2r = f1.rev(), f2.rev()
222 f1r, f2r = f1.rev(), f2.rev()
142 if f1r > f2r:
223 if f1r > f2r:
143 f1 = g1.next()
224 f1 = g1.next()
144 elif f2r > f1r:
225 elif f2r > f1r:
145 f2 = g2.next()
226 f2 = g2.next()
146 elif f1 == f2:
227 elif f1 == f2:
147 return f1 # a match
228 return f1 # a match
148 elif f1r == f2r or f1r < limit or f2r < limit:
229 elif f1r == f2r or f1r < limit or f2r < limit:
149 return False # copy no longer relevant
230 return False # copy no longer relevant
150 except StopIteration:
231 except StopIteration:
151 return False
232 return False
152
233
153 def checkcopies(f, m1, m2):
234 def checkcopies(f, m1, m2):
154 '''check possible copies of f from m1 to m2'''
235 '''check possible copies of f from m1 to m2'''
155 of = None
236 of = None
156 seen = set([f])
237 seen = set([f])
157 for oc in ctx(f, m1[f]).ancestors():
238 for oc in ctx(f, m1[f]).ancestors():
158 ocr = oc.rev()
239 ocr = oc.rev()
159 of = oc.path()
240 of = oc.path()
160 if of in seen:
241 if of in seen:
161 # check limit late - grab last rename before
242 # check limit late - grab last rename before
162 if ocr < limit:
243 if ocr < limit:
163 break
244 break
164 continue
245 continue
165 seen.add(of)
246 seen.add(of)
166
247
167 fullcopy[f] = of # remember for dir rename detection
248 fullcopy[f] = of # remember for dir rename detection
168 if of not in m2:
249 if of not in m2:
169 continue # no match, keep looking
250 continue # no match, keep looking
170 if m2[of] == ma.get(of):
251 if m2[of] == ma.get(of):
171 break # no merge needed, quit early
252 break # no merge needed, quit early
172 c2 = ctx(of, m2[of])
253 c2 = ctx(of, m2[of])
173 cr = related(oc, c2, ca.rev())
254 cr = related(oc, c2, ca.rev())
174 if cr and (of == f or of == c2.path()): # non-divergent
255 if cr and (of == f or of == c2.path()): # non-divergent
175 copy[f] = of
256 copy[f] = of
176 of = None
257 of = None
177 break
258 break
178
259
179 if of in ma:
260 if of in ma:
180 diverge.setdefault(of, []).append(f)
261 diverge.setdefault(of, []).append(f)
181
262
182 repo.ui.debug(" searching for copies back to rev %d\n" % limit)
263 repo.ui.debug(" searching for copies back to rev %d\n" % limit)
183
264
184 u1 = _nonoverlap(m1, m2, ma)
265 u1 = _nonoverlap(m1, m2, ma)
185 u2 = _nonoverlap(m2, m1, ma)
266 u2 = _nonoverlap(m2, m1, ma)
186
267
187 if u1:
268 if u1:
188 repo.ui.debug(" unmatched files in local:\n %s\n"
269 repo.ui.debug(" unmatched files in local:\n %s\n"
189 % "\n ".join(u1))
270 % "\n ".join(u1))
190 if u2:
271 if u2:
191 repo.ui.debug(" unmatched files in other:\n %s\n"
272 repo.ui.debug(" unmatched files in other:\n %s\n"
192 % "\n ".join(u2))
273 % "\n ".join(u2))
193
274
194 for f in u1:
275 for f in u1:
195 checkcopies(f, m1, m2)
276 checkcopies(f, m1, m2)
196 for f in u2:
277 for f in u2:
197 checkcopies(f, m2, m1)
278 checkcopies(f, m2, m1)
198
279
199 diverge2 = set()
280 diverge2 = set()
200 for of, fl in diverge.items():
281 for of, fl in diverge.items():
201 if len(fl) == 1 or of in c2:
282 if len(fl) == 1 or of in c2:
202 del diverge[of] # not actually divergent, or not a rename
283 del diverge[of] # not actually divergent, or not a rename
203 else:
284 else:
204 diverge2.update(fl) # reverse map for below
285 diverge2.update(fl) # reverse map for below
205
286
206 if fullcopy:
287 if fullcopy:
207 repo.ui.debug(" all copies found (* = to merge, ! = divergent):\n")
288 repo.ui.debug(" all copies found (* = to merge, ! = divergent):\n")
208 for f in fullcopy:
289 for f in fullcopy:
209 note = ""
290 note = ""
210 if f in copy:
291 if f in copy:
211 note += "*"
292 note += "*"
212 if f in diverge2:
293 if f in diverge2:
213 note += "!"
294 note += "!"
214 repo.ui.debug(" %s -> %s %s\n" % (f, fullcopy[f], note))
295 repo.ui.debug(" %s -> %s %s\n" % (f, fullcopy[f], note))
215 del diverge2
296 del diverge2
216
297
217 if not fullcopy or not checkdirs:
298 if not fullcopy or not checkdirs:
218 return copy, diverge
299 return copy, diverge
219
300
220 repo.ui.debug(" checking for directory renames\n")
301 repo.ui.debug(" checking for directory renames\n")
221
302
222 # generate a directory move map
303 # generate a directory move map
223 d1, d2 = _dirs(m1), _dirs(m2)
304 d1, d2 = _dirs(m1), _dirs(m2)
224 invalid = set()
305 invalid = set()
225 dirmove = {}
306 dirmove = {}
226
307
227 # examine each file copy for a potential directory move, which is
308 # examine each file copy for a potential directory move, which is
228 # when all the files in a directory are moved to a new directory
309 # when all the files in a directory are moved to a new directory
229 for dst, src in fullcopy.iteritems():
310 for dst, src in fullcopy.iteritems():
230 dsrc, ddst = _dirname(src), _dirname(dst)
311 dsrc, ddst = _dirname(src), _dirname(dst)
231 if dsrc in invalid:
312 if dsrc in invalid:
232 # already seen to be uninteresting
313 # already seen to be uninteresting
233 continue
314 continue
234 elif dsrc in d1 and ddst in d1:
315 elif dsrc in d1 and ddst in d1:
235 # directory wasn't entirely moved locally
316 # directory wasn't entirely moved locally
236 invalid.add(dsrc)
317 invalid.add(dsrc)
237 elif dsrc in d2 and ddst in d2:
318 elif dsrc in d2 and ddst in d2:
238 # directory wasn't entirely moved remotely
319 # directory wasn't entirely moved remotely
239 invalid.add(dsrc)
320 invalid.add(dsrc)
240 elif dsrc in dirmove and dirmove[dsrc] != ddst:
321 elif dsrc in dirmove and dirmove[dsrc] != ddst:
241 # files from the same directory moved to two different places
322 # files from the same directory moved to two different places
242 invalid.add(dsrc)
323 invalid.add(dsrc)
243 else:
324 else:
244 # looks good so far
325 # looks good so far
245 dirmove[dsrc + "/"] = ddst + "/"
326 dirmove[dsrc + "/"] = ddst + "/"
246
327
247 for i in invalid:
328 for i in invalid:
248 if i in dirmove:
329 if i in dirmove:
249 del dirmove[i]
330 del dirmove[i]
250 del d1, d2, invalid
331 del d1, d2, invalid
251
332
252 if not dirmove:
333 if not dirmove:
253 return copy, diverge
334 return copy, diverge
254
335
255 for d in dirmove:
336 for d in dirmove:
256 repo.ui.debug(" dir %s -> %s\n" % (d, dirmove[d]))
337 repo.ui.debug(" dir %s -> %s\n" % (d, dirmove[d]))
257
338
258 # check unaccounted nonoverlapping files against directory moves
339 # check unaccounted nonoverlapping files against directory moves
259 for f in u1 + u2:
340 for f in u1 + u2:
260 if f not in fullcopy:
341 if f not in fullcopy:
261 for d in dirmove:
342 for d in dirmove:
262 if f.startswith(d):
343 if f.startswith(d):
263 # new file added in a directory that was moved, move it
344 # new file added in a directory that was moved, move it
264 df = dirmove[d] + f[len(d):]
345 df = dirmove[d] + f[len(d):]
265 if df not in copy:
346 if df not in copy:
266 copy[f] = df
347 copy[f] = df
267 repo.ui.debug(" file %s -> %s\n" % (f, copy[f]))
348 repo.ui.debug(" file %s -> %s\n" % (f, copy[f]))
268 break
349 break
269
350
270 return copy, diverge
351 return copy, diverge
@@ -1,177 +1,175 b''
1 Setup extension:
1 Setup extension:
2
2
3 $ echo "[extensions]" >> $HGRCPATH
3 $ echo "[extensions]" >> $HGRCPATH
4 $ echo "mq =" >> $HGRCPATH
4 $ echo "mq =" >> $HGRCPATH
5 $ echo "[mq]" >> $HGRCPATH
5 $ echo "[mq]" >> $HGRCPATH
6 $ echo "git = keep" >> $HGRCPATH
6 $ echo "git = keep" >> $HGRCPATH
7
7
8 Test merge with mq changeset as the second parent:
8 Test merge with mq changeset as the second parent:
9
9
10 $ hg init m
10 $ hg init m
11 $ cd m
11 $ cd m
12 $ touch a b c
12 $ touch a b c
13 $ hg add a
13 $ hg add a
14 $ hg commit -m a
14 $ hg commit -m a
15 $ hg add b
15 $ hg add b
16 $ hg qnew -d "0 0" b
16 $ hg qnew -d "0 0" b
17 $ hg update 0
17 $ hg update 0
18 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
18 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
19 $ hg add c
19 $ hg add c
20 $ hg commit -m c
20 $ hg commit -m c
21 created new head
21 created new head
22 $ hg merge
22 $ hg merge
23 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
23 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
24 (branch merge, don't forget to commit)
24 (branch merge, don't forget to commit)
25 $ hg commit -m merge
25 $ hg commit -m merge
26 abort: cannot commit over an applied mq patch
26 abort: cannot commit over an applied mq patch
27 [255]
27 [255]
28 $ cd ..
28 $ cd ..
29
29
30 Issue529: mq aborts when merging patch deleting files
30 Issue529: mq aborts when merging patch deleting files
31
31
32 $ checkundo()
32 $ checkundo()
33 > {
33 > {
34 > if [ -f .hg/store/undo ]; then
34 > if [ -f .hg/store/undo ]; then
35 > echo ".hg/store/undo still exists"
35 > echo ".hg/store/undo still exists"
36 > fi
36 > fi
37 > }
37 > }
38
38
39 Commit two dummy files in "init" changeset:
39 Commit two dummy files in "init" changeset:
40
40
41 $ hg init t
41 $ hg init t
42 $ cd t
42 $ cd t
43 $ echo a > a
43 $ echo a > a
44 $ echo b > b
44 $ echo b > b
45 $ hg ci -Am init
45 $ hg ci -Am init
46 adding a
46 adding a
47 adding b
47 adding b
48 $ hg tag -l init
48 $ hg tag -l init
49
49
50 Create a patch removing a:
50 Create a patch removing a:
51
51
52 $ hg qnew rm_a
52 $ hg qnew rm_a
53 $ hg rm a
53 $ hg rm a
54 $ hg qrefresh -m "rm a"
54 $ hg qrefresh -m "rm a"
55
55
56 Save the patch queue so we can merge it later:
56 Save the patch queue so we can merge it later:
57
57
58 $ hg qsave -c -e
58 $ hg qsave -c -e
59 copy $TESTTMP/t/.hg/patches to $TESTTMP/t/.hg/patches.1 (glob)
59 copy $TESTTMP/t/.hg/patches to $TESTTMP/t/.hg/patches.1 (glob)
60 $ checkundo
60 $ checkundo
61
61
62 Update b and commit in an "update" changeset:
62 Update b and commit in an "update" changeset:
63
63
64 $ hg up -C init
64 $ hg up -C init
65 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
65 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
66 $ echo b >> b
66 $ echo b >> b
67 $ hg st
67 $ hg st
68 M b
68 M b
69 $ hg ci -m update
69 $ hg ci -m update
70 created new head
70 created new head
71
71
72 # Here, qpush used to abort with :
72 # Here, qpush used to abort with :
73 # The system cannot find the file specified => a
73 # The system cannot find the file specified => a
74 $ hg manifest
74 $ hg manifest
75 a
75 a
76 b
76 b
77
77
78 $ hg qpush -a -m
78 $ hg qpush -a -m
79 merging with queue at: $TESTTMP/t/.hg/patches.1 (glob)
79 merging with queue at: $TESTTMP/t/.hg/patches.1 (glob)
80 applying rm_a
80 applying rm_a
81 now at: rm_a
81 now at: rm_a
82
82
83 $ checkundo
83 $ checkundo
84 $ hg manifest
84 $ hg manifest
85 b
85 b
86
86
87 Ensure status is correct after merge:
87 Ensure status is correct after merge:
88
88
89 $ hg qpop -a
89 $ hg qpop -a
90 popping rm_a
90 popping rm_a
91 popping .hg.patches.merge.marker
91 popping .hg.patches.merge.marker
92 patch queue now empty
92 patch queue now empty
93
93
94 $ cd ..
94 $ cd ..
95
95
96 Classic MQ merge sequence *with an explicit named queue*:
96 Classic MQ merge sequence *with an explicit named queue*:
97
97
98 $ hg init t2
98 $ hg init t2
99 $ cd t2
99 $ cd t2
100 $ echo '[diff]' > .hg/hgrc
100 $ echo '[diff]' > .hg/hgrc
101 $ echo 'nodates = 1' >> .hg/hgrc
101 $ echo 'nodates = 1' >> .hg/hgrc
102 $ echo a > a
102 $ echo a > a
103 $ hg ci -Am init
103 $ hg ci -Am init
104 adding a
104 adding a
105 $ echo b > a
105 $ echo b > a
106 $ hg ci -m changea
106 $ hg ci -m changea
107 $ hg up -C 0
107 $ hg up -C 0
108 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
108 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
109 $ hg cp a aa
109 $ hg cp a aa
110 $ echo c >> a
110 $ echo c >> a
111 $ hg qnew --git -f -e patcha
111 $ hg qnew --git -f -e patcha
112 $ echo d >> a
112 $ echo d >> a
113 $ hg qnew -d '0 0' -f -e patcha2
113 $ hg qnew -d '0 0' -f -e patcha2
114
114
115 Create the reference queue:
115 Create the reference queue:
116
116
117 $ hg qsave -c -e -n refqueue
117 $ hg qsave -c -e -n refqueue
118 copy $TESTTMP/t2/.hg/patches to $TESTTMP/t2/.hg/refqueue (glob)
118 copy $TESTTMP/t2/.hg/patches to $TESTTMP/t2/.hg/refqueue (glob)
119 $ hg up -C 1
119 $ hg up -C 1
120 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
120 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
121
121
122 Merge:
122 Merge:
123
123
124 $ HGMERGE=internal:other hg qpush -a -m -n refqueue
124 $ HGMERGE=internal:other hg qpush -a -m -n refqueue
125 merging with queue at: $TESTTMP/t2/.hg/refqueue (glob)
125 merging with queue at: $TESTTMP/t2/.hg/refqueue (glob)
126 applying patcha
126 applying patcha
127 patching file a
127 patching file a
128 Hunk #1 FAILED at 0
128 Hunk #1 FAILED at 0
129 1 out of 1 hunks FAILED -- saving rejects to file a.rej
129 1 out of 1 hunks FAILED -- saving rejects to file a.rej
130 patch failed, unable to continue (try -v)
130 patch failed, unable to continue (try -v)
131 patch failed, rejects left in working dir
131 patch failed, rejects left in working dir
132 patch didn't work out, merging patcha
132 patch didn't work out, merging patcha
133 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
133 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
134 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
134 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
135 (branch merge, don't forget to commit)
135 (branch merge, don't forget to commit)
136 applying patcha2
136 applying patcha2
137 now at: patcha2
137 now at: patcha2
138
138
139 Check patcha is still a git patch:
139 Check patcha is still a git patch:
140
140
141 $ cat .hg/patches/patcha
141 $ cat .hg/patches/patcha
142 # HG changeset patch
142 # HG changeset patch
143 # Parent d3873e73d99ef67873dac33fbcc66268d5d2b6f4
143 # Parent d3873e73d99ef67873dac33fbcc66268d5d2b6f4
144
144
145 diff --git a/a b/a
145 diff --git a/a b/a
146 --- a/a
146 --- a/a
147 +++ b/a
147 +++ b/a
148 @@ -1,1 +1,2 @@
148 @@ -1,1 +1,2 @@
149 -b
149 -b
150 +a
150 +a
151 +c
151 +c
152 diff --git a/a b/aa
152 diff --git a/aa b/aa
153 copy from a
153 new file mode 100644
154 copy to aa
154 --- /dev/null
155 --- a/a
156 +++ b/aa
155 +++ b/aa
157 @@ -1,1 +1,1 @@
156 @@ -0,0 +1,1 @@
158 -b
159 +a
157 +a
160
158
161 Check patcha2 is still a regular patch:
159 Check patcha2 is still a regular patch:
162
160
163 $ cat .hg/patches/patcha2
161 $ cat .hg/patches/patcha2
164 # HG changeset patch
162 # HG changeset patch
165 # Parent ???????????????????????????????????????? (glob)
163 # Parent ???????????????????????????????????????? (glob)
166 # Date 0 0
164 # Date 0 0
167
165
168 diff -r ???????????? -r ???????????? a (glob)
166 diff -r ???????????? -r ???????????? a (glob)
169 --- a/a
167 --- a/a
170 +++ b/a
168 +++ b/a
171 @@ -1,2 +1,3 @@
169 @@ -1,2 +1,3 @@
172 a
170 a
173 c
171 c
174 +d
172 +d
175
173
176 $ cd ..
174 $ cd ..
177
175
@@ -1,1344 +1,1348 b''
1
1
2 $ add()
2 $ add()
3 > {
3 > {
4 > echo $2 >> $1
4 > echo $2 >> $1
5 > }
5 > }
6 $ hg init t
6 $ hg init t
7 $ cd t
7 $ cd t
8
8
9 set up a boring main branch
9 set up a boring main branch
10
10
11 $ add a a
11 $ add a a
12 $ hg add a
12 $ hg add a
13 $ mkdir x
13 $ mkdir x
14 $ add x/x x
14 $ add x/x x
15 $ hg add x/x
15 $ hg add x/x
16 $ hg ci -m0
16 $ hg ci -m0
17 $ add a m1
17 $ add a m1
18 $ hg ci -m1
18 $ hg ci -m1
19 $ add a m2
19 $ add a m2
20 $ add x/y y1
20 $ add x/y y1
21 $ hg add x/y
21 $ hg add x/y
22 $ hg ci -m2
22 $ hg ci -m2
23 $ cd ..
23 $ cd ..
24 $ show()
24 $ show()
25 > {
25 > {
26 > echo "- $2: $1"
26 > echo "- $2: $1"
27 > hg st -C $1
27 > hg st -C $1
28 > echo
28 > echo
29 > hg diff --git $1
29 > hg diff --git $1
30 > echo
30 > echo
31 > }
31 > }
32 $ count=0
32 $ count=0
33
33
34 make a new branch and get diff/status output
34 make a new branch and get diff/status output
35 $1 - first commit
35 $1 - first commit
36 $2 - second commit
36 $2 - second commit
37 $3 - working dir action
37 $3 - working dir action
38 $4 - test description
38 $4 - test description
39
39
40 $ tb()
40 $ tb()
41 > {
41 > {
42 > hg clone t t2 ; cd t2
42 > hg clone t t2 ; cd t2
43 > hg co -q -C 0
43 > hg co -q -C 0
44 >
44 >
45 > add a $count
45 > add a $count
46 > count=`expr $count + 1`
46 > count=`expr $count + 1`
47 > hg ci -m "t0"
47 > hg ci -m "t0"
48 > $1
48 > $1
49 > hg ci -m "t1"
49 > hg ci -m "t1"
50 > $2
50 > $2
51 > hg ci -m "t2"
51 > hg ci -m "t2"
52 > $3
52 > $3
53 >
53 >
54 > echo "** $4 **"
54 > echo "** $4 **"
55 > echo "** $1 / $2 / $3"
55 > echo "** $1 / $2 / $3"
56 > show "" "working to parent"
56 > show "" "working to parent"
57 > show "--rev 0" "working to root"
57 > show "--rev 0" "working to root"
58 > show "--rev 2" "working to branch"
58 > show "--rev 2" "working to branch"
59 > show "--rev 0 --rev ." "root to parent"
59 > show "--rev 0 --rev ." "root to parent"
60 > show "--rev . --rev 0" "parent to root"
60 > show "--rev . --rev 0" "parent to root"
61 > show "--rev 2 --rev ." "branch to parent"
61 > show "--rev 2 --rev ." "branch to parent"
62 > show "--rev . --rev 2" "parent to branch"
62 > show "--rev . --rev 2" "parent to branch"
63 > echo
63 > echo
64 > cd ..
64 > cd ..
65 > rm -rf t2
65 > rm -rf t2
66 > }
66 > }
67 $ tb "add a a1" "add a a2" "hg mv a b" "rename in working dir"
67 $ tb "add a a1" "add a a2" "hg mv a b" "rename in working dir"
68 updating to branch default
68 updating to branch default
69 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
69 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
70 created new head
70 created new head
71 ** rename in working dir **
71 ** rename in working dir **
72 ** add a a1 / add a a2 / hg mv a b
72 ** add a a1 / add a a2 / hg mv a b
73 - working to parent:
73 - working to parent:
74 A b
74 A b
75 a
75 a
76 R a
76 R a
77
77
78 diff --git a/a b/b
78 diff --git a/a b/b
79 rename from a
79 rename from a
80 rename to b
80 rename to b
81
81
82 - working to root: --rev 0
82 - working to root: --rev 0
83 A b
83 A b
84 a
84 a
85 R a
85 R a
86
86
87 diff --git a/a b/b
87 diff --git a/a b/b
88 rename from a
88 rename from a
89 rename to b
89 rename to b
90 --- a/a
90 --- a/a
91 +++ b/b
91 +++ b/b
92 @@ -1,1 +1,4 @@
92 @@ -1,1 +1,4 @@
93 a
93 a
94 +0
94 +0
95 +a1
95 +a1
96 +a2
96 +a2
97
97
98 - working to branch: --rev 2
98 - working to branch: --rev 2
99 A b
99 A b
100 a
100 a
101 R a
101 R a
102 R x/y
102 R x/y
103
103
104 diff --git a/a b/b
104 diff --git a/a b/b
105 rename from a
105 rename from a
106 rename to b
106 rename to b
107 --- a/a
107 --- a/a
108 +++ b/b
108 +++ b/b
109 @@ -1,3 +1,4 @@
109 @@ -1,3 +1,4 @@
110 a
110 a
111 -m1
111 -m1
112 -m2
112 -m2
113 +0
113 +0
114 +a1
114 +a1
115 +a2
115 +a2
116 diff --git a/x/y b/x/y
116 diff --git a/x/y b/x/y
117 deleted file mode 100644
117 deleted file mode 100644
118 --- a/x/y
118 --- a/x/y
119 +++ /dev/null
119 +++ /dev/null
120 @@ -1,1 +0,0 @@
120 @@ -1,1 +0,0 @@
121 -y1
121 -y1
122
122
123 - root to parent: --rev 0 --rev .
123 - root to parent: --rev 0 --rev .
124 M a
124 M a
125
125
126 diff --git a/a b/a
126 diff --git a/a b/a
127 --- a/a
127 --- a/a
128 +++ b/a
128 +++ b/a
129 @@ -1,1 +1,4 @@
129 @@ -1,1 +1,4 @@
130 a
130 a
131 +0
131 +0
132 +a1
132 +a1
133 +a2
133 +a2
134
134
135 - parent to root: --rev . --rev 0
135 - parent to root: --rev . --rev 0
136 M a
136 M a
137
137
138 diff --git a/a b/a
138 diff --git a/a b/a
139 --- a/a
139 --- a/a
140 +++ b/a
140 +++ b/a
141 @@ -1,4 +1,1 @@
141 @@ -1,4 +1,1 @@
142 a
142 a
143 -0
143 -0
144 -a1
144 -a1
145 -a2
145 -a2
146
146
147 - branch to parent: --rev 2 --rev .
147 - branch to parent: --rev 2 --rev .
148 M a
148 M a
149 R x/y
149 R x/y
150
150
151 diff --git a/a b/a
151 diff --git a/a b/a
152 --- a/a
152 --- a/a
153 +++ b/a
153 +++ b/a
154 @@ -1,3 +1,4 @@
154 @@ -1,3 +1,4 @@
155 a
155 a
156 -m1
156 -m1
157 -m2
157 -m2
158 +0
158 +0
159 +a1
159 +a1
160 +a2
160 +a2
161 diff --git a/x/y b/x/y
161 diff --git a/x/y b/x/y
162 deleted file mode 100644
162 deleted file mode 100644
163 --- a/x/y
163 --- a/x/y
164 +++ /dev/null
164 +++ /dev/null
165 @@ -1,1 +0,0 @@
165 @@ -1,1 +0,0 @@
166 -y1
166 -y1
167
167
168 - parent to branch: --rev . --rev 2
168 - parent to branch: --rev . --rev 2
169 M a
169 M a
170 A x/y
170 A x/y
171
171
172 diff --git a/a b/a
172 diff --git a/a b/a
173 --- a/a
173 --- a/a
174 +++ b/a
174 +++ b/a
175 @@ -1,4 +1,3 @@
175 @@ -1,4 +1,3 @@
176 a
176 a
177 -0
177 -0
178 -a1
178 -a1
179 -a2
179 -a2
180 +m1
180 +m1
181 +m2
181 +m2
182 diff --git a/x/y b/x/y
182 diff --git a/x/y b/x/y
183 new file mode 100644
183 new file mode 100644
184 --- /dev/null
184 --- /dev/null
185 +++ b/x/y
185 +++ b/x/y
186 @@ -0,0 +1,1 @@
186 @@ -0,0 +1,1 @@
187 +y1
187 +y1
188
188
189
189
190 $ tb "add a a1" "add a a2" "hg cp a b" "copy in working dir"
190 $ tb "add a a1" "add a a2" "hg cp a b" "copy in working dir"
191 updating to branch default
191 updating to branch default
192 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
192 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
193 created new head
193 created new head
194 ** copy in working dir **
194 ** copy in working dir **
195 ** add a a1 / add a a2 / hg cp a b
195 ** add a a1 / add a a2 / hg cp a b
196 - working to parent:
196 - working to parent:
197 A b
197 A b
198 a
198 a
199
199
200 diff --git a/a b/b
200 diff --git a/a b/b
201 copy from a
201 copy from a
202 copy to b
202 copy to b
203
203
204 - working to root: --rev 0
204 - working to root: --rev 0
205 M a
205 M a
206 A b
206 A b
207 a
207 a
208
208
209 diff --git a/a b/a
209 diff --git a/a b/a
210 --- a/a
210 --- a/a
211 +++ b/a
211 +++ b/a
212 @@ -1,1 +1,4 @@
212 @@ -1,1 +1,4 @@
213 a
213 a
214 +1
214 +1
215 +a1
215 +a1
216 +a2
216 +a2
217 diff --git a/a b/b
217 diff --git a/a b/b
218 copy from a
218 copy from a
219 copy to b
219 copy to b
220 --- a/a
220 --- a/a
221 +++ b/b
221 +++ b/b
222 @@ -1,1 +1,4 @@
222 @@ -1,1 +1,4 @@
223 a
223 a
224 +1
224 +1
225 +a1
225 +a1
226 +a2
226 +a2
227
227
228 - working to branch: --rev 2
228 - working to branch: --rev 2
229 M a
229 M a
230 A b
230 A b
231 a
231 a
232 R x/y
232 R x/y
233
233
234 diff --git a/a b/a
234 diff --git a/a b/a
235 --- a/a
235 --- a/a
236 +++ b/a
236 +++ b/a
237 @@ -1,3 +1,4 @@
237 @@ -1,3 +1,4 @@
238 a
238 a
239 -m1
239 -m1
240 -m2
240 -m2
241 +1
241 +1
242 +a1
242 +a1
243 +a2
243 +a2
244 diff --git a/a b/b
244 diff --git a/a b/b
245 copy from a
245 copy from a
246 copy to b
246 copy to b
247 --- a/a
247 --- a/a
248 +++ b/b
248 +++ b/b
249 @@ -1,3 +1,4 @@
249 @@ -1,3 +1,4 @@
250 a
250 a
251 -m1
251 -m1
252 -m2
252 -m2
253 +1
253 +1
254 +a1
254 +a1
255 +a2
255 +a2
256 diff --git a/x/y b/x/y
256 diff --git a/x/y b/x/y
257 deleted file mode 100644
257 deleted file mode 100644
258 --- a/x/y
258 --- a/x/y
259 +++ /dev/null
259 +++ /dev/null
260 @@ -1,1 +0,0 @@
260 @@ -1,1 +0,0 @@
261 -y1
261 -y1
262
262
263 - root to parent: --rev 0 --rev .
263 - root to parent: --rev 0 --rev .
264 M a
264 M a
265
265
266 diff --git a/a b/a
266 diff --git a/a b/a
267 --- a/a
267 --- a/a
268 +++ b/a
268 +++ b/a
269 @@ -1,1 +1,4 @@
269 @@ -1,1 +1,4 @@
270 a
270 a
271 +1
271 +1
272 +a1
272 +a1
273 +a2
273 +a2
274
274
275 - parent to root: --rev . --rev 0
275 - parent to root: --rev . --rev 0
276 M a
276 M a
277
277
278 diff --git a/a b/a
278 diff --git a/a b/a
279 --- a/a
279 --- a/a
280 +++ b/a
280 +++ b/a
281 @@ -1,4 +1,1 @@
281 @@ -1,4 +1,1 @@
282 a
282 a
283 -1
283 -1
284 -a1
284 -a1
285 -a2
285 -a2
286
286
287 - branch to parent: --rev 2 --rev .
287 - branch to parent: --rev 2 --rev .
288 M a
288 M a
289 R x/y
289 R x/y
290
290
291 diff --git a/a b/a
291 diff --git a/a b/a
292 --- a/a
292 --- a/a
293 +++ b/a
293 +++ b/a
294 @@ -1,3 +1,4 @@
294 @@ -1,3 +1,4 @@
295 a
295 a
296 -m1
296 -m1
297 -m2
297 -m2
298 +1
298 +1
299 +a1
299 +a1
300 +a2
300 +a2
301 diff --git a/x/y b/x/y
301 diff --git a/x/y b/x/y
302 deleted file mode 100644
302 deleted file mode 100644
303 --- a/x/y
303 --- a/x/y
304 +++ /dev/null
304 +++ /dev/null
305 @@ -1,1 +0,0 @@
305 @@ -1,1 +0,0 @@
306 -y1
306 -y1
307
307
308 - parent to branch: --rev . --rev 2
308 - parent to branch: --rev . --rev 2
309 M a
309 M a
310 A x/y
310 A x/y
311
311
312 diff --git a/a b/a
312 diff --git a/a b/a
313 --- a/a
313 --- a/a
314 +++ b/a
314 +++ b/a
315 @@ -1,4 +1,3 @@
315 @@ -1,4 +1,3 @@
316 a
316 a
317 -1
317 -1
318 -a1
318 -a1
319 -a2
319 -a2
320 +m1
320 +m1
321 +m2
321 +m2
322 diff --git a/x/y b/x/y
322 diff --git a/x/y b/x/y
323 new file mode 100644
323 new file mode 100644
324 --- /dev/null
324 --- /dev/null
325 +++ b/x/y
325 +++ b/x/y
326 @@ -0,0 +1,1 @@
326 @@ -0,0 +1,1 @@
327 +y1
327 +y1
328
328
329
329
330 $ tb "hg mv a b" "add b b1" "add b w" "single rename"
330 $ tb "hg mv a b" "add b b1" "add b w" "single rename"
331 updating to branch default
331 updating to branch default
332 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
332 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
333 created new head
333 created new head
334 ** single rename **
334 ** single rename **
335 ** hg mv a b / add b b1 / add b w
335 ** hg mv a b / add b b1 / add b w
336 - working to parent:
336 - working to parent:
337 M b
337 M b
338
338
339 diff --git a/b b/b
339 diff --git a/b b/b
340 --- a/b
340 --- a/b
341 +++ b/b
341 +++ b/b
342 @@ -1,3 +1,4 @@
342 @@ -1,3 +1,4 @@
343 a
343 a
344 2
344 2
345 b1
345 b1
346 +w
346 +w
347
347
348 - working to root: --rev 0
348 - working to root: --rev 0
349 A b
349 A b
350 a
350 a
351 R a
351 R a
352
352
353 diff --git a/a b/b
353 diff --git a/a b/b
354 rename from a
354 rename from a
355 rename to b
355 rename to b
356 --- a/a
356 --- a/a
357 +++ b/b
357 +++ b/b
358 @@ -1,1 +1,4 @@
358 @@ -1,1 +1,4 @@
359 a
359 a
360 +2
360 +2
361 +b1
361 +b1
362 +w
362 +w
363
363
364 - working to branch: --rev 2
364 - working to branch: --rev 2
365 A b
365 A b
366 a
366 a
367 R a
367 R a
368 R x/y
368 R x/y
369
369
370 diff --git a/a b/b
370 diff --git a/a b/b
371 rename from a
371 rename from a
372 rename to b
372 rename to b
373 --- a/a
373 --- a/a
374 +++ b/b
374 +++ b/b
375 @@ -1,3 +1,4 @@
375 @@ -1,3 +1,4 @@
376 a
376 a
377 -m1
377 -m1
378 -m2
378 -m2
379 +2
379 +2
380 +b1
380 +b1
381 +w
381 +w
382 diff --git a/x/y b/x/y
382 diff --git a/x/y b/x/y
383 deleted file mode 100644
383 deleted file mode 100644
384 --- a/x/y
384 --- a/x/y
385 +++ /dev/null
385 +++ /dev/null
386 @@ -1,1 +0,0 @@
386 @@ -1,1 +0,0 @@
387 -y1
387 -y1
388
388
389 - root to parent: --rev 0 --rev .
389 - root to parent: --rev 0 --rev .
390 A b
390 A b
391 a
391 a
392 R a
392 R a
393
393
394 diff --git a/a b/b
394 diff --git a/a b/b
395 rename from a
395 rename from a
396 rename to b
396 rename to b
397 --- a/a
397 --- a/a
398 +++ b/b
398 +++ b/b
399 @@ -1,1 +1,3 @@
399 @@ -1,1 +1,3 @@
400 a
400 a
401 +2
401 +2
402 +b1
402 +b1
403
403
404 - parent to root: --rev . --rev 0
404 - parent to root: --rev . --rev 0
405 A a
405 A a
406 b
406 b
407 R b
407 R b
408
408
409 diff --git a/b b/a
409 diff --git a/b b/a
410 rename from b
410 rename from b
411 rename to a
411 rename to a
412 --- a/b
412 --- a/b
413 +++ b/a
413 +++ b/a
414 @@ -1,3 +1,1 @@
414 @@ -1,3 +1,1 @@
415 a
415 a
416 -2
416 -2
417 -b1
417 -b1
418
418
419 - branch to parent: --rev 2 --rev .
419 - branch to parent: --rev 2 --rev .
420 A b
420 A b
421 a
421 a
422 R a
422 R a
423 R x/y
423 R x/y
424
424
425 diff --git a/a b/b
425 diff --git a/a b/b
426 rename from a
426 rename from a
427 rename to b
427 rename to b
428 --- a/a
428 --- a/a
429 +++ b/b
429 +++ b/b
430 @@ -1,3 +1,3 @@
430 @@ -1,3 +1,3 @@
431 a
431 a
432 -m1
432 -m1
433 -m2
433 -m2
434 +2
434 +2
435 +b1
435 +b1
436 diff --git a/x/y b/x/y
436 diff --git a/x/y b/x/y
437 deleted file mode 100644
437 deleted file mode 100644
438 --- a/x/y
438 --- a/x/y
439 +++ /dev/null
439 +++ /dev/null
440 @@ -1,1 +0,0 @@
440 @@ -1,1 +0,0 @@
441 -y1
441 -y1
442
442
443 - parent to branch: --rev . --rev 2
443 - parent to branch: --rev . --rev 2
444 A a
444 A a
445 b
445 b
446 A x/y
446 A x/y
447 R b
447 R b
448
448
449 diff --git a/b b/a
449 diff --git a/b b/a
450 rename from b
450 rename from b
451 rename to a
451 rename to a
452 --- a/b
452 --- a/b
453 +++ b/a
453 +++ b/a
454 @@ -1,3 +1,3 @@
454 @@ -1,3 +1,3 @@
455 a
455 a
456 -2
456 -2
457 -b1
457 -b1
458 +m1
458 +m1
459 +m2
459 +m2
460 diff --git a/x/y b/x/y
460 diff --git a/x/y b/x/y
461 new file mode 100644
461 new file mode 100644
462 --- /dev/null
462 --- /dev/null
463 +++ b/x/y
463 +++ b/x/y
464 @@ -0,0 +1,1 @@
464 @@ -0,0 +1,1 @@
465 +y1
465 +y1
466
466
467
467
468 $ tb "hg cp a b" "add b b1" "add a w" "single copy"
468 $ tb "hg cp a b" "add b b1" "add a w" "single copy"
469 updating to branch default
469 updating to branch default
470 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
470 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
471 created new head
471 created new head
472 ** single copy **
472 ** single copy **
473 ** hg cp a b / add b b1 / add a w
473 ** hg cp a b / add b b1 / add a w
474 - working to parent:
474 - working to parent:
475 M a
475 M a
476
476
477 diff --git a/a b/a
477 diff --git a/a b/a
478 --- a/a
478 --- a/a
479 +++ b/a
479 +++ b/a
480 @@ -1,2 +1,3 @@
480 @@ -1,2 +1,3 @@
481 a
481 a
482 3
482 3
483 +w
483 +w
484
484
485 - working to root: --rev 0
485 - working to root: --rev 0
486 M a
486 M a
487 A b
487 A b
488 a
488 a
489
489
490 diff --git a/a b/a
490 diff --git a/a b/a
491 --- a/a
491 --- a/a
492 +++ b/a
492 +++ b/a
493 @@ -1,1 +1,3 @@
493 @@ -1,1 +1,3 @@
494 a
494 a
495 +3
495 +3
496 +w
496 +w
497 diff --git a/a b/b
497 diff --git a/a b/b
498 copy from a
498 copy from a
499 copy to b
499 copy to b
500 --- a/a
500 --- a/a
501 +++ b/b
501 +++ b/b
502 @@ -1,1 +1,3 @@
502 @@ -1,1 +1,3 @@
503 a
503 a
504 +3
504 +3
505 +b1
505 +b1
506
506
507 - working to branch: --rev 2
507 - working to branch: --rev 2
508 M a
508 M a
509 A b
509 A b
510 a
510 a
511 R x/y
511 R x/y
512
512
513 diff --git a/a b/a
513 diff --git a/a b/a
514 --- a/a
514 --- a/a
515 +++ b/a
515 +++ b/a
516 @@ -1,3 +1,3 @@
516 @@ -1,3 +1,3 @@
517 a
517 a
518 -m1
518 -m1
519 -m2
519 -m2
520 +3
520 +3
521 +w
521 +w
522 diff --git a/a b/b
522 diff --git a/a b/b
523 copy from a
523 copy from a
524 copy to b
524 copy to b
525 --- a/a
525 --- a/a
526 +++ b/b
526 +++ b/b
527 @@ -1,3 +1,3 @@
527 @@ -1,3 +1,3 @@
528 a
528 a
529 -m1
529 -m1
530 -m2
530 -m2
531 +3
531 +3
532 +b1
532 +b1
533 diff --git a/x/y b/x/y
533 diff --git a/x/y b/x/y
534 deleted file mode 100644
534 deleted file mode 100644
535 --- a/x/y
535 --- a/x/y
536 +++ /dev/null
536 +++ /dev/null
537 @@ -1,1 +0,0 @@
537 @@ -1,1 +0,0 @@
538 -y1
538 -y1
539
539
540 - root to parent: --rev 0 --rev .
540 - root to parent: --rev 0 --rev .
541 M a
541 M a
542 A b
542 A b
543 a
543 a
544
544
545 diff --git a/a b/a
545 diff --git a/a b/a
546 --- a/a
546 --- a/a
547 +++ b/a
547 +++ b/a
548 @@ -1,1 +1,2 @@
548 @@ -1,1 +1,2 @@
549 a
549 a
550 +3
550 +3
551 diff --git a/a b/b
551 diff --git a/a b/b
552 copy from a
552 copy from a
553 copy to b
553 copy to b
554 --- a/a
554 --- a/a
555 +++ b/b
555 +++ b/b
556 @@ -1,1 +1,3 @@
556 @@ -1,1 +1,3 @@
557 a
557 a
558 +3
558 +3
559 +b1
559 +b1
560
560
561 - parent to root: --rev . --rev 0
561 - parent to root: --rev . --rev 0
562 M a
562 M a
563 b
563 R b
564 R b
564
565
565 diff --git a/a b/a
566 diff --git a/a b/a
566 --- a/a
567 --- a/a
567 +++ b/a
568 +++ b/a
568 @@ -1,2 +1,1 @@
569 @@ -1,2 +1,1 @@
569 a
570 a
570 -3
571 -3
571 diff --git a/b b/b
572 diff --git a/b b/b
572 deleted file mode 100644
573 deleted file mode 100644
573 --- a/b
574 --- a/b
574 +++ /dev/null
575 +++ /dev/null
575 @@ -1,3 +0,0 @@
576 @@ -1,3 +0,0 @@
576 -a
577 -a
577 -3
578 -3
578 -b1
579 -b1
579
580
580 - branch to parent: --rev 2 --rev .
581 - branch to parent: --rev 2 --rev .
581 M a
582 M a
582 A b
583 A b
583 a
584 a
584 R x/y
585 R x/y
585
586
586 diff --git a/a b/a
587 diff --git a/a b/a
587 --- a/a
588 --- a/a
588 +++ b/a
589 +++ b/a
589 @@ -1,3 +1,2 @@
590 @@ -1,3 +1,2 @@
590 a
591 a
591 -m1
592 -m1
592 -m2
593 -m2
593 +3
594 +3
594 diff --git a/a b/b
595 diff --git a/a b/b
595 copy from a
596 copy from a
596 copy to b
597 copy to b
597 --- a/a
598 --- a/a
598 +++ b/b
599 +++ b/b
599 @@ -1,3 +1,3 @@
600 @@ -1,3 +1,3 @@
600 a
601 a
601 -m1
602 -m1
602 -m2
603 -m2
603 +3
604 +3
604 +b1
605 +b1
605 diff --git a/x/y b/x/y
606 diff --git a/x/y b/x/y
606 deleted file mode 100644
607 deleted file mode 100644
607 --- a/x/y
608 --- a/x/y
608 +++ /dev/null
609 +++ /dev/null
609 @@ -1,1 +0,0 @@
610 @@ -1,1 +0,0 @@
610 -y1
611 -y1
611
612
612 - parent to branch: --rev . --rev 2
613 - parent to branch: --rev . --rev 2
613 M a
614 M a
615 b
614 A x/y
616 A x/y
615 R b
617 R b
616
618
617 diff --git a/a b/a
619 diff --git a/a b/a
618 --- a/a
620 --- a/a
619 +++ b/a
621 +++ b/a
620 @@ -1,2 +1,3 @@
622 @@ -1,2 +1,3 @@
621 a
623 a
622 -3
624 -3
623 +m1
625 +m1
624 +m2
626 +m2
625 diff --git a/b b/b
627 diff --git a/b b/b
626 deleted file mode 100644
628 deleted file mode 100644
627 --- a/b
629 --- a/b
628 +++ /dev/null
630 +++ /dev/null
629 @@ -1,3 +0,0 @@
631 @@ -1,3 +0,0 @@
630 -a
632 -a
631 -3
633 -3
632 -b1
634 -b1
633 diff --git a/x/y b/x/y
635 diff --git a/x/y b/x/y
634 new file mode 100644
636 new file mode 100644
635 --- /dev/null
637 --- /dev/null
636 +++ b/x/y
638 +++ b/x/y
637 @@ -0,0 +1,1 @@
639 @@ -0,0 +1,1 @@
638 +y1
640 +y1
639
641
640
642
641 $ tb "hg mv a b" "hg mv b c" "hg mv c d" "rename chain"
643 $ tb "hg mv a b" "hg mv b c" "hg mv c d" "rename chain"
642 updating to branch default
644 updating to branch default
643 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
645 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
644 created new head
646 created new head
645 ** rename chain **
647 ** rename chain **
646 ** hg mv a b / hg mv b c / hg mv c d
648 ** hg mv a b / hg mv b c / hg mv c d
647 - working to parent:
649 - working to parent:
648 A d
650 A d
649 c
651 c
650 R c
652 R c
651
653
652 diff --git a/c b/d
654 diff --git a/c b/d
653 rename from c
655 rename from c
654 rename to d
656 rename to d
655
657
656 - working to root: --rev 0
658 - working to root: --rev 0
657 A d
659 A d
658 a
660 a
659 R a
661 R a
660
662
661 diff --git a/a b/d
663 diff --git a/a b/d
662 rename from a
664 rename from a
663 rename to d
665 rename to d
664 --- a/a
666 --- a/a
665 +++ b/d
667 +++ b/d
666 @@ -1,1 +1,2 @@
668 @@ -1,1 +1,2 @@
667 a
669 a
668 +4
670 +4
669
671
670 - working to branch: --rev 2
672 - working to branch: --rev 2
671 A d
673 A d
672 a
674 a
673 R a
675 R a
674 R x/y
676 R x/y
675
677
676 diff --git a/a b/d
678 diff --git a/a b/d
677 rename from a
679 rename from a
678 rename to d
680 rename to d
679 --- a/a
681 --- a/a
680 +++ b/d
682 +++ b/d
681 @@ -1,3 +1,2 @@
683 @@ -1,3 +1,2 @@
682 a
684 a
683 -m1
685 -m1
684 -m2
686 -m2
685 +4
687 +4
686 diff --git a/x/y b/x/y
688 diff --git a/x/y b/x/y
687 deleted file mode 100644
689 deleted file mode 100644
688 --- a/x/y
690 --- a/x/y
689 +++ /dev/null
691 +++ /dev/null
690 @@ -1,1 +0,0 @@
692 @@ -1,1 +0,0 @@
691 -y1
693 -y1
692
694
693 - root to parent: --rev 0 --rev .
695 - root to parent: --rev 0 --rev .
694 A c
696 A c
695 a
697 a
696 R a
698 R a
697
699
698 diff --git a/a b/c
700 diff --git a/a b/c
699 rename from a
701 rename from a
700 rename to c
702 rename to c
701 --- a/a
703 --- a/a
702 +++ b/c
704 +++ b/c
703 @@ -1,1 +1,2 @@
705 @@ -1,1 +1,2 @@
704 a
706 a
705 +4
707 +4
706
708
707 - parent to root: --rev . --rev 0
709 - parent to root: --rev . --rev 0
708 A a
710 A a
709 c
711 c
710 R c
712 R c
711
713
712 diff --git a/c b/a
714 diff --git a/c b/a
713 rename from c
715 rename from c
714 rename to a
716 rename to a
715 --- a/c
717 --- a/c
716 +++ b/a
718 +++ b/a
717 @@ -1,2 +1,1 @@
719 @@ -1,2 +1,1 @@
718 a
720 a
719 -4
721 -4
720
722
721 - branch to parent: --rev 2 --rev .
723 - branch to parent: --rev 2 --rev .
722 A c
724 A c
723 a
725 a
724 R a
726 R a
725 R x/y
727 R x/y
726
728
727 diff --git a/a b/c
729 diff --git a/a b/c
728 rename from a
730 rename from a
729 rename to c
731 rename to c
730 --- a/a
732 --- a/a
731 +++ b/c
733 +++ b/c
732 @@ -1,3 +1,2 @@
734 @@ -1,3 +1,2 @@
733 a
735 a
734 -m1
736 -m1
735 -m2
737 -m2
736 +4
738 +4
737 diff --git a/x/y b/x/y
739 diff --git a/x/y b/x/y
738 deleted file mode 100644
740 deleted file mode 100644
739 --- a/x/y
741 --- a/x/y
740 +++ /dev/null
742 +++ /dev/null
741 @@ -1,1 +0,0 @@
743 @@ -1,1 +0,0 @@
742 -y1
744 -y1
743
745
744 - parent to branch: --rev . --rev 2
746 - parent to branch: --rev . --rev 2
745 A a
747 A a
746 c
748 c
747 A x/y
749 A x/y
748 R c
750 R c
749
751
750 diff --git a/c b/a
752 diff --git a/c b/a
751 rename from c
753 rename from c
752 rename to a
754 rename to a
753 --- a/c
755 --- a/c
754 +++ b/a
756 +++ b/a
755 @@ -1,2 +1,3 @@
757 @@ -1,2 +1,3 @@
756 a
758 a
757 -4
759 -4
758 +m1
760 +m1
759 +m2
761 +m2
760 diff --git a/x/y b/x/y
762 diff --git a/x/y b/x/y
761 new file mode 100644
763 new file mode 100644
762 --- /dev/null
764 --- /dev/null
763 +++ b/x/y
765 +++ b/x/y
764 @@ -0,0 +1,1 @@
766 @@ -0,0 +1,1 @@
765 +y1
767 +y1
766
768
767
769
768 $ tb "hg cp a b" "hg cp b c" "hg cp c d" "copy chain"
770 $ tb "hg cp a b" "hg cp b c" "hg cp c d" "copy chain"
769 updating to branch default
771 updating to branch default
770 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
772 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
771 created new head
773 created new head
772 ** copy chain **
774 ** copy chain **
773 ** hg cp a b / hg cp b c / hg cp c d
775 ** hg cp a b / hg cp b c / hg cp c d
774 - working to parent:
776 - working to parent:
775 A d
777 A d
776 c
778 c
777
779
778 diff --git a/c b/d
780 diff --git a/c b/d
779 copy from c
781 copy from c
780 copy to d
782 copy to d
781
783
782 - working to root: --rev 0
784 - working to root: --rev 0
783 M a
785 M a
784 A b
786 A b
785 a
787 a
786 A c
788 A c
787 a
789 a
788 A d
790 A d
789 a
791 a
790
792
791 diff --git a/a b/a
793 diff --git a/a b/a
792 --- a/a
794 --- a/a
793 +++ b/a
795 +++ b/a
794 @@ -1,1 +1,2 @@
796 @@ -1,1 +1,2 @@
795 a
797 a
796 +5
798 +5
797 diff --git a/a b/b
799 diff --git a/a b/b
798 copy from a
800 copy from a
799 copy to b
801 copy to b
800 --- a/a
802 --- a/a
801 +++ b/b
803 +++ b/b
802 @@ -1,1 +1,2 @@
804 @@ -1,1 +1,2 @@
803 a
805 a
804 +5
806 +5
805 diff --git a/a b/c
807 diff --git a/a b/c
806 copy from a
808 copy from a
807 copy to c
809 copy to c
808 --- a/a
810 --- a/a
809 +++ b/c
811 +++ b/c
810 @@ -1,1 +1,2 @@
812 @@ -1,1 +1,2 @@
811 a
813 a
812 +5
814 +5
813 diff --git a/a b/d
815 diff --git a/a b/d
814 copy from a
816 copy from a
815 copy to d
817 copy to d
816 --- a/a
818 --- a/a
817 +++ b/d
819 +++ b/d
818 @@ -1,1 +1,2 @@
820 @@ -1,1 +1,2 @@
819 a
821 a
820 +5
822 +5
821
823
822 - working to branch: --rev 2
824 - working to branch: --rev 2
823 M a
825 M a
824 A b
826 A b
825 a
827 a
826 A c
828 A c
827 a
829 a
828 A d
830 A d
829 a
831 a
830 R x/y
832 R x/y
831
833
832 diff --git a/a b/a
834 diff --git a/a b/a
833 --- a/a
835 --- a/a
834 +++ b/a
836 +++ b/a
835 @@ -1,3 +1,2 @@
837 @@ -1,3 +1,2 @@
836 a
838 a
837 -m1
839 -m1
838 -m2
840 -m2
839 +5
841 +5
840 diff --git a/a b/b
842 diff --git a/a b/b
841 copy from a
843 copy from a
842 copy to b
844 copy to b
843 --- a/a
845 --- a/a
844 +++ b/b
846 +++ b/b
845 @@ -1,3 +1,2 @@
847 @@ -1,3 +1,2 @@
846 a
848 a
847 -m1
849 -m1
848 -m2
850 -m2
849 +5
851 +5
850 diff --git a/a b/c
852 diff --git a/a b/c
851 copy from a
853 copy from a
852 copy to c
854 copy to c
853 --- a/a
855 --- a/a
854 +++ b/c
856 +++ b/c
855 @@ -1,3 +1,2 @@
857 @@ -1,3 +1,2 @@
856 a
858 a
857 -m1
859 -m1
858 -m2
860 -m2
859 +5
861 +5
860 diff --git a/a b/d
862 diff --git a/a b/d
861 copy from a
863 copy from a
862 copy to d
864 copy to d
863 --- a/a
865 --- a/a
864 +++ b/d
866 +++ b/d
865 @@ -1,3 +1,2 @@
867 @@ -1,3 +1,2 @@
866 a
868 a
867 -m1
869 -m1
868 -m2
870 -m2
869 +5
871 +5
870 diff --git a/x/y b/x/y
872 diff --git a/x/y b/x/y
871 deleted file mode 100644
873 deleted file mode 100644
872 --- a/x/y
874 --- a/x/y
873 +++ /dev/null
875 +++ /dev/null
874 @@ -1,1 +0,0 @@
876 @@ -1,1 +0,0 @@
875 -y1
877 -y1
876
878
877 - root to parent: --rev 0 --rev .
879 - root to parent: --rev 0 --rev .
878 M a
880 M a
879 A b
881 A b
880 a
882 a
881 A c
883 A c
882 a
884 a
883
885
884 diff --git a/a b/a
886 diff --git a/a b/a
885 --- a/a
887 --- a/a
886 +++ b/a
888 +++ b/a
887 @@ -1,1 +1,2 @@
889 @@ -1,1 +1,2 @@
888 a
890 a
889 +5
891 +5
890 diff --git a/a b/b
892 diff --git a/a b/b
891 copy from a
893 copy from a
892 copy to b
894 copy to b
893 --- a/a
895 --- a/a
894 +++ b/b
896 +++ b/b
895 @@ -1,1 +1,2 @@
897 @@ -1,1 +1,2 @@
896 a
898 a
897 +5
899 +5
898 diff --git a/a b/c
900 diff --git a/a b/c
899 copy from a
901 copy from a
900 copy to c
902 copy to c
901 --- a/a
903 --- a/a
902 +++ b/c
904 +++ b/c
903 @@ -1,1 +1,2 @@
905 @@ -1,1 +1,2 @@
904 a
906 a
905 +5
907 +5
906
908
907 - parent to root: --rev . --rev 0
909 - parent to root: --rev . --rev 0
908 M a
910 M a
911 b
909 R b
912 R b
910 R c
913 R c
911
914
912 diff --git a/a b/a
915 diff --git a/a b/a
913 --- a/a
916 --- a/a
914 +++ b/a
917 +++ b/a
915 @@ -1,2 +1,1 @@
918 @@ -1,2 +1,1 @@
916 a
919 a
917 -5
920 -5
918 diff --git a/b b/b
921 diff --git a/b b/b
919 deleted file mode 100644
922 deleted file mode 100644
920 --- a/b
923 --- a/b
921 +++ /dev/null
924 +++ /dev/null
922 @@ -1,2 +0,0 @@
925 @@ -1,2 +0,0 @@
923 -a
926 -a
924 -5
927 -5
925 diff --git a/c b/c
928 diff --git a/c b/c
926 deleted file mode 100644
929 deleted file mode 100644
927 --- a/c
930 --- a/c
928 +++ /dev/null
931 +++ /dev/null
929 @@ -1,2 +0,0 @@
932 @@ -1,2 +0,0 @@
930 -a
933 -a
931 -5
934 -5
932
935
933 - branch to parent: --rev 2 --rev .
936 - branch to parent: --rev 2 --rev .
934 M a
937 M a
935 A b
938 A b
936 a
939 a
937 A c
940 A c
938 a
941 a
939 R x/y
942 R x/y
940
943
941 diff --git a/a b/a
944 diff --git a/a b/a
942 --- a/a
945 --- a/a
943 +++ b/a
946 +++ b/a
944 @@ -1,3 +1,2 @@
947 @@ -1,3 +1,2 @@
945 a
948 a
946 -m1
949 -m1
947 -m2
950 -m2
948 +5
951 +5
949 diff --git a/a b/b
952 diff --git a/a b/b
950 copy from a
953 copy from a
951 copy to b
954 copy to b
952 --- a/a
955 --- a/a
953 +++ b/b
956 +++ b/b
954 @@ -1,3 +1,2 @@
957 @@ -1,3 +1,2 @@
955 a
958 a
956 -m1
959 -m1
957 -m2
960 -m2
958 +5
961 +5
959 diff --git a/a b/c
962 diff --git a/a b/c
960 copy from a
963 copy from a
961 copy to c
964 copy to c
962 --- a/a
965 --- a/a
963 +++ b/c
966 +++ b/c
964 @@ -1,3 +1,2 @@
967 @@ -1,3 +1,2 @@
965 a
968 a
966 -m1
969 -m1
967 -m2
970 -m2
968 +5
971 +5
969 diff --git a/x/y b/x/y
972 diff --git a/x/y b/x/y
970 deleted file mode 100644
973 deleted file mode 100644
971 --- a/x/y
974 --- a/x/y
972 +++ /dev/null
975 +++ /dev/null
973 @@ -1,1 +0,0 @@
976 @@ -1,1 +0,0 @@
974 -y1
977 -y1
975
978
976 - parent to branch: --rev . --rev 2
979 - parent to branch: --rev . --rev 2
977 M a
980 M a
981 b
978 A x/y
982 A x/y
979 R b
983 R b
980 R c
984 R c
981
985
982 diff --git a/a b/a
986 diff --git a/a b/a
983 --- a/a
987 --- a/a
984 +++ b/a
988 +++ b/a
985 @@ -1,2 +1,3 @@
989 @@ -1,2 +1,3 @@
986 a
990 a
987 -5
991 -5
988 +m1
992 +m1
989 +m2
993 +m2
990 diff --git a/b b/b
994 diff --git a/b b/b
991 deleted file mode 100644
995 deleted file mode 100644
992 --- a/b
996 --- a/b
993 +++ /dev/null
997 +++ /dev/null
994 @@ -1,2 +0,0 @@
998 @@ -1,2 +0,0 @@
995 -a
999 -a
996 -5
1000 -5
997 diff --git a/c b/c
1001 diff --git a/c b/c
998 deleted file mode 100644
1002 deleted file mode 100644
999 --- a/c
1003 --- a/c
1000 +++ /dev/null
1004 +++ /dev/null
1001 @@ -1,2 +0,0 @@
1005 @@ -1,2 +0,0 @@
1002 -a
1006 -a
1003 -5
1007 -5
1004 diff --git a/x/y b/x/y
1008 diff --git a/x/y b/x/y
1005 new file mode 100644
1009 new file mode 100644
1006 --- /dev/null
1010 --- /dev/null
1007 +++ b/x/y
1011 +++ b/x/y
1008 @@ -0,0 +1,1 @@
1012 @@ -0,0 +1,1 @@
1009 +y1
1013 +y1
1010
1014
1011
1015
1012 $ tb "add a a1" "hg mv a b" "hg mv b a" "circular rename"
1016 $ tb "add a a1" "hg mv a b" "hg mv b a" "circular rename"
1013 updating to branch default
1017 updating to branch default
1014 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
1018 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
1015 created new head
1019 created new head
1016 ** circular rename **
1020 ** circular rename **
1017 ** add a a1 / hg mv a b / hg mv b a
1021 ** add a a1 / hg mv a b / hg mv b a
1018 - working to parent:
1022 - working to parent:
1019 A a
1023 A a
1020 b
1024 b
1021 R b
1025 R b
1022
1026
1023 diff --git a/b b/a
1027 diff --git a/b b/a
1024 rename from b
1028 rename from b
1025 rename to a
1029 rename to a
1026
1030
1027 - working to root: --rev 0
1031 - working to root: --rev 0
1028 M a
1032 M a
1029
1033
1030 diff --git a/a b/a
1034 diff --git a/a b/a
1031 --- a/a
1035 --- a/a
1032 +++ b/a
1036 +++ b/a
1033 @@ -1,1 +1,3 @@
1037 @@ -1,1 +1,3 @@
1034 a
1038 a
1035 +6
1039 +6
1036 +a1
1040 +a1
1037
1041
1038 - working to branch: --rev 2
1042 - working to branch: --rev 2
1039 M a
1043 M a
1040 R x/y
1044 R x/y
1041
1045
1042 diff --git a/a b/a
1046 diff --git a/a b/a
1043 --- a/a
1047 --- a/a
1044 +++ b/a
1048 +++ b/a
1045 @@ -1,3 +1,3 @@
1049 @@ -1,3 +1,3 @@
1046 a
1050 a
1047 -m1
1051 -m1
1048 -m2
1052 -m2
1049 +6
1053 +6
1050 +a1
1054 +a1
1051 diff --git a/x/y b/x/y
1055 diff --git a/x/y b/x/y
1052 deleted file mode 100644
1056 deleted file mode 100644
1053 --- a/x/y
1057 --- a/x/y
1054 +++ /dev/null
1058 +++ /dev/null
1055 @@ -1,1 +0,0 @@
1059 @@ -1,1 +0,0 @@
1056 -y1
1060 -y1
1057
1061
1058 - root to parent: --rev 0 --rev .
1062 - root to parent: --rev 0 --rev .
1059 A b
1063 A b
1060 a
1064 a
1061 R a
1065 R a
1062
1066
1063 diff --git a/a b/b
1067 diff --git a/a b/b
1064 rename from a
1068 rename from a
1065 rename to b
1069 rename to b
1066 --- a/a
1070 --- a/a
1067 +++ b/b
1071 +++ b/b
1068 @@ -1,1 +1,3 @@
1072 @@ -1,1 +1,3 @@
1069 a
1073 a
1070 +6
1074 +6
1071 +a1
1075 +a1
1072
1076
1073 - parent to root: --rev . --rev 0
1077 - parent to root: --rev . --rev 0
1074 A a
1078 A a
1075 b
1079 b
1076 R b
1080 R b
1077
1081
1078 diff --git a/b b/a
1082 diff --git a/b b/a
1079 rename from b
1083 rename from b
1080 rename to a
1084 rename to a
1081 --- a/b
1085 --- a/b
1082 +++ b/a
1086 +++ b/a
1083 @@ -1,3 +1,1 @@
1087 @@ -1,3 +1,1 @@
1084 a
1088 a
1085 -6
1089 -6
1086 -a1
1090 -a1
1087
1091
1088 - branch to parent: --rev 2 --rev .
1092 - branch to parent: --rev 2 --rev .
1089 A b
1093 A b
1090 a
1094 a
1091 R a
1095 R a
1092 R x/y
1096 R x/y
1093
1097
1094 diff --git a/a b/b
1098 diff --git a/a b/b
1095 rename from a
1099 rename from a
1096 rename to b
1100 rename to b
1097 --- a/a
1101 --- a/a
1098 +++ b/b
1102 +++ b/b
1099 @@ -1,3 +1,3 @@
1103 @@ -1,3 +1,3 @@
1100 a
1104 a
1101 -m1
1105 -m1
1102 -m2
1106 -m2
1103 +6
1107 +6
1104 +a1
1108 +a1
1105 diff --git a/x/y b/x/y
1109 diff --git a/x/y b/x/y
1106 deleted file mode 100644
1110 deleted file mode 100644
1107 --- a/x/y
1111 --- a/x/y
1108 +++ /dev/null
1112 +++ /dev/null
1109 @@ -1,1 +0,0 @@
1113 @@ -1,1 +0,0 @@
1110 -y1
1114 -y1
1111
1115
1112 - parent to branch: --rev . --rev 2
1116 - parent to branch: --rev . --rev 2
1113 A a
1117 A a
1114 b
1118 b
1115 A x/y
1119 A x/y
1116 R b
1120 R b
1117
1121
1118 diff --git a/b b/a
1122 diff --git a/b b/a
1119 rename from b
1123 rename from b
1120 rename to a
1124 rename to a
1121 --- a/b
1125 --- a/b
1122 +++ b/a
1126 +++ b/a
1123 @@ -1,3 +1,3 @@
1127 @@ -1,3 +1,3 @@
1124 a
1128 a
1125 -6
1129 -6
1126 -a1
1130 -a1
1127 +m1
1131 +m1
1128 +m2
1132 +m2
1129 diff --git a/x/y b/x/y
1133 diff --git a/x/y b/x/y
1130 new file mode 100644
1134 new file mode 100644
1131 --- /dev/null
1135 --- /dev/null
1132 +++ b/x/y
1136 +++ b/x/y
1133 @@ -0,0 +1,1 @@
1137 @@ -0,0 +1,1 @@
1134 +y1
1138 +y1
1135
1139
1136
1140
1137 $ tb "hg mv x y" "add y/x x1" "add y/x x2" "directory move"
1141 $ tb "hg mv x y" "add y/x x1" "add y/x x2" "directory move"
1138 updating to branch default
1142 updating to branch default
1139 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
1143 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
1140 created new head
1144 created new head
1141 moving x/x to y/x (glob)
1145 moving x/x to y/x (glob)
1142 ** directory move **
1146 ** directory move **
1143 ** hg mv x y / add y/x x1 / add y/x x2
1147 ** hg mv x y / add y/x x1 / add y/x x2
1144 - working to parent:
1148 - working to parent:
1145 M y/x
1149 M y/x
1146
1150
1147 diff --git a/y/x b/y/x
1151 diff --git a/y/x b/y/x
1148 --- a/y/x
1152 --- a/y/x
1149 +++ b/y/x
1153 +++ b/y/x
1150 @@ -1,2 +1,3 @@
1154 @@ -1,2 +1,3 @@
1151 x
1155 x
1152 x1
1156 x1
1153 +x2
1157 +x2
1154
1158
1155 - working to root: --rev 0
1159 - working to root: --rev 0
1156 M a
1160 M a
1157 A y/x
1161 A y/x
1158 x/x
1162 x/x
1159 R x/x
1163 R x/x
1160
1164
1161 diff --git a/a b/a
1165 diff --git a/a b/a
1162 --- a/a
1166 --- a/a
1163 +++ b/a
1167 +++ b/a
1164 @@ -1,1 +1,2 @@
1168 @@ -1,1 +1,2 @@
1165 a
1169 a
1166 +7
1170 +7
1167 diff --git a/x/x b/y/x
1171 diff --git a/x/x b/y/x
1168 rename from x/x
1172 rename from x/x
1169 rename to y/x
1173 rename to y/x
1170 --- a/x/x
1174 --- a/x/x
1171 +++ b/y/x
1175 +++ b/y/x
1172 @@ -1,1 +1,3 @@
1176 @@ -1,1 +1,3 @@
1173 x
1177 x
1174 +x1
1178 +x1
1175 +x2
1179 +x2
1176
1180
1177 - working to branch: --rev 2
1181 - working to branch: --rev 2
1178 M a
1182 M a
1179 A y/x
1183 A y/x
1180 x/x
1184 x/x
1181 R x/x
1185 R x/x
1182 R x/y
1186 R x/y
1183
1187
1184 diff --git a/a b/a
1188 diff --git a/a b/a
1185 --- a/a
1189 --- a/a
1186 +++ b/a
1190 +++ b/a
1187 @@ -1,3 +1,2 @@
1191 @@ -1,3 +1,2 @@
1188 a
1192 a
1189 -m1
1193 -m1
1190 -m2
1194 -m2
1191 +7
1195 +7
1192 diff --git a/x/y b/x/y
1196 diff --git a/x/y b/x/y
1193 deleted file mode 100644
1197 deleted file mode 100644
1194 --- a/x/y
1198 --- a/x/y
1195 +++ /dev/null
1199 +++ /dev/null
1196 @@ -1,1 +0,0 @@
1200 @@ -1,1 +0,0 @@
1197 -y1
1201 -y1
1198 diff --git a/x/x b/y/x
1202 diff --git a/x/x b/y/x
1199 rename from x/x
1203 rename from x/x
1200 rename to y/x
1204 rename to y/x
1201 --- a/x/x
1205 --- a/x/x
1202 +++ b/y/x
1206 +++ b/y/x
1203 @@ -1,1 +1,3 @@
1207 @@ -1,1 +1,3 @@
1204 x
1208 x
1205 +x1
1209 +x1
1206 +x2
1210 +x2
1207
1211
1208 - root to parent: --rev 0 --rev .
1212 - root to parent: --rev 0 --rev .
1209 M a
1213 M a
1210 A y/x
1214 A y/x
1211 x/x
1215 x/x
1212 R x/x
1216 R x/x
1213
1217
1214 diff --git a/a b/a
1218 diff --git a/a b/a
1215 --- a/a
1219 --- a/a
1216 +++ b/a
1220 +++ b/a
1217 @@ -1,1 +1,2 @@
1221 @@ -1,1 +1,2 @@
1218 a
1222 a
1219 +7
1223 +7
1220 diff --git a/x/x b/y/x
1224 diff --git a/x/x b/y/x
1221 rename from x/x
1225 rename from x/x
1222 rename to y/x
1226 rename to y/x
1223 --- a/x/x
1227 --- a/x/x
1224 +++ b/y/x
1228 +++ b/y/x
1225 @@ -1,1 +1,2 @@
1229 @@ -1,1 +1,2 @@
1226 x
1230 x
1227 +x1
1231 +x1
1228
1232
1229 - parent to root: --rev . --rev 0
1233 - parent to root: --rev . --rev 0
1230 M a
1234 M a
1231 A x/x
1235 A x/x
1232 y/x
1236 y/x
1233 R y/x
1237 R y/x
1234
1238
1235 diff --git a/a b/a
1239 diff --git a/a b/a
1236 --- a/a
1240 --- a/a
1237 +++ b/a
1241 +++ b/a
1238 @@ -1,2 +1,1 @@
1242 @@ -1,2 +1,1 @@
1239 a
1243 a
1240 -7
1244 -7
1241 diff --git a/y/x b/x/x
1245 diff --git a/y/x b/x/x
1242 rename from y/x
1246 rename from y/x
1243 rename to x/x
1247 rename to x/x
1244 --- a/y/x
1248 --- a/y/x
1245 +++ b/x/x
1249 +++ b/x/x
1246 @@ -1,2 +1,1 @@
1250 @@ -1,2 +1,1 @@
1247 x
1251 x
1248 -x1
1252 -x1
1249
1253
1250 - branch to parent: --rev 2 --rev .
1254 - branch to parent: --rev 2 --rev .
1251 M a
1255 M a
1252 A y/x
1256 A y/x
1253 x/x
1257 x/x
1254 R x/x
1258 R x/x
1255 R x/y
1259 R x/y
1256
1260
1257 diff --git a/a b/a
1261 diff --git a/a b/a
1258 --- a/a
1262 --- a/a
1259 +++ b/a
1263 +++ b/a
1260 @@ -1,3 +1,2 @@
1264 @@ -1,3 +1,2 @@
1261 a
1265 a
1262 -m1
1266 -m1
1263 -m2
1267 -m2
1264 +7
1268 +7
1265 diff --git a/x/y b/x/y
1269 diff --git a/x/y b/x/y
1266 deleted file mode 100644
1270 deleted file mode 100644
1267 --- a/x/y
1271 --- a/x/y
1268 +++ /dev/null
1272 +++ /dev/null
1269 @@ -1,1 +0,0 @@
1273 @@ -1,1 +0,0 @@
1270 -y1
1274 -y1
1271 diff --git a/x/x b/y/x
1275 diff --git a/x/x b/y/x
1272 rename from x/x
1276 rename from x/x
1273 rename to y/x
1277 rename to y/x
1274 --- a/x/x
1278 --- a/x/x
1275 +++ b/y/x
1279 +++ b/y/x
1276 @@ -1,1 +1,2 @@
1280 @@ -1,1 +1,2 @@
1277 x
1281 x
1278 +x1
1282 +x1
1279
1283
1280 - parent to branch: --rev . --rev 2
1284 - parent to branch: --rev . --rev 2
1281 M a
1285 M a
1282 A x/x
1286 A x/x
1283 y/x
1287 y/x
1284 A x/y
1288 A x/y
1285 R y/x
1289 R y/x
1286
1290
1287 diff --git a/a b/a
1291 diff --git a/a b/a
1288 --- a/a
1292 --- a/a
1289 +++ b/a
1293 +++ b/a
1290 @@ -1,2 +1,3 @@
1294 @@ -1,2 +1,3 @@
1291 a
1295 a
1292 -7
1296 -7
1293 +m1
1297 +m1
1294 +m2
1298 +m2
1295 diff --git a/y/x b/x/x
1299 diff --git a/y/x b/x/x
1296 rename from y/x
1300 rename from y/x
1297 rename to x/x
1301 rename to x/x
1298 --- a/y/x
1302 --- a/y/x
1299 +++ b/x/x
1303 +++ b/x/x
1300 @@ -1,2 +1,1 @@
1304 @@ -1,2 +1,1 @@
1301 x
1305 x
1302 -x1
1306 -x1
1303 diff --git a/x/y b/x/y
1307 diff --git a/x/y b/x/y
1304 new file mode 100644
1308 new file mode 100644
1305 --- /dev/null
1309 --- /dev/null
1306 +++ b/x/y
1310 +++ b/x/y
1307 @@ -0,0 +1,1 @@
1311 @@ -0,0 +1,1 @@
1308 +y1
1312 +y1
1309
1313
1310
1314
1311
1315
1312 Cannot implement unrelated branch with tb
1316 Cannot implement unrelated branch with tb
1313 testing copies with unrelated branch
1317 testing copies with unrelated branch
1314
1318
1315 $ hg init unrelated
1319 $ hg init unrelated
1316 $ cd unrelated
1320 $ cd unrelated
1317 $ add a a
1321 $ add a a
1318 $ hg ci -Am adda
1322 $ hg ci -Am adda
1319 adding a
1323 adding a
1320 $ hg mv a b
1324 $ hg mv a b
1321 $ hg ci -m movea
1325 $ hg ci -m movea
1322 $ hg up -C null
1326 $ hg up -C null
1323 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1327 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1324 $ add a a
1328 $ add a a
1325 $ hg ci -Am addunrelateda
1329 $ hg ci -Am addunrelateda
1326 adding a
1330 adding a
1327 created new head
1331 created new head
1328
1332
1329 unrelated branch diff
1333 unrelated branch diff
1330
1334
1331 $ hg diff --git -r 2 -r 1
1335 $ hg diff --git -r 2 -r 1
1332 diff --git a/a b/a
1336 diff --git a/a b/a
1333 deleted file mode 100644
1337 deleted file mode 100644
1334 --- a/a
1338 --- a/a
1335 +++ /dev/null
1339 +++ /dev/null
1336 @@ -1,1 +0,0 @@
1340 @@ -1,1 +0,0 @@
1337 -a
1341 -a
1338 diff --git a/b b/b
1342 diff --git a/b b/b
1339 new file mode 100644
1343 new file mode 100644
1340 --- /dev/null
1344 --- /dev/null
1341 +++ b/b
1345 +++ b/b
1342 @@ -0,0 +1,1 @@
1346 @@ -0,0 +1,1 @@
1343 +a
1347 +a
1344 $ cd ..
1348 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now