##// END OF EJS Templates
forget: support forgetting explicit paths in subrepos...
David M. Carr -
r15474:95174c38 default
parent child Browse files
Show More
@@ -1,5643 +1,5666 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 merge as mergemod
17 import merge as mergemod
17 import minirst, revset, fileset
18 import minirst, revset, fileset
18 import dagparser, context, simplemerge
19 import dagparser, context, simplemerge
19 import random, setdiscovery, treediscovery, dagutil
20 import random, setdiscovery, treediscovery, dagutil
20
21
21 table = {}
22 table = {}
22
23
23 command = cmdutil.command(table)
24 command = cmdutil.command(table)
24
25
25 # common command options
26 # common command options
26
27
27 globalopts = [
28 globalopts = [
28 ('R', 'repository', '',
29 ('R', 'repository', '',
29 _('repository root directory or name of overlay bundle file'),
30 _('repository root directory or name of overlay bundle file'),
30 _('REPO')),
31 _('REPO')),
31 ('', 'cwd', '',
32 ('', 'cwd', '',
32 _('change working directory'), _('DIR')),
33 _('change working directory'), _('DIR')),
33 ('y', 'noninteractive', None,
34 ('y', 'noninteractive', None,
34 _('do not prompt, automatically pick the first choice for all prompts')),
35 _('do not prompt, automatically pick the first choice for all prompts')),
35 ('q', 'quiet', None, _('suppress output')),
36 ('q', 'quiet', None, _('suppress output')),
36 ('v', 'verbose', None, _('enable additional output')),
37 ('v', 'verbose', None, _('enable additional output')),
37 ('', 'config', [],
38 ('', 'config', [],
38 _('set/override config option (use \'section.name=value\')'),
39 _('set/override config option (use \'section.name=value\')'),
39 _('CONFIG')),
40 _('CONFIG')),
40 ('', 'debug', None, _('enable debugging output')),
41 ('', 'debug', None, _('enable debugging output')),
41 ('', 'debugger', None, _('start debugger')),
42 ('', 'debugger', None, _('start debugger')),
42 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
43 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
43 _('ENCODE')),
44 _('ENCODE')),
44 ('', 'encodingmode', encoding.encodingmode,
45 ('', 'encodingmode', encoding.encodingmode,
45 _('set the charset encoding mode'), _('MODE')),
46 _('set the charset encoding mode'), _('MODE')),
46 ('', 'traceback', None, _('always print a traceback on exception')),
47 ('', 'traceback', None, _('always print a traceback on exception')),
47 ('', 'time', None, _('time how long the command takes')),
48 ('', 'time', None, _('time how long the command takes')),
48 ('', 'profile', None, _('print command execution profile')),
49 ('', 'profile', None, _('print command execution profile')),
49 ('', 'version', None, _('output version information and exit')),
50 ('', 'version', None, _('output version information and exit')),
50 ('h', 'help', None, _('display help and exit')),
51 ('h', 'help', None, _('display help and exit')),
51 ]
52 ]
52
53
53 dryrunopts = [('n', 'dry-run', None,
54 dryrunopts = [('n', 'dry-run', None,
54 _('do not perform actions, just print output'))]
55 _('do not perform actions, just print output'))]
55
56
56 remoteopts = [
57 remoteopts = [
57 ('e', 'ssh', '',
58 ('e', 'ssh', '',
58 _('specify ssh command to use'), _('CMD')),
59 _('specify ssh command to use'), _('CMD')),
59 ('', 'remotecmd', '',
60 ('', 'remotecmd', '',
60 _('specify hg command to run on the remote side'), _('CMD')),
61 _('specify hg command to run on the remote side'), _('CMD')),
61 ('', 'insecure', None,
62 ('', 'insecure', None,
62 _('do not verify server certificate (ignoring web.cacerts config)')),
63 _('do not verify server certificate (ignoring web.cacerts config)')),
63 ]
64 ]
64
65
65 walkopts = [
66 walkopts = [
66 ('I', 'include', [],
67 ('I', 'include', [],
67 _('include names matching the given patterns'), _('PATTERN')),
68 _('include names matching the given patterns'), _('PATTERN')),
68 ('X', 'exclude', [],
69 ('X', 'exclude', [],
69 _('exclude names matching the given patterns'), _('PATTERN')),
70 _('exclude names matching the given patterns'), _('PATTERN')),
70 ]
71 ]
71
72
72 commitopts = [
73 commitopts = [
73 ('m', 'message', '',
74 ('m', 'message', '',
74 _('use text as commit message'), _('TEXT')),
75 _('use text as commit message'), _('TEXT')),
75 ('l', 'logfile', '',
76 ('l', 'logfile', '',
76 _('read commit message from file'), _('FILE')),
77 _('read commit message from file'), _('FILE')),
77 ]
78 ]
78
79
79 commitopts2 = [
80 commitopts2 = [
80 ('d', 'date', '',
81 ('d', 'date', '',
81 _('record the specified date as commit date'), _('DATE')),
82 _('record the specified date as commit date'), _('DATE')),
82 ('u', 'user', '',
83 ('u', 'user', '',
83 _('record the specified user as committer'), _('USER')),
84 _('record the specified user as committer'), _('USER')),
84 ]
85 ]
85
86
86 templateopts = [
87 templateopts = [
87 ('', 'style', '',
88 ('', 'style', '',
88 _('display using template map file'), _('STYLE')),
89 _('display using template map file'), _('STYLE')),
89 ('', 'template', '',
90 ('', 'template', '',
90 _('display with template'), _('TEMPLATE')),
91 _('display with template'), _('TEMPLATE')),
91 ]
92 ]
92
93
93 logopts = [
94 logopts = [
94 ('p', 'patch', None, _('show patch')),
95 ('p', 'patch', None, _('show patch')),
95 ('g', 'git', None, _('use git extended diff format')),
96 ('g', 'git', None, _('use git extended diff format')),
96 ('l', 'limit', '',
97 ('l', 'limit', '',
97 _('limit number of changes displayed'), _('NUM')),
98 _('limit number of changes displayed'), _('NUM')),
98 ('M', 'no-merges', None, _('do not show merges')),
99 ('M', 'no-merges', None, _('do not show merges')),
99 ('', 'stat', None, _('output diffstat-style summary of changes')),
100 ('', 'stat', None, _('output diffstat-style summary of changes')),
100 ] + templateopts
101 ] + templateopts
101
102
102 diffopts = [
103 diffopts = [
103 ('a', 'text', None, _('treat all files as text')),
104 ('a', 'text', None, _('treat all files as text')),
104 ('g', 'git', None, _('use git extended diff format')),
105 ('g', 'git', None, _('use git extended diff format')),
105 ('', 'nodates', None, _('omit dates from diff headers'))
106 ('', 'nodates', None, _('omit dates from diff headers'))
106 ]
107 ]
107
108
108 diffopts2 = [
109 diffopts2 = [
109 ('p', 'show-function', None, _('show which function each change is in')),
110 ('p', 'show-function', None, _('show which function each change is in')),
110 ('', 'reverse', None, _('produce a diff that undoes the changes')),
111 ('', 'reverse', None, _('produce a diff that undoes the changes')),
111 ('w', 'ignore-all-space', None,
112 ('w', 'ignore-all-space', None,
112 _('ignore white space when comparing lines')),
113 _('ignore white space when comparing lines')),
113 ('b', 'ignore-space-change', None,
114 ('b', 'ignore-space-change', None,
114 _('ignore changes in the amount of white space')),
115 _('ignore changes in the amount of white space')),
115 ('B', 'ignore-blank-lines', None,
116 ('B', 'ignore-blank-lines', None,
116 _('ignore changes whose lines are all blank')),
117 _('ignore changes whose lines are all blank')),
117 ('U', 'unified', '',
118 ('U', 'unified', '',
118 _('number of lines of context to show'), _('NUM')),
119 _('number of lines of context to show'), _('NUM')),
119 ('', 'stat', None, _('output diffstat-style summary of changes')),
120 ('', 'stat', None, _('output diffstat-style summary of changes')),
120 ]
121 ]
121
122
122 mergetoolopts = [
123 mergetoolopts = [
123 ('t', 'tool', '', _('specify merge tool')),
124 ('t', 'tool', '', _('specify merge tool')),
124 ]
125 ]
125
126
126 similarityopts = [
127 similarityopts = [
127 ('s', 'similarity', '',
128 ('s', 'similarity', '',
128 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
129 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
129 ]
130 ]
130
131
131 subrepoopts = [
132 subrepoopts = [
132 ('S', 'subrepos', None,
133 ('S', 'subrepos', None,
133 _('recurse into subrepositories'))
134 _('recurse into subrepositories'))
134 ]
135 ]
135
136
136 # Commands start here, listed alphabetically
137 # Commands start here, listed alphabetically
137
138
138 @command('^add',
139 @command('^add',
139 walkopts + subrepoopts + dryrunopts,
140 walkopts + subrepoopts + dryrunopts,
140 _('[OPTION]... [FILE]...'))
141 _('[OPTION]... [FILE]...'))
141 def add(ui, repo, *pats, **opts):
142 def add(ui, repo, *pats, **opts):
142 """add the specified files on the next commit
143 """add the specified files on the next commit
143
144
144 Schedule files to be version controlled and added to the
145 Schedule files to be version controlled and added to the
145 repository.
146 repository.
146
147
147 The files will be added to the repository at the next commit. To
148 The files will be added to the repository at the next commit. To
148 undo an add before that, see :hg:`forget`.
149 undo an add before that, see :hg:`forget`.
149
150
150 If no names are given, add all files to the repository.
151 If no names are given, add all files to the repository.
151
152
152 .. container:: verbose
153 .. container:: verbose
153
154
154 An example showing how new (unknown) files are added
155 An example showing how new (unknown) files are added
155 automatically by :hg:`add`::
156 automatically by :hg:`add`::
156
157
157 $ ls
158 $ ls
158 foo.c
159 foo.c
159 $ hg status
160 $ hg status
160 ? foo.c
161 ? foo.c
161 $ hg add
162 $ hg add
162 adding foo.c
163 adding foo.c
163 $ hg status
164 $ hg status
164 A foo.c
165 A foo.c
165
166
166 Returns 0 if all files are successfully added.
167 Returns 0 if all files are successfully added.
167 """
168 """
168
169
169 m = scmutil.match(repo[None], pats, opts)
170 m = scmutil.match(repo[None], pats, opts)
170 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
171 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
171 opts.get('subrepos'), prefix="")
172 opts.get('subrepos'), prefix="")
172 return rejected and 1 or 0
173 return rejected and 1 or 0
173
174
174 @command('addremove',
175 @command('addremove',
175 similarityopts + walkopts + dryrunopts,
176 similarityopts + walkopts + dryrunopts,
176 _('[OPTION]... [FILE]...'))
177 _('[OPTION]... [FILE]...'))
177 def addremove(ui, repo, *pats, **opts):
178 def addremove(ui, repo, *pats, **opts):
178 """add all new files, delete all missing files
179 """add all new files, delete all missing files
179
180
180 Add all new files and remove all missing files from the
181 Add all new files and remove all missing files from the
181 repository.
182 repository.
182
183
183 New files are ignored if they match any of the patterns in
184 New files are ignored if they match any of the patterns in
184 ``.hgignore``. As with add, these changes take effect at the next
185 ``.hgignore``. As with add, these changes take effect at the next
185 commit.
186 commit.
186
187
187 Use the -s/--similarity option to detect renamed files. With a
188 Use the -s/--similarity option to detect renamed files. With a
188 parameter greater than 0, this compares every removed file with
189 parameter greater than 0, this compares every removed file with
189 every added file and records those similar enough as renames. This
190 every added file and records those similar enough as renames. This
190 option takes a percentage between 0 (disabled) and 100 (files must
191 option takes a percentage between 0 (disabled) and 100 (files must
191 be identical) as its parameter. Detecting renamed files this way
192 be identical) as its parameter. Detecting renamed files this way
192 can be expensive. After using this option, :hg:`status -C` can be
193 can be expensive. After using this option, :hg:`status -C` can be
193 used to check which files were identified as moved or renamed.
194 used to check which files were identified as moved or renamed.
194
195
195 Returns 0 if all files are successfully added.
196 Returns 0 if all files are successfully added.
196 """
197 """
197 try:
198 try:
198 sim = float(opts.get('similarity') or 100)
199 sim = float(opts.get('similarity') or 100)
199 except ValueError:
200 except ValueError:
200 raise util.Abort(_('similarity must be a number'))
201 raise util.Abort(_('similarity must be a number'))
201 if sim < 0 or sim > 100:
202 if sim < 0 or sim > 100:
202 raise util.Abort(_('similarity must be between 0 and 100'))
203 raise util.Abort(_('similarity must be between 0 and 100'))
203 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
204 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
204
205
205 @command('^annotate|blame',
206 @command('^annotate|blame',
206 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
207 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
207 ('', 'follow', None,
208 ('', 'follow', None,
208 _('follow copies/renames and list the filename (DEPRECATED)')),
209 _('follow copies/renames and list the filename (DEPRECATED)')),
209 ('', 'no-follow', None, _("don't follow copies and renames")),
210 ('', 'no-follow', None, _("don't follow copies and renames")),
210 ('a', 'text', None, _('treat all files as text')),
211 ('a', 'text', None, _('treat all files as text')),
211 ('u', 'user', None, _('list the author (long with -v)')),
212 ('u', 'user', None, _('list the author (long with -v)')),
212 ('f', 'file', None, _('list the filename')),
213 ('f', 'file', None, _('list the filename')),
213 ('d', 'date', None, _('list the date (short with -q)')),
214 ('d', 'date', None, _('list the date (short with -q)')),
214 ('n', 'number', None, _('list the revision number (default)')),
215 ('n', 'number', None, _('list the revision number (default)')),
215 ('c', 'changeset', None, _('list the changeset')),
216 ('c', 'changeset', None, _('list the changeset')),
216 ('l', 'line-number', None, _('show line number at the first appearance'))
217 ('l', 'line-number', None, _('show line number at the first appearance'))
217 ] + walkopts,
218 ] + walkopts,
218 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
219 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
219 def annotate(ui, repo, *pats, **opts):
220 def annotate(ui, repo, *pats, **opts):
220 """show changeset information by line for each file
221 """show changeset information by line for each file
221
222
222 List changes in files, showing the revision id responsible for
223 List changes in files, showing the revision id responsible for
223 each line
224 each line
224
225
225 This command is useful for discovering when a change was made and
226 This command is useful for discovering when a change was made and
226 by whom.
227 by whom.
227
228
228 Without the -a/--text option, annotate will avoid processing files
229 Without the -a/--text option, annotate will avoid processing files
229 it detects as binary. With -a, annotate will annotate the file
230 it detects as binary. With -a, annotate will annotate the file
230 anyway, although the results will probably be neither useful
231 anyway, although the results will probably be neither useful
231 nor desirable.
232 nor desirable.
232
233
233 Returns 0 on success.
234 Returns 0 on success.
234 """
235 """
235 if opts.get('follow'):
236 if opts.get('follow'):
236 # --follow is deprecated and now just an alias for -f/--file
237 # --follow is deprecated and now just an alias for -f/--file
237 # to mimic the behavior of Mercurial before version 1.5
238 # to mimic the behavior of Mercurial before version 1.5
238 opts['file'] = True
239 opts['file'] = True
239
240
240 datefunc = ui.quiet and util.shortdate or util.datestr
241 datefunc = ui.quiet and util.shortdate or util.datestr
241 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
242 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
242
243
243 if not pats:
244 if not pats:
244 raise util.Abort(_('at least one filename or pattern is required'))
245 raise util.Abort(_('at least one filename or pattern is required'))
245
246
246 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
247 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
247 ('number', ' ', lambda x: str(x[0].rev())),
248 ('number', ' ', lambda x: str(x[0].rev())),
248 ('changeset', ' ', lambda x: short(x[0].node())),
249 ('changeset', ' ', lambda x: short(x[0].node())),
249 ('date', ' ', getdate),
250 ('date', ' ', getdate),
250 ('file', ' ', lambda x: x[0].path()),
251 ('file', ' ', lambda x: x[0].path()),
251 ('line_number', ':', lambda x: str(x[1])),
252 ('line_number', ':', lambda x: str(x[1])),
252 ]
253 ]
253
254
254 if (not opts.get('user') and not opts.get('changeset')
255 if (not opts.get('user') and not opts.get('changeset')
255 and not opts.get('date') and not opts.get('file')):
256 and not opts.get('date') and not opts.get('file')):
256 opts['number'] = True
257 opts['number'] = True
257
258
258 linenumber = opts.get('line_number') is not None
259 linenumber = opts.get('line_number') is not None
259 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
260 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
260 raise util.Abort(_('at least one of -n/-c is required for -l'))
261 raise util.Abort(_('at least one of -n/-c is required for -l'))
261
262
262 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
263 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
263 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
264 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
264
265
265 def bad(x, y):
266 def bad(x, y):
266 raise util.Abort("%s: %s" % (x, y))
267 raise util.Abort("%s: %s" % (x, y))
267
268
268 ctx = scmutil.revsingle(repo, opts.get('rev'))
269 ctx = scmutil.revsingle(repo, opts.get('rev'))
269 m = scmutil.match(ctx, pats, opts)
270 m = scmutil.match(ctx, pats, opts)
270 m.bad = bad
271 m.bad = bad
271 follow = not opts.get('no_follow')
272 follow = not opts.get('no_follow')
272 for abs in ctx.walk(m):
273 for abs in ctx.walk(m):
273 fctx = ctx[abs]
274 fctx = ctx[abs]
274 if not opts.get('text') and util.binary(fctx.data()):
275 if not opts.get('text') and util.binary(fctx.data()):
275 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
276 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
276 continue
277 continue
277
278
278 lines = fctx.annotate(follow=follow, linenumber=linenumber)
279 lines = fctx.annotate(follow=follow, linenumber=linenumber)
279 pieces = []
280 pieces = []
280
281
281 for f, sep in funcmap:
282 for f, sep in funcmap:
282 l = [f(n) for n, dummy in lines]
283 l = [f(n) for n, dummy in lines]
283 if l:
284 if l:
284 sized = [(x, encoding.colwidth(x)) for x in l]
285 sized = [(x, encoding.colwidth(x)) for x in l]
285 ml = max([w for x, w in sized])
286 ml = max([w for x, w in sized])
286 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
287 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
287 for x, w in sized])
288 for x, w in sized])
288
289
289 if pieces:
290 if pieces:
290 for p, l in zip(zip(*pieces), lines):
291 for p, l in zip(zip(*pieces), lines):
291 ui.write("%s: %s" % ("".join(p), l[1]))
292 ui.write("%s: %s" % ("".join(p), l[1]))
292
293
293 @command('archive',
294 @command('archive',
294 [('', 'no-decode', None, _('do not pass files through decoders')),
295 [('', 'no-decode', None, _('do not pass files through decoders')),
295 ('p', 'prefix', '', _('directory prefix for files in archive'),
296 ('p', 'prefix', '', _('directory prefix for files in archive'),
296 _('PREFIX')),
297 _('PREFIX')),
297 ('r', 'rev', '', _('revision to distribute'), _('REV')),
298 ('r', 'rev', '', _('revision to distribute'), _('REV')),
298 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
299 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
299 ] + subrepoopts + walkopts,
300 ] + subrepoopts + walkopts,
300 _('[OPTION]... DEST'))
301 _('[OPTION]... DEST'))
301 def archive(ui, repo, dest, **opts):
302 def archive(ui, repo, dest, **opts):
302 '''create an unversioned archive of a repository revision
303 '''create an unversioned archive of a repository revision
303
304
304 By default, the revision used is the parent of the working
305 By default, the revision used is the parent of the working
305 directory; use -r/--rev to specify a different revision.
306 directory; use -r/--rev to specify a different revision.
306
307
307 The archive type is automatically detected based on file
308 The archive type is automatically detected based on file
308 extension (or override using -t/--type).
309 extension (or override using -t/--type).
309
310
310 .. container:: verbose
311 .. container:: verbose
311
312
312 Examples:
313 Examples:
313
314
314 - create a zip file containing the 1.0 release::
315 - create a zip file containing the 1.0 release::
315
316
316 hg archive -r 1.0 project-1.0.zip
317 hg archive -r 1.0 project-1.0.zip
317
318
318 - create a tarball excluding .hg files::
319 - create a tarball excluding .hg files::
319
320
320 hg archive project.tar.gz -X ".hg*"
321 hg archive project.tar.gz -X ".hg*"
321
322
322 Valid types are:
323 Valid types are:
323
324
324 :``files``: a directory full of files (default)
325 :``files``: a directory full of files (default)
325 :``tar``: tar archive, uncompressed
326 :``tar``: tar archive, uncompressed
326 :``tbz2``: tar archive, compressed using bzip2
327 :``tbz2``: tar archive, compressed using bzip2
327 :``tgz``: tar archive, compressed using gzip
328 :``tgz``: tar archive, compressed using gzip
328 :``uzip``: zip archive, uncompressed
329 :``uzip``: zip archive, uncompressed
329 :``zip``: zip archive, compressed using deflate
330 :``zip``: zip archive, compressed using deflate
330
331
331 The exact name of the destination archive or directory is given
332 The exact name of the destination archive or directory is given
332 using a format string; see :hg:`help export` for details.
333 using a format string; see :hg:`help export` for details.
333
334
334 Each member added to an archive file has a directory prefix
335 Each member added to an archive file has a directory prefix
335 prepended. Use -p/--prefix to specify a format string for the
336 prepended. Use -p/--prefix to specify a format string for the
336 prefix. The default is the basename of the archive, with suffixes
337 prefix. The default is the basename of the archive, with suffixes
337 removed.
338 removed.
338
339
339 Returns 0 on success.
340 Returns 0 on success.
340 '''
341 '''
341
342
342 ctx = scmutil.revsingle(repo, opts.get('rev'))
343 ctx = scmutil.revsingle(repo, opts.get('rev'))
343 if not ctx:
344 if not ctx:
344 raise util.Abort(_('no working directory: please specify a revision'))
345 raise util.Abort(_('no working directory: please specify a revision'))
345 node = ctx.node()
346 node = ctx.node()
346 dest = cmdutil.makefilename(repo, dest, node)
347 dest = cmdutil.makefilename(repo, dest, node)
347 if os.path.realpath(dest) == repo.root:
348 if os.path.realpath(dest) == repo.root:
348 raise util.Abort(_('repository root cannot be destination'))
349 raise util.Abort(_('repository root cannot be destination'))
349
350
350 kind = opts.get('type') or archival.guesskind(dest) or 'files'
351 kind = opts.get('type') or archival.guesskind(dest) or 'files'
351 prefix = opts.get('prefix')
352 prefix = opts.get('prefix')
352
353
353 if dest == '-':
354 if dest == '-':
354 if kind == 'files':
355 if kind == 'files':
355 raise util.Abort(_('cannot archive plain files to stdout'))
356 raise util.Abort(_('cannot archive plain files to stdout'))
356 dest = cmdutil.makefileobj(repo, dest)
357 dest = cmdutil.makefileobj(repo, dest)
357 if not prefix:
358 if not prefix:
358 prefix = os.path.basename(repo.root) + '-%h'
359 prefix = os.path.basename(repo.root) + '-%h'
359
360
360 prefix = cmdutil.makefilename(repo, prefix, node)
361 prefix = cmdutil.makefilename(repo, prefix, node)
361 matchfn = scmutil.match(ctx, [], opts)
362 matchfn = scmutil.match(ctx, [], opts)
362 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
363 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
363 matchfn, prefix, subrepos=opts.get('subrepos'))
364 matchfn, prefix, subrepos=opts.get('subrepos'))
364
365
365 @command('backout',
366 @command('backout',
366 [('', 'merge', None, _('merge with old dirstate parent after backout')),
367 [('', 'merge', None, _('merge with old dirstate parent after backout')),
367 ('', 'parent', '',
368 ('', 'parent', '',
368 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
369 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
369 ('r', 'rev', '', _('revision to backout'), _('REV')),
370 ('r', 'rev', '', _('revision to backout'), _('REV')),
370 ] + mergetoolopts + walkopts + commitopts + commitopts2,
371 ] + mergetoolopts + walkopts + commitopts + commitopts2,
371 _('[OPTION]... [-r] REV'))
372 _('[OPTION]... [-r] REV'))
372 def backout(ui, repo, node=None, rev=None, **opts):
373 def backout(ui, repo, node=None, rev=None, **opts):
373 '''reverse effect of earlier changeset
374 '''reverse effect of earlier changeset
374
375
375 Prepare a new changeset with the effect of REV undone in the
376 Prepare a new changeset with the effect of REV undone in the
376 current working directory.
377 current working directory.
377
378
378 If REV is the parent of the working directory, then this new changeset
379 If REV is the parent of the working directory, then this new changeset
379 is committed automatically. Otherwise, hg needs to merge the
380 is committed automatically. Otherwise, hg needs to merge the
380 changes and the merged result is left uncommitted.
381 changes and the merged result is left uncommitted.
381
382
382 .. note::
383 .. note::
383 backout cannot be used to fix either an unwanted or
384 backout cannot be used to fix either an unwanted or
384 incorrect merge.
385 incorrect merge.
385
386
386 .. container:: verbose
387 .. container:: verbose
387
388
388 By default, the pending changeset will have one parent,
389 By default, the pending changeset will have one parent,
389 maintaining a linear history. With --merge, the pending
390 maintaining a linear history. With --merge, the pending
390 changeset will instead have two parents: the old parent of the
391 changeset will instead have two parents: the old parent of the
391 working directory and a new child of REV that simply undoes REV.
392 working directory and a new child of REV that simply undoes REV.
392
393
393 Before version 1.7, the behavior without --merge was equivalent
394 Before version 1.7, the behavior without --merge was equivalent
394 to specifying --merge followed by :hg:`update --clean .` to
395 to specifying --merge followed by :hg:`update --clean .` to
395 cancel the merge and leave the child of REV as a head to be
396 cancel the merge and leave the child of REV as a head to be
396 merged separately.
397 merged separately.
397
398
398 See :hg:`help dates` for a list of formats valid for -d/--date.
399 See :hg:`help dates` for a list of formats valid for -d/--date.
399
400
400 Returns 0 on success.
401 Returns 0 on success.
401 '''
402 '''
402 if rev and node:
403 if rev and node:
403 raise util.Abort(_("please specify just one revision"))
404 raise util.Abort(_("please specify just one revision"))
404
405
405 if not rev:
406 if not rev:
406 rev = node
407 rev = node
407
408
408 if not rev:
409 if not rev:
409 raise util.Abort(_("please specify a revision to backout"))
410 raise util.Abort(_("please specify a revision to backout"))
410
411
411 date = opts.get('date')
412 date = opts.get('date')
412 if date:
413 if date:
413 opts['date'] = util.parsedate(date)
414 opts['date'] = util.parsedate(date)
414
415
415 cmdutil.bailifchanged(repo)
416 cmdutil.bailifchanged(repo)
416 node = scmutil.revsingle(repo, rev).node()
417 node = scmutil.revsingle(repo, rev).node()
417
418
418 op1, op2 = repo.dirstate.parents()
419 op1, op2 = repo.dirstate.parents()
419 a = repo.changelog.ancestor(op1, node)
420 a = repo.changelog.ancestor(op1, node)
420 if a != node:
421 if a != node:
421 raise util.Abort(_('cannot backout change on a different branch'))
422 raise util.Abort(_('cannot backout change on a different branch'))
422
423
423 p1, p2 = repo.changelog.parents(node)
424 p1, p2 = repo.changelog.parents(node)
424 if p1 == nullid:
425 if p1 == nullid:
425 raise util.Abort(_('cannot backout a change with no parents'))
426 raise util.Abort(_('cannot backout a change with no parents'))
426 if p2 != nullid:
427 if p2 != nullid:
427 if not opts.get('parent'):
428 if not opts.get('parent'):
428 raise util.Abort(_('cannot backout a merge changeset'))
429 raise util.Abort(_('cannot backout a merge changeset'))
429 p = repo.lookup(opts['parent'])
430 p = repo.lookup(opts['parent'])
430 if p not in (p1, p2):
431 if p not in (p1, p2):
431 raise util.Abort(_('%s is not a parent of %s') %
432 raise util.Abort(_('%s is not a parent of %s') %
432 (short(p), short(node)))
433 (short(p), short(node)))
433 parent = p
434 parent = p
434 else:
435 else:
435 if opts.get('parent'):
436 if opts.get('parent'):
436 raise util.Abort(_('cannot use --parent on non-merge changeset'))
437 raise util.Abort(_('cannot use --parent on non-merge changeset'))
437 parent = p1
438 parent = p1
438
439
439 # the backout should appear on the same branch
440 # the backout should appear on the same branch
440 branch = repo.dirstate.branch()
441 branch = repo.dirstate.branch()
441 hg.clean(repo, node, show_stats=False)
442 hg.clean(repo, node, show_stats=False)
442 repo.dirstate.setbranch(branch)
443 repo.dirstate.setbranch(branch)
443 revert_opts = opts.copy()
444 revert_opts = opts.copy()
444 revert_opts['date'] = None
445 revert_opts['date'] = None
445 revert_opts['all'] = True
446 revert_opts['all'] = True
446 revert_opts['rev'] = hex(parent)
447 revert_opts['rev'] = hex(parent)
447 revert_opts['no_backup'] = None
448 revert_opts['no_backup'] = None
448 revert(ui, repo, **revert_opts)
449 revert(ui, repo, **revert_opts)
449 if not opts.get('merge') and op1 != node:
450 if not opts.get('merge') and op1 != node:
450 try:
451 try:
451 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
452 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
452 return hg.update(repo, op1)
453 return hg.update(repo, op1)
453 finally:
454 finally:
454 ui.setconfig('ui', 'forcemerge', '')
455 ui.setconfig('ui', 'forcemerge', '')
455
456
456 commit_opts = opts.copy()
457 commit_opts = opts.copy()
457 commit_opts['addremove'] = False
458 commit_opts['addremove'] = False
458 if not commit_opts['message'] and not commit_opts['logfile']:
459 if not commit_opts['message'] and not commit_opts['logfile']:
459 # we don't translate commit messages
460 # we don't translate commit messages
460 commit_opts['message'] = "Backed out changeset %s" % short(node)
461 commit_opts['message'] = "Backed out changeset %s" % short(node)
461 commit_opts['force_editor'] = True
462 commit_opts['force_editor'] = True
462 commit(ui, repo, **commit_opts)
463 commit(ui, repo, **commit_opts)
463 def nice(node):
464 def nice(node):
464 return '%d:%s' % (repo.changelog.rev(node), short(node))
465 return '%d:%s' % (repo.changelog.rev(node), short(node))
465 ui.status(_('changeset %s backs out changeset %s\n') %
466 ui.status(_('changeset %s backs out changeset %s\n') %
466 (nice(repo.changelog.tip()), nice(node)))
467 (nice(repo.changelog.tip()), nice(node)))
467 if opts.get('merge') and op1 != node:
468 if opts.get('merge') and op1 != node:
468 hg.clean(repo, op1, show_stats=False)
469 hg.clean(repo, op1, show_stats=False)
469 ui.status(_('merging with changeset %s\n')
470 ui.status(_('merging with changeset %s\n')
470 % nice(repo.changelog.tip()))
471 % nice(repo.changelog.tip()))
471 try:
472 try:
472 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
473 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
473 return hg.merge(repo, hex(repo.changelog.tip()))
474 return hg.merge(repo, hex(repo.changelog.tip()))
474 finally:
475 finally:
475 ui.setconfig('ui', 'forcemerge', '')
476 ui.setconfig('ui', 'forcemerge', '')
476 return 0
477 return 0
477
478
478 @command('bisect',
479 @command('bisect',
479 [('r', 'reset', False, _('reset bisect state')),
480 [('r', 'reset', False, _('reset bisect state')),
480 ('g', 'good', False, _('mark changeset good')),
481 ('g', 'good', False, _('mark changeset good')),
481 ('b', 'bad', False, _('mark changeset bad')),
482 ('b', 'bad', False, _('mark changeset bad')),
482 ('s', 'skip', False, _('skip testing changeset')),
483 ('s', 'skip', False, _('skip testing changeset')),
483 ('e', 'extend', False, _('extend the bisect range')),
484 ('e', 'extend', False, _('extend the bisect range')),
484 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
485 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
485 ('U', 'noupdate', False, _('do not update to target'))],
486 ('U', 'noupdate', False, _('do not update to target'))],
486 _("[-gbsr] [-U] [-c CMD] [REV]"))
487 _("[-gbsr] [-U] [-c CMD] [REV]"))
487 def bisect(ui, repo, rev=None, extra=None, command=None,
488 def bisect(ui, repo, rev=None, extra=None, command=None,
488 reset=None, good=None, bad=None, skip=None, extend=None,
489 reset=None, good=None, bad=None, skip=None, extend=None,
489 noupdate=None):
490 noupdate=None):
490 """subdivision search of changesets
491 """subdivision search of changesets
491
492
492 This command helps to find changesets which introduce problems. To
493 This command helps to find changesets which introduce problems. To
493 use, mark the earliest changeset you know exhibits the problem as
494 use, mark the earliest changeset you know exhibits the problem as
494 bad, then mark the latest changeset which is free from the problem
495 bad, then mark the latest changeset which is free from the problem
495 as good. Bisect will update your working directory to a revision
496 as good. Bisect will update your working directory to a revision
496 for testing (unless the -U/--noupdate option is specified). Once
497 for testing (unless the -U/--noupdate option is specified). Once
497 you have performed tests, mark the working directory as good or
498 you have performed tests, mark the working directory as good or
498 bad, and bisect will either update to another candidate changeset
499 bad, and bisect will either update to another candidate changeset
499 or announce that it has found the bad revision.
500 or announce that it has found the bad revision.
500
501
501 As a shortcut, you can also use the revision argument to mark a
502 As a shortcut, you can also use the revision argument to mark a
502 revision as good or bad without checking it out first.
503 revision as good or bad without checking it out first.
503
504
504 If you supply a command, it will be used for automatic bisection.
505 If you supply a command, it will be used for automatic bisection.
505 Its exit status will be used to mark revisions as good or bad:
506 Its exit status will be used to mark revisions as good or bad:
506 status 0 means good, 125 means to skip the revision, 127
507 status 0 means good, 125 means to skip the revision, 127
507 (command not found) will abort the bisection, and any other
508 (command not found) will abort the bisection, and any other
508 non-zero exit status means the revision is bad.
509 non-zero exit status means the revision is bad.
509
510
510 .. container:: verbose
511 .. container:: verbose
511
512
512 Some examples:
513 Some examples:
513
514
514 - start a bisection with known bad revision 12, and good revision 34::
515 - start a bisection with known bad revision 12, and good revision 34::
515
516
516 hg bisect --bad 34
517 hg bisect --bad 34
517 hg bisect --good 12
518 hg bisect --good 12
518
519
519 - advance the current bisection by marking current revision as good or
520 - advance the current bisection by marking current revision as good or
520 bad::
521 bad::
521
522
522 hg bisect --good
523 hg bisect --good
523 hg bisect --bad
524 hg bisect --bad
524
525
525 - mark the current revision, or a known revision, to be skipped (eg. if
526 - mark the current revision, or a known revision, to be skipped (eg. if
526 that revision is not usable because of another issue)::
527 that revision is not usable because of another issue)::
527
528
528 hg bisect --skip
529 hg bisect --skip
529 hg bisect --skip 23
530 hg bisect --skip 23
530
531
531 - forget the current bisection::
532 - forget the current bisection::
532
533
533 hg bisect --reset
534 hg bisect --reset
534
535
535 - use 'make && make tests' to automatically find the first broken
536 - use 'make && make tests' to automatically find the first broken
536 revision::
537 revision::
537
538
538 hg bisect --reset
539 hg bisect --reset
539 hg bisect --bad 34
540 hg bisect --bad 34
540 hg bisect --good 12
541 hg bisect --good 12
541 hg bisect --command 'make && make tests'
542 hg bisect --command 'make && make tests'
542
543
543 - see all changesets whose states are already known in the current
544 - see all changesets whose states are already known in the current
544 bisection::
545 bisection::
545
546
546 hg log -r "bisect(pruned)"
547 hg log -r "bisect(pruned)"
547
548
548 - see all changesets that took part in the current bisection::
549 - see all changesets that took part in the current bisection::
549
550
550 hg log -r "bisect(range)"
551 hg log -r "bisect(range)"
551
552
552 - with the graphlog extension, you can even get a nice graph::
553 - with the graphlog extension, you can even get a nice graph::
553
554
554 hg log --graph -r "bisect(range)"
555 hg log --graph -r "bisect(range)"
555
556
556 See :hg:`help revsets` for more about the `bisect()` keyword.
557 See :hg:`help revsets` for more about the `bisect()` keyword.
557
558
558 Returns 0 on success.
559 Returns 0 on success.
559 """
560 """
560 def extendbisectrange(nodes, good):
561 def extendbisectrange(nodes, good):
561 # bisect is incomplete when it ends on a merge node and
562 # bisect is incomplete when it ends on a merge node and
562 # one of the parent was not checked.
563 # one of the parent was not checked.
563 parents = repo[nodes[0]].parents()
564 parents = repo[nodes[0]].parents()
564 if len(parents) > 1:
565 if len(parents) > 1:
565 side = good and state['bad'] or state['good']
566 side = good and state['bad'] or state['good']
566 num = len(set(i.node() for i in parents) & set(side))
567 num = len(set(i.node() for i in parents) & set(side))
567 if num == 1:
568 if num == 1:
568 return parents[0].ancestor(parents[1])
569 return parents[0].ancestor(parents[1])
569 return None
570 return None
570
571
571 def print_result(nodes, good):
572 def print_result(nodes, good):
572 displayer = cmdutil.show_changeset(ui, repo, {})
573 displayer = cmdutil.show_changeset(ui, repo, {})
573 if len(nodes) == 1:
574 if len(nodes) == 1:
574 # narrowed it down to a single revision
575 # narrowed it down to a single revision
575 if good:
576 if good:
576 ui.write(_("The first good revision is:\n"))
577 ui.write(_("The first good revision is:\n"))
577 else:
578 else:
578 ui.write(_("The first bad revision is:\n"))
579 ui.write(_("The first bad revision is:\n"))
579 displayer.show(repo[nodes[0]])
580 displayer.show(repo[nodes[0]])
580 extendnode = extendbisectrange(nodes, good)
581 extendnode = extendbisectrange(nodes, good)
581 if extendnode is not None:
582 if extendnode is not None:
582 ui.write(_('Not all ancestors of this changeset have been'
583 ui.write(_('Not all ancestors of this changeset have been'
583 ' checked.\nUse bisect --extend to continue the '
584 ' checked.\nUse bisect --extend to continue the '
584 'bisection from\nthe common ancestor, %s.\n')
585 'bisection from\nthe common ancestor, %s.\n')
585 % extendnode)
586 % extendnode)
586 else:
587 else:
587 # multiple possible revisions
588 # multiple possible revisions
588 if good:
589 if good:
589 ui.write(_("Due to skipped revisions, the first "
590 ui.write(_("Due to skipped revisions, the first "
590 "good revision could be any of:\n"))
591 "good revision could be any of:\n"))
591 else:
592 else:
592 ui.write(_("Due to skipped revisions, the first "
593 ui.write(_("Due to skipped revisions, the first "
593 "bad revision could be any of:\n"))
594 "bad revision could be any of:\n"))
594 for n in nodes:
595 for n in nodes:
595 displayer.show(repo[n])
596 displayer.show(repo[n])
596 displayer.close()
597 displayer.close()
597
598
598 def check_state(state, interactive=True):
599 def check_state(state, interactive=True):
599 if not state['good'] or not state['bad']:
600 if not state['good'] or not state['bad']:
600 if (good or bad or skip or reset) and interactive:
601 if (good or bad or skip or reset) and interactive:
601 return
602 return
602 if not state['good']:
603 if not state['good']:
603 raise util.Abort(_('cannot bisect (no known good revisions)'))
604 raise util.Abort(_('cannot bisect (no known good revisions)'))
604 else:
605 else:
605 raise util.Abort(_('cannot bisect (no known bad revisions)'))
606 raise util.Abort(_('cannot bisect (no known bad revisions)'))
606 return True
607 return True
607
608
608 # backward compatibility
609 # backward compatibility
609 if rev in "good bad reset init".split():
610 if rev in "good bad reset init".split():
610 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
611 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
611 cmd, rev, extra = rev, extra, None
612 cmd, rev, extra = rev, extra, None
612 if cmd == "good":
613 if cmd == "good":
613 good = True
614 good = True
614 elif cmd == "bad":
615 elif cmd == "bad":
615 bad = True
616 bad = True
616 else:
617 else:
617 reset = True
618 reset = True
618 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
619 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
619 raise util.Abort(_('incompatible arguments'))
620 raise util.Abort(_('incompatible arguments'))
620
621
621 if reset:
622 if reset:
622 p = repo.join("bisect.state")
623 p = repo.join("bisect.state")
623 if os.path.exists(p):
624 if os.path.exists(p):
624 os.unlink(p)
625 os.unlink(p)
625 return
626 return
626
627
627 state = hbisect.load_state(repo)
628 state = hbisect.load_state(repo)
628
629
629 if command:
630 if command:
630 changesets = 1
631 changesets = 1
631 try:
632 try:
632 while changesets:
633 while changesets:
633 # update state
634 # update state
634 status = util.system(command, out=ui.fout)
635 status = util.system(command, out=ui.fout)
635 if status == 125:
636 if status == 125:
636 transition = "skip"
637 transition = "skip"
637 elif status == 0:
638 elif status == 0:
638 transition = "good"
639 transition = "good"
639 # status < 0 means process was killed
640 # status < 0 means process was killed
640 elif status == 127:
641 elif status == 127:
641 raise util.Abort(_("failed to execute %s") % command)
642 raise util.Abort(_("failed to execute %s") % command)
642 elif status < 0:
643 elif status < 0:
643 raise util.Abort(_("%s killed") % command)
644 raise util.Abort(_("%s killed") % command)
644 else:
645 else:
645 transition = "bad"
646 transition = "bad"
646 ctx = scmutil.revsingle(repo, rev)
647 ctx = scmutil.revsingle(repo, rev)
647 rev = None # clear for future iterations
648 rev = None # clear for future iterations
648 state[transition].append(ctx.node())
649 state[transition].append(ctx.node())
649 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
650 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
650 check_state(state, interactive=False)
651 check_state(state, interactive=False)
651 # bisect
652 # bisect
652 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
653 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
653 # update to next check
654 # update to next check
654 cmdutil.bailifchanged(repo)
655 cmdutil.bailifchanged(repo)
655 hg.clean(repo, nodes[0], show_stats=False)
656 hg.clean(repo, nodes[0], show_stats=False)
656 finally:
657 finally:
657 hbisect.save_state(repo, state)
658 hbisect.save_state(repo, state)
658 print_result(nodes, good)
659 print_result(nodes, good)
659 return
660 return
660
661
661 # update state
662 # update state
662
663
663 if rev:
664 if rev:
664 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
665 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
665 else:
666 else:
666 nodes = [repo.lookup('.')]
667 nodes = [repo.lookup('.')]
667
668
668 if good or bad or skip:
669 if good or bad or skip:
669 if good:
670 if good:
670 state['good'] += nodes
671 state['good'] += nodes
671 elif bad:
672 elif bad:
672 state['bad'] += nodes
673 state['bad'] += nodes
673 elif skip:
674 elif skip:
674 state['skip'] += nodes
675 state['skip'] += nodes
675 hbisect.save_state(repo, state)
676 hbisect.save_state(repo, state)
676
677
677 if not check_state(state):
678 if not check_state(state):
678 return
679 return
679
680
680 # actually bisect
681 # actually bisect
681 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
682 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
682 if extend:
683 if extend:
683 if not changesets:
684 if not changesets:
684 extendnode = extendbisectrange(nodes, good)
685 extendnode = extendbisectrange(nodes, good)
685 if extendnode is not None:
686 if extendnode is not None:
686 ui.write(_("Extending search to changeset %d:%s\n"
687 ui.write(_("Extending search to changeset %d:%s\n"
687 % (extendnode.rev(), extendnode)))
688 % (extendnode.rev(), extendnode)))
688 if noupdate:
689 if noupdate:
689 return
690 return
690 cmdutil.bailifchanged(repo)
691 cmdutil.bailifchanged(repo)
691 return hg.clean(repo, extendnode.node())
692 return hg.clean(repo, extendnode.node())
692 raise util.Abort(_("nothing to extend"))
693 raise util.Abort(_("nothing to extend"))
693
694
694 if changesets == 0:
695 if changesets == 0:
695 print_result(nodes, good)
696 print_result(nodes, good)
696 else:
697 else:
697 assert len(nodes) == 1 # only a single node can be tested next
698 assert len(nodes) == 1 # only a single node can be tested next
698 node = nodes[0]
699 node = nodes[0]
699 # compute the approximate number of remaining tests
700 # compute the approximate number of remaining tests
700 tests, size = 0, 2
701 tests, size = 0, 2
701 while size <= changesets:
702 while size <= changesets:
702 tests, size = tests + 1, size * 2
703 tests, size = tests + 1, size * 2
703 rev = repo.changelog.rev(node)
704 rev = repo.changelog.rev(node)
704 ui.write(_("Testing changeset %d:%s "
705 ui.write(_("Testing changeset %d:%s "
705 "(%d changesets remaining, ~%d tests)\n")
706 "(%d changesets remaining, ~%d tests)\n")
706 % (rev, short(node), changesets, tests))
707 % (rev, short(node), changesets, tests))
707 if not noupdate:
708 if not noupdate:
708 cmdutil.bailifchanged(repo)
709 cmdutil.bailifchanged(repo)
709 return hg.clean(repo, node)
710 return hg.clean(repo, node)
710
711
711 @command('bookmarks',
712 @command('bookmarks',
712 [('f', 'force', False, _('force')),
713 [('f', 'force', False, _('force')),
713 ('r', 'rev', '', _('revision'), _('REV')),
714 ('r', 'rev', '', _('revision'), _('REV')),
714 ('d', 'delete', False, _('delete a given bookmark')),
715 ('d', 'delete', False, _('delete a given bookmark')),
715 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
716 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
716 ('i', 'inactive', False, _('do not mark a new bookmark active'))],
717 ('i', 'inactive', False, _('do not mark a new bookmark active'))],
717 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
718 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
718 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
719 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
719 rename=None, inactive=False):
720 rename=None, inactive=False):
720 '''track a line of development with movable markers
721 '''track a line of development with movable markers
721
722
722 Bookmarks are pointers to certain commits that move when
723 Bookmarks are pointers to certain commits that move when
723 committing. Bookmarks are local. They can be renamed, copied and
724 committing. Bookmarks are local. They can be renamed, copied and
724 deleted. It is possible to use bookmark names in :hg:`merge` and
725 deleted. It is possible to use bookmark names in :hg:`merge` and
725 :hg:`update` to merge and update respectively to a given bookmark.
726 :hg:`update` to merge and update respectively to a given bookmark.
726
727
727 You can use :hg:`bookmark NAME` to set a bookmark on the working
728 You can use :hg:`bookmark NAME` to set a bookmark on the working
728 directory's parent revision with the given name. If you specify
729 directory's parent revision with the given name. If you specify
729 a revision using -r REV (where REV may be an existing bookmark),
730 a revision using -r REV (where REV may be an existing bookmark),
730 the bookmark is assigned to that revision.
731 the bookmark is assigned to that revision.
731
732
732 Bookmarks can be pushed and pulled between repositories (see :hg:`help
733 Bookmarks can be pushed and pulled between repositories (see :hg:`help
733 push` and :hg:`help pull`). This requires both the local and remote
734 push` and :hg:`help pull`). This requires both the local and remote
734 repositories to support bookmarks. For versions prior to 1.8, this means
735 repositories to support bookmarks. For versions prior to 1.8, this means
735 the bookmarks extension must be enabled.
736 the bookmarks extension must be enabled.
736 '''
737 '''
737 hexfn = ui.debugflag and hex or short
738 hexfn = ui.debugflag and hex or short
738 marks = repo._bookmarks
739 marks = repo._bookmarks
739 cur = repo.changectx('.').node()
740 cur = repo.changectx('.').node()
740
741
741 if rename:
742 if rename:
742 if rename not in marks:
743 if rename not in marks:
743 raise util.Abort(_("bookmark '%s' does not exist") % rename)
744 raise util.Abort(_("bookmark '%s' does not exist") % rename)
744 if mark in marks and not force:
745 if mark in marks and not force:
745 raise util.Abort(_("bookmark '%s' already exists "
746 raise util.Abort(_("bookmark '%s' already exists "
746 "(use -f to force)") % mark)
747 "(use -f to force)") % mark)
747 if mark is None:
748 if mark is None:
748 raise util.Abort(_("new bookmark name required"))
749 raise util.Abort(_("new bookmark name required"))
749 marks[mark] = marks[rename]
750 marks[mark] = marks[rename]
750 if repo._bookmarkcurrent == rename and not inactive:
751 if repo._bookmarkcurrent == rename and not inactive:
751 bookmarks.setcurrent(repo, mark)
752 bookmarks.setcurrent(repo, mark)
752 del marks[rename]
753 del marks[rename]
753 bookmarks.write(repo)
754 bookmarks.write(repo)
754 return
755 return
755
756
756 if delete:
757 if delete:
757 if mark is None:
758 if mark is None:
758 raise util.Abort(_("bookmark name required"))
759 raise util.Abort(_("bookmark name required"))
759 if mark not in marks:
760 if mark not in marks:
760 raise util.Abort(_("bookmark '%s' does not exist") % mark)
761 raise util.Abort(_("bookmark '%s' does not exist") % mark)
761 if mark == repo._bookmarkcurrent:
762 if mark == repo._bookmarkcurrent:
762 bookmarks.setcurrent(repo, None)
763 bookmarks.setcurrent(repo, None)
763 del marks[mark]
764 del marks[mark]
764 bookmarks.write(repo)
765 bookmarks.write(repo)
765 return
766 return
766
767
767 if mark is not None:
768 if mark is not None:
768 if "\n" in mark:
769 if "\n" in mark:
769 raise util.Abort(_("bookmark name cannot contain newlines"))
770 raise util.Abort(_("bookmark name cannot contain newlines"))
770 mark = mark.strip()
771 mark = mark.strip()
771 if not mark:
772 if not mark:
772 raise util.Abort(_("bookmark names cannot consist entirely of "
773 raise util.Abort(_("bookmark names cannot consist entirely of "
773 "whitespace"))
774 "whitespace"))
774 if inactive and mark == repo._bookmarkcurrent:
775 if inactive and mark == repo._bookmarkcurrent:
775 bookmarks.setcurrent(repo, None)
776 bookmarks.setcurrent(repo, None)
776 return
777 return
777 if mark in marks and not force:
778 if mark in marks and not force:
778 raise util.Abort(_("bookmark '%s' already exists "
779 raise util.Abort(_("bookmark '%s' already exists "
779 "(use -f to force)") % mark)
780 "(use -f to force)") % mark)
780 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
781 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
781 and not force):
782 and not force):
782 raise util.Abort(
783 raise util.Abort(
783 _("a bookmark cannot have the name of an existing branch"))
784 _("a bookmark cannot have the name of an existing branch"))
784 if rev:
785 if rev:
785 marks[mark] = repo.lookup(rev)
786 marks[mark] = repo.lookup(rev)
786 else:
787 else:
787 marks[mark] = repo.changectx('.').node()
788 marks[mark] = repo.changectx('.').node()
788 if not inactive and repo.changectx('.').node() == marks[mark]:
789 if not inactive and repo.changectx('.').node() == marks[mark]:
789 bookmarks.setcurrent(repo, mark)
790 bookmarks.setcurrent(repo, mark)
790 bookmarks.write(repo)
791 bookmarks.write(repo)
791 return
792 return
792
793
793 if mark is None:
794 if mark is None:
794 if rev:
795 if rev:
795 raise util.Abort(_("bookmark name required"))
796 raise util.Abort(_("bookmark name required"))
796 if len(marks) == 0:
797 if len(marks) == 0:
797 ui.status(_("no bookmarks set\n"))
798 ui.status(_("no bookmarks set\n"))
798 else:
799 else:
799 for bmark, n in sorted(marks.iteritems()):
800 for bmark, n in sorted(marks.iteritems()):
800 current = repo._bookmarkcurrent
801 current = repo._bookmarkcurrent
801 if bmark == current and n == cur:
802 if bmark == current and n == cur:
802 prefix, label = '*', 'bookmarks.current'
803 prefix, label = '*', 'bookmarks.current'
803 else:
804 else:
804 prefix, label = ' ', ''
805 prefix, label = ' ', ''
805
806
806 if ui.quiet:
807 if ui.quiet:
807 ui.write("%s\n" % bmark, label=label)
808 ui.write("%s\n" % bmark, label=label)
808 else:
809 else:
809 ui.write(" %s %-25s %d:%s\n" % (
810 ui.write(" %s %-25s %d:%s\n" % (
810 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
811 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
811 label=label)
812 label=label)
812 return
813 return
813
814
814 @command('branch',
815 @command('branch',
815 [('f', 'force', None,
816 [('f', 'force', None,
816 _('set branch name even if it shadows an existing branch')),
817 _('set branch name even if it shadows an existing branch')),
817 ('C', 'clean', None, _('reset branch name to parent branch name'))],
818 ('C', 'clean', None, _('reset branch name to parent branch name'))],
818 _('[-fC] [NAME]'))
819 _('[-fC] [NAME]'))
819 def branch(ui, repo, label=None, **opts):
820 def branch(ui, repo, label=None, **opts):
820 """set or show the current branch name
821 """set or show the current branch name
821
822
822 With no argument, show the current branch name. With one argument,
823 With no argument, show the current branch name. With one argument,
823 set the working directory branch name (the branch will not exist
824 set the working directory branch name (the branch will not exist
824 in the repository until the next commit). Standard practice
825 in the repository until the next commit). Standard practice
825 recommends that primary development take place on the 'default'
826 recommends that primary development take place on the 'default'
826 branch.
827 branch.
827
828
828 Unless -f/--force is specified, branch will not let you set a
829 Unless -f/--force is specified, branch will not let you set a
829 branch name that already exists, even if it's inactive.
830 branch name that already exists, even if it's inactive.
830
831
831 Use -C/--clean to reset the working directory branch to that of
832 Use -C/--clean to reset the working directory branch to that of
832 the parent of the working directory, negating a previous branch
833 the parent of the working directory, negating a previous branch
833 change.
834 change.
834
835
835 Use the command :hg:`update` to switch to an existing branch. Use
836 Use the command :hg:`update` to switch to an existing branch. Use
836 :hg:`commit --close-branch` to mark this branch as closed.
837 :hg:`commit --close-branch` to mark this branch as closed.
837
838
838 .. note::
839 .. note::
839 Branch names are permanent. Use :hg:`bookmark` to create a
840 Branch names are permanent. Use :hg:`bookmark` to create a
840 light-weight bookmark instead. See :hg:`help glossary` for more
841 light-weight bookmark instead. See :hg:`help glossary` for more
841 information about named branches and bookmarks.
842 information about named branches and bookmarks.
842
843
843 Returns 0 on success.
844 Returns 0 on success.
844 """
845 """
845
846
846 if opts.get('clean'):
847 if opts.get('clean'):
847 label = repo[None].p1().branch()
848 label = repo[None].p1().branch()
848 repo.dirstate.setbranch(label)
849 repo.dirstate.setbranch(label)
849 ui.status(_('reset working directory to branch %s\n') % label)
850 ui.status(_('reset working directory to branch %s\n') % label)
850 elif label:
851 elif label:
851 if not opts.get('force') and label in repo.branchtags():
852 if not opts.get('force') and label in repo.branchtags():
852 if label not in [p.branch() for p in repo.parents()]:
853 if label not in [p.branch() for p in repo.parents()]:
853 raise util.Abort(_('a branch of the same name already exists'),
854 raise util.Abort(_('a branch of the same name already exists'),
854 # i18n: "it" refers to an existing branch
855 # i18n: "it" refers to an existing branch
855 hint=_("use 'hg update' to switch to it"))
856 hint=_("use 'hg update' to switch to it"))
856 repo.dirstate.setbranch(label)
857 repo.dirstate.setbranch(label)
857 ui.status(_('marked working directory as branch %s\n') % label)
858 ui.status(_('marked working directory as branch %s\n') % label)
858 else:
859 else:
859 ui.write("%s\n" % repo.dirstate.branch())
860 ui.write("%s\n" % repo.dirstate.branch())
860
861
861 @command('branches',
862 @command('branches',
862 [('a', 'active', False, _('show only branches that have unmerged heads')),
863 [('a', 'active', False, _('show only branches that have unmerged heads')),
863 ('c', 'closed', False, _('show normal and closed branches'))],
864 ('c', 'closed', False, _('show normal and closed branches'))],
864 _('[-ac]'))
865 _('[-ac]'))
865 def branches(ui, repo, active=False, closed=False):
866 def branches(ui, repo, active=False, closed=False):
866 """list repository named branches
867 """list repository named branches
867
868
868 List the repository's named branches, indicating which ones are
869 List the repository's named branches, indicating which ones are
869 inactive. If -c/--closed is specified, also list branches which have
870 inactive. If -c/--closed is specified, also list branches which have
870 been marked closed (see :hg:`commit --close-branch`).
871 been marked closed (see :hg:`commit --close-branch`).
871
872
872 If -a/--active is specified, only show active branches. A branch
873 If -a/--active is specified, only show active branches. A branch
873 is considered active if it contains repository heads.
874 is considered active if it contains repository heads.
874
875
875 Use the command :hg:`update` to switch to an existing branch.
876 Use the command :hg:`update` to switch to an existing branch.
876
877
877 Returns 0.
878 Returns 0.
878 """
879 """
879
880
880 hexfunc = ui.debugflag and hex or short
881 hexfunc = ui.debugflag and hex or short
881 activebranches = [repo[n].branch() for n in repo.heads()]
882 activebranches = [repo[n].branch() for n in repo.heads()]
882 def testactive(tag, node):
883 def testactive(tag, node):
883 realhead = tag in activebranches
884 realhead = tag in activebranches
884 open = node in repo.branchheads(tag, closed=False)
885 open = node in repo.branchheads(tag, closed=False)
885 return realhead and open
886 return realhead and open
886 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
887 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
887 for tag, node in repo.branchtags().items()],
888 for tag, node in repo.branchtags().items()],
888 reverse=True)
889 reverse=True)
889
890
890 for isactive, node, tag in branches:
891 for isactive, node, tag in branches:
891 if (not active) or isactive:
892 if (not active) or isactive:
892 if ui.quiet:
893 if ui.quiet:
893 ui.write("%s\n" % tag)
894 ui.write("%s\n" % tag)
894 else:
895 else:
895 hn = repo.lookup(node)
896 hn = repo.lookup(node)
896 if isactive:
897 if isactive:
897 label = 'branches.active'
898 label = 'branches.active'
898 notice = ''
899 notice = ''
899 elif hn not in repo.branchheads(tag, closed=False):
900 elif hn not in repo.branchheads(tag, closed=False):
900 if not closed:
901 if not closed:
901 continue
902 continue
902 label = 'branches.closed'
903 label = 'branches.closed'
903 notice = _(' (closed)')
904 notice = _(' (closed)')
904 else:
905 else:
905 label = 'branches.inactive'
906 label = 'branches.inactive'
906 notice = _(' (inactive)')
907 notice = _(' (inactive)')
907 if tag == repo.dirstate.branch():
908 if tag == repo.dirstate.branch():
908 label = 'branches.current'
909 label = 'branches.current'
909 rev = str(node).rjust(31 - encoding.colwidth(tag))
910 rev = str(node).rjust(31 - encoding.colwidth(tag))
910 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
911 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
911 tag = ui.label(tag, label)
912 tag = ui.label(tag, label)
912 ui.write("%s %s%s\n" % (tag, rev, notice))
913 ui.write("%s %s%s\n" % (tag, rev, notice))
913
914
914 @command('bundle',
915 @command('bundle',
915 [('f', 'force', None, _('run even when the destination is unrelated')),
916 [('f', 'force', None, _('run even when the destination is unrelated')),
916 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
917 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
917 _('REV')),
918 _('REV')),
918 ('b', 'branch', [], _('a specific branch you would like to bundle'),
919 ('b', 'branch', [], _('a specific branch you would like to bundle'),
919 _('BRANCH')),
920 _('BRANCH')),
920 ('', 'base', [],
921 ('', 'base', [],
921 _('a base changeset assumed to be available at the destination'),
922 _('a base changeset assumed to be available at the destination'),
922 _('REV')),
923 _('REV')),
923 ('a', 'all', None, _('bundle all changesets in the repository')),
924 ('a', 'all', None, _('bundle all changesets in the repository')),
924 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
925 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
925 ] + remoteopts,
926 ] + remoteopts,
926 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
927 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
927 def bundle(ui, repo, fname, dest=None, **opts):
928 def bundle(ui, repo, fname, dest=None, **opts):
928 """create a changegroup file
929 """create a changegroup file
929
930
930 Generate a compressed changegroup file collecting changesets not
931 Generate a compressed changegroup file collecting changesets not
931 known to be in another repository.
932 known to be in another repository.
932
933
933 If you omit the destination repository, then hg assumes the
934 If you omit the destination repository, then hg assumes the
934 destination will have all the nodes you specify with --base
935 destination will have all the nodes you specify with --base
935 parameters. To create a bundle containing all changesets, use
936 parameters. To create a bundle containing all changesets, use
936 -a/--all (or --base null).
937 -a/--all (or --base null).
937
938
938 You can change compression method with the -t/--type option.
939 You can change compression method with the -t/--type option.
939 The available compression methods are: none, bzip2, and
940 The available compression methods are: none, bzip2, and
940 gzip (by default, bundles are compressed using bzip2).
941 gzip (by default, bundles are compressed using bzip2).
941
942
942 The bundle file can then be transferred using conventional means
943 The bundle file can then be transferred using conventional means
943 and applied to another repository with the unbundle or pull
944 and applied to another repository with the unbundle or pull
944 command. This is useful when direct push and pull are not
945 command. This is useful when direct push and pull are not
945 available or when exporting an entire repository is undesirable.
946 available or when exporting an entire repository is undesirable.
946
947
947 Applying bundles preserves all changeset contents including
948 Applying bundles preserves all changeset contents including
948 permissions, copy/rename information, and revision history.
949 permissions, copy/rename information, and revision history.
949
950
950 Returns 0 on success, 1 if no changes found.
951 Returns 0 on success, 1 if no changes found.
951 """
952 """
952 revs = None
953 revs = None
953 if 'rev' in opts:
954 if 'rev' in opts:
954 revs = scmutil.revrange(repo, opts['rev'])
955 revs = scmutil.revrange(repo, opts['rev'])
955
956
956 if opts.get('all'):
957 if opts.get('all'):
957 base = ['null']
958 base = ['null']
958 else:
959 else:
959 base = scmutil.revrange(repo, opts.get('base'))
960 base = scmutil.revrange(repo, opts.get('base'))
960 if base:
961 if base:
961 if dest:
962 if dest:
962 raise util.Abort(_("--base is incompatible with specifying "
963 raise util.Abort(_("--base is incompatible with specifying "
963 "a destination"))
964 "a destination"))
964 common = [repo.lookup(rev) for rev in base]
965 common = [repo.lookup(rev) for rev in base]
965 heads = revs and map(repo.lookup, revs) or revs
966 heads = revs and map(repo.lookup, revs) or revs
966 else:
967 else:
967 dest = ui.expandpath(dest or 'default-push', dest or 'default')
968 dest = ui.expandpath(dest or 'default-push', dest or 'default')
968 dest, branches = hg.parseurl(dest, opts.get('branch'))
969 dest, branches = hg.parseurl(dest, opts.get('branch'))
969 other = hg.peer(repo, opts, dest)
970 other = hg.peer(repo, opts, dest)
970 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
971 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
971 heads = revs and map(repo.lookup, revs) or revs
972 heads = revs and map(repo.lookup, revs) or revs
972 common, outheads = discovery.findcommonoutgoing(repo, other,
973 common, outheads = discovery.findcommonoutgoing(repo, other,
973 onlyheads=heads,
974 onlyheads=heads,
974 force=opts.get('force'))
975 force=opts.get('force'))
975
976
976 cg = repo.getbundle('bundle', common=common, heads=heads)
977 cg = repo.getbundle('bundle', common=common, heads=heads)
977 if not cg:
978 if not cg:
978 ui.status(_("no changes found\n"))
979 ui.status(_("no changes found\n"))
979 return 1
980 return 1
980
981
981 bundletype = opts.get('type', 'bzip2').lower()
982 bundletype = opts.get('type', 'bzip2').lower()
982 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
983 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
983 bundletype = btypes.get(bundletype)
984 bundletype = btypes.get(bundletype)
984 if bundletype not in changegroup.bundletypes:
985 if bundletype not in changegroup.bundletypes:
985 raise util.Abort(_('unknown bundle type specified with --type'))
986 raise util.Abort(_('unknown bundle type specified with --type'))
986
987
987 changegroup.writebundle(cg, fname, bundletype)
988 changegroup.writebundle(cg, fname, bundletype)
988
989
989 @command('cat',
990 @command('cat',
990 [('o', 'output', '',
991 [('o', 'output', '',
991 _('print output to file with formatted name'), _('FORMAT')),
992 _('print output to file with formatted name'), _('FORMAT')),
992 ('r', 'rev', '', _('print the given revision'), _('REV')),
993 ('r', 'rev', '', _('print the given revision'), _('REV')),
993 ('', 'decode', None, _('apply any matching decode filter')),
994 ('', 'decode', None, _('apply any matching decode filter')),
994 ] + walkopts,
995 ] + walkopts,
995 _('[OPTION]... FILE...'))
996 _('[OPTION]... FILE...'))
996 def cat(ui, repo, file1, *pats, **opts):
997 def cat(ui, repo, file1, *pats, **opts):
997 """output the current or given revision of files
998 """output the current or given revision of files
998
999
999 Print the specified files as they were at the given revision. If
1000 Print the specified files as they were at the given revision. If
1000 no revision is given, the parent of the working directory is used,
1001 no revision is given, the parent of the working directory is used,
1001 or tip if no revision is checked out.
1002 or tip if no revision is checked out.
1002
1003
1003 Output may be to a file, in which case the name of the file is
1004 Output may be to a file, in which case the name of the file is
1004 given using a format string. The formatting rules are the same as
1005 given using a format string. The formatting rules are the same as
1005 for the export command, with the following additions:
1006 for the export command, with the following additions:
1006
1007
1007 :``%s``: basename of file being printed
1008 :``%s``: basename of file being printed
1008 :``%d``: dirname of file being printed, or '.' if in repository root
1009 :``%d``: dirname of file being printed, or '.' if in repository root
1009 :``%p``: root-relative path name of file being printed
1010 :``%p``: root-relative path name of file being printed
1010
1011
1011 Returns 0 on success.
1012 Returns 0 on success.
1012 """
1013 """
1013 ctx = scmutil.revsingle(repo, opts.get('rev'))
1014 ctx = scmutil.revsingle(repo, opts.get('rev'))
1014 err = 1
1015 err = 1
1015 m = scmutil.match(ctx, (file1,) + pats, opts)
1016 m = scmutil.match(ctx, (file1,) + pats, opts)
1016 for abs in ctx.walk(m):
1017 for abs in ctx.walk(m):
1017 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1018 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1018 pathname=abs)
1019 pathname=abs)
1019 data = ctx[abs].data()
1020 data = ctx[abs].data()
1020 if opts.get('decode'):
1021 if opts.get('decode'):
1021 data = repo.wwritedata(abs, data)
1022 data = repo.wwritedata(abs, data)
1022 fp.write(data)
1023 fp.write(data)
1023 fp.close()
1024 fp.close()
1024 err = 0
1025 err = 0
1025 return err
1026 return err
1026
1027
1027 @command('^clone',
1028 @command('^clone',
1028 [('U', 'noupdate', None,
1029 [('U', 'noupdate', None,
1029 _('the clone will include an empty working copy (only a repository)')),
1030 _('the clone will include an empty working copy (only a repository)')),
1030 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1031 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1031 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1032 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1032 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1033 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1033 ('', 'pull', None, _('use pull protocol to copy metadata')),
1034 ('', 'pull', None, _('use pull protocol to copy metadata')),
1034 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1035 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1035 ] + remoteopts,
1036 ] + remoteopts,
1036 _('[OPTION]... SOURCE [DEST]'))
1037 _('[OPTION]... SOURCE [DEST]'))
1037 def clone(ui, source, dest=None, **opts):
1038 def clone(ui, source, dest=None, **opts):
1038 """make a copy of an existing repository
1039 """make a copy of an existing repository
1039
1040
1040 Create a copy of an existing repository in a new directory.
1041 Create a copy of an existing repository in a new directory.
1041
1042
1042 If no destination directory name is specified, it defaults to the
1043 If no destination directory name is specified, it defaults to the
1043 basename of the source.
1044 basename of the source.
1044
1045
1045 The location of the source is added to the new repository's
1046 The location of the source is added to the new repository's
1046 ``.hg/hgrc`` file, as the default to be used for future pulls.
1047 ``.hg/hgrc`` file, as the default to be used for future pulls.
1047
1048
1048 Only local paths and ``ssh://`` URLs are supported as
1049 Only local paths and ``ssh://`` URLs are supported as
1049 destinations. For ``ssh://`` destinations, no working directory or
1050 destinations. For ``ssh://`` destinations, no working directory or
1050 ``.hg/hgrc`` will be created on the remote side.
1051 ``.hg/hgrc`` will be created on the remote side.
1051
1052
1052 To pull only a subset of changesets, specify one or more revisions
1053 To pull only a subset of changesets, specify one or more revisions
1053 identifiers with -r/--rev or branches with -b/--branch. The
1054 identifiers with -r/--rev or branches with -b/--branch. The
1054 resulting clone will contain only the specified changesets and
1055 resulting clone will contain only the specified changesets and
1055 their ancestors. These options (or 'clone src#rev dest') imply
1056 their ancestors. These options (or 'clone src#rev dest') imply
1056 --pull, even for local source repositories. Note that specifying a
1057 --pull, even for local source repositories. Note that specifying a
1057 tag will include the tagged changeset but not the changeset
1058 tag will include the tagged changeset but not the changeset
1058 containing the tag.
1059 containing the tag.
1059
1060
1060 To check out a particular version, use -u/--update, or
1061 To check out a particular version, use -u/--update, or
1061 -U/--noupdate to create a clone with no working directory.
1062 -U/--noupdate to create a clone with no working directory.
1062
1063
1063 .. container:: verbose
1064 .. container:: verbose
1064
1065
1065 For efficiency, hardlinks are used for cloning whenever the
1066 For efficiency, hardlinks are used for cloning whenever the
1066 source and destination are on the same filesystem (note this
1067 source and destination are on the same filesystem (note this
1067 applies only to the repository data, not to the working
1068 applies only to the repository data, not to the working
1068 directory). Some filesystems, such as AFS, implement hardlinking
1069 directory). Some filesystems, such as AFS, implement hardlinking
1069 incorrectly, but do not report errors. In these cases, use the
1070 incorrectly, but do not report errors. In these cases, use the
1070 --pull option to avoid hardlinking.
1071 --pull option to avoid hardlinking.
1071
1072
1072 In some cases, you can clone repositories and the working
1073 In some cases, you can clone repositories and the working
1073 directory using full hardlinks with ::
1074 directory using full hardlinks with ::
1074
1075
1075 $ cp -al REPO REPOCLONE
1076 $ cp -al REPO REPOCLONE
1076
1077
1077 This is the fastest way to clone, but it is not always safe. The
1078 This is the fastest way to clone, but it is not always safe. The
1078 operation is not atomic (making sure REPO is not modified during
1079 operation is not atomic (making sure REPO is not modified during
1079 the operation is up to you) and you have to make sure your
1080 the operation is up to you) and you have to make sure your
1080 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1081 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1081 so). Also, this is not compatible with certain extensions that
1082 so). Also, this is not compatible with certain extensions that
1082 place their metadata under the .hg directory, such as mq.
1083 place their metadata under the .hg directory, such as mq.
1083
1084
1084 Mercurial will update the working directory to the first applicable
1085 Mercurial will update the working directory to the first applicable
1085 revision from this list:
1086 revision from this list:
1086
1087
1087 a) null if -U or the source repository has no changesets
1088 a) null if -U or the source repository has no changesets
1088 b) if -u . and the source repository is local, the first parent of
1089 b) if -u . and the source repository is local, the first parent of
1089 the source repository's working directory
1090 the source repository's working directory
1090 c) the changeset specified with -u (if a branch name, this means the
1091 c) the changeset specified with -u (if a branch name, this means the
1091 latest head of that branch)
1092 latest head of that branch)
1092 d) the changeset specified with -r
1093 d) the changeset specified with -r
1093 e) the tipmost head specified with -b
1094 e) the tipmost head specified with -b
1094 f) the tipmost head specified with the url#branch source syntax
1095 f) the tipmost head specified with the url#branch source syntax
1095 g) the tipmost head of the default branch
1096 g) the tipmost head of the default branch
1096 h) tip
1097 h) tip
1097
1098
1098 Examples:
1099 Examples:
1099
1100
1100 - clone a remote repository to a new directory named hg/::
1101 - clone a remote repository to a new directory named hg/::
1101
1102
1102 hg clone http://selenic.com/hg
1103 hg clone http://selenic.com/hg
1103
1104
1104 - create a lightweight local clone::
1105 - create a lightweight local clone::
1105
1106
1106 hg clone project/ project-feature/
1107 hg clone project/ project-feature/
1107
1108
1108 - clone from an absolute path on an ssh server (note double-slash)::
1109 - clone from an absolute path on an ssh server (note double-slash)::
1109
1110
1110 hg clone ssh://user@server//home/projects/alpha/
1111 hg clone ssh://user@server//home/projects/alpha/
1111
1112
1112 - do a high-speed clone over a LAN while checking out a
1113 - do a high-speed clone over a LAN while checking out a
1113 specified version::
1114 specified version::
1114
1115
1115 hg clone --uncompressed http://server/repo -u 1.5
1116 hg clone --uncompressed http://server/repo -u 1.5
1116
1117
1117 - create a repository without changesets after a particular revision::
1118 - create a repository without changesets after a particular revision::
1118
1119
1119 hg clone -r 04e544 experimental/ good/
1120 hg clone -r 04e544 experimental/ good/
1120
1121
1121 - clone (and track) a particular named branch::
1122 - clone (and track) a particular named branch::
1122
1123
1123 hg clone http://selenic.com/hg#stable
1124 hg clone http://selenic.com/hg#stable
1124
1125
1125 See :hg:`help urls` for details on specifying URLs.
1126 See :hg:`help urls` for details on specifying URLs.
1126
1127
1127 Returns 0 on success.
1128 Returns 0 on success.
1128 """
1129 """
1129 if opts.get('noupdate') and opts.get('updaterev'):
1130 if opts.get('noupdate') and opts.get('updaterev'):
1130 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1131 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1131
1132
1132 r = hg.clone(ui, opts, source, dest,
1133 r = hg.clone(ui, opts, source, dest,
1133 pull=opts.get('pull'),
1134 pull=opts.get('pull'),
1134 stream=opts.get('uncompressed'),
1135 stream=opts.get('uncompressed'),
1135 rev=opts.get('rev'),
1136 rev=opts.get('rev'),
1136 update=opts.get('updaterev') or not opts.get('noupdate'),
1137 update=opts.get('updaterev') or not opts.get('noupdate'),
1137 branch=opts.get('branch'))
1138 branch=opts.get('branch'))
1138
1139
1139 return r is None
1140 return r is None
1140
1141
1141 @command('^commit|ci',
1142 @command('^commit|ci',
1142 [('A', 'addremove', None,
1143 [('A', 'addremove', None,
1143 _('mark new/missing files as added/removed before committing')),
1144 _('mark new/missing files as added/removed before committing')),
1144 ('', 'close-branch', None,
1145 ('', 'close-branch', None,
1145 _('mark a branch as closed, hiding it from the branch list')),
1146 _('mark a branch as closed, hiding it from the branch list')),
1146 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1147 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1147 _('[OPTION]... [FILE]...'))
1148 _('[OPTION]... [FILE]...'))
1148 def commit(ui, repo, *pats, **opts):
1149 def commit(ui, repo, *pats, **opts):
1149 """commit the specified files or all outstanding changes
1150 """commit the specified files or all outstanding changes
1150
1151
1151 Commit changes to the given files into the repository. Unlike a
1152 Commit changes to the given files into the repository. Unlike a
1152 centralized SCM, this operation is a local operation. See
1153 centralized SCM, this operation is a local operation. See
1153 :hg:`push` for a way to actively distribute your changes.
1154 :hg:`push` for a way to actively distribute your changes.
1154
1155
1155 If a list of files is omitted, all changes reported by :hg:`status`
1156 If a list of files is omitted, all changes reported by :hg:`status`
1156 will be committed.
1157 will be committed.
1157
1158
1158 If you are committing the result of a merge, do not provide any
1159 If you are committing the result of a merge, do not provide any
1159 filenames or -I/-X filters.
1160 filenames or -I/-X filters.
1160
1161
1161 If no commit message is specified, Mercurial starts your
1162 If no commit message is specified, Mercurial starts your
1162 configured editor where you can enter a message. In case your
1163 configured editor where you can enter a message. In case your
1163 commit fails, you will find a backup of your message in
1164 commit fails, you will find a backup of your message in
1164 ``.hg/last-message.txt``.
1165 ``.hg/last-message.txt``.
1165
1166
1166 See :hg:`help dates` for a list of formats valid for -d/--date.
1167 See :hg:`help dates` for a list of formats valid for -d/--date.
1167
1168
1168 Returns 0 on success, 1 if nothing changed.
1169 Returns 0 on success, 1 if nothing changed.
1169 """
1170 """
1170 if opts.get('subrepos'):
1171 if opts.get('subrepos'):
1171 # Let --subrepos on the command line overide config setting.
1172 # Let --subrepos on the command line overide config setting.
1172 ui.setconfig('ui', 'commitsubrepos', True)
1173 ui.setconfig('ui', 'commitsubrepos', True)
1173
1174
1174 extra = {}
1175 extra = {}
1175 if opts.get('close_branch'):
1176 if opts.get('close_branch'):
1176 if repo['.'].node() not in repo.branchheads():
1177 if repo['.'].node() not in repo.branchheads():
1177 # The topo heads set is included in the branch heads set of the
1178 # The topo heads set is included in the branch heads set of the
1178 # current branch, so it's sufficient to test branchheads
1179 # current branch, so it's sufficient to test branchheads
1179 raise util.Abort(_('can only close branch heads'))
1180 raise util.Abort(_('can only close branch heads'))
1180 extra['close'] = 1
1181 extra['close'] = 1
1181 e = cmdutil.commiteditor
1182 e = cmdutil.commiteditor
1182 if opts.get('force_editor'):
1183 if opts.get('force_editor'):
1183 e = cmdutil.commitforceeditor
1184 e = cmdutil.commitforceeditor
1184
1185
1185 def commitfunc(ui, repo, message, match, opts):
1186 def commitfunc(ui, repo, message, match, opts):
1186 return repo.commit(message, opts.get('user'), opts.get('date'), match,
1187 return repo.commit(message, opts.get('user'), opts.get('date'), match,
1187 editor=e, extra=extra)
1188 editor=e, extra=extra)
1188
1189
1189 branch = repo[None].branch()
1190 branch = repo[None].branch()
1190 bheads = repo.branchheads(branch)
1191 bheads = repo.branchheads(branch)
1191
1192
1192 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1193 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1193 if not node:
1194 if not node:
1194 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1195 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1195 if stat[3]:
1196 if stat[3]:
1196 ui.status(_("nothing changed (%d missing files, see 'hg status')\n")
1197 ui.status(_("nothing changed (%d missing files, see 'hg status')\n")
1197 % len(stat[3]))
1198 % len(stat[3]))
1198 else:
1199 else:
1199 ui.status(_("nothing changed\n"))
1200 ui.status(_("nothing changed\n"))
1200 return 1
1201 return 1
1201
1202
1202 ctx = repo[node]
1203 ctx = repo[node]
1203 parents = ctx.parents()
1204 parents = ctx.parents()
1204
1205
1205 if (bheads and node not in bheads and not
1206 if (bheads and node not in bheads and not
1206 [x for x in parents if x.node() in bheads and x.branch() == branch]):
1207 [x for x in parents if x.node() in bheads and x.branch() == branch]):
1207 ui.status(_('created new head\n'))
1208 ui.status(_('created new head\n'))
1208 # The message is not printed for initial roots. For the other
1209 # The message is not printed for initial roots. For the other
1209 # changesets, it is printed in the following situations:
1210 # changesets, it is printed in the following situations:
1210 #
1211 #
1211 # Par column: for the 2 parents with ...
1212 # Par column: for the 2 parents with ...
1212 # N: null or no parent
1213 # N: null or no parent
1213 # B: parent is on another named branch
1214 # B: parent is on another named branch
1214 # C: parent is a regular non head changeset
1215 # C: parent is a regular non head changeset
1215 # H: parent was a branch head of the current branch
1216 # H: parent was a branch head of the current branch
1216 # Msg column: whether we print "created new head" message
1217 # Msg column: whether we print "created new head" message
1217 # In the following, it is assumed that there already exists some
1218 # In the following, it is assumed that there already exists some
1218 # initial branch heads of the current branch, otherwise nothing is
1219 # initial branch heads of the current branch, otherwise nothing is
1219 # printed anyway.
1220 # printed anyway.
1220 #
1221 #
1221 # Par Msg Comment
1222 # Par Msg Comment
1222 # NN y additional topo root
1223 # NN y additional topo root
1223 #
1224 #
1224 # BN y additional branch root
1225 # BN y additional branch root
1225 # CN y additional topo head
1226 # CN y additional topo head
1226 # HN n usual case
1227 # HN n usual case
1227 #
1228 #
1228 # BB y weird additional branch root
1229 # BB y weird additional branch root
1229 # CB y branch merge
1230 # CB y branch merge
1230 # HB n merge with named branch
1231 # HB n merge with named branch
1231 #
1232 #
1232 # CC y additional head from merge
1233 # CC y additional head from merge
1233 # CH n merge with a head
1234 # CH n merge with a head
1234 #
1235 #
1235 # HH n head merge: head count decreases
1236 # HH n head merge: head count decreases
1236
1237
1237 if not opts.get('close_branch'):
1238 if not opts.get('close_branch'):
1238 for r in parents:
1239 for r in parents:
1239 if r.extra().get('close') and r.branch() == branch:
1240 if r.extra().get('close') and r.branch() == branch:
1240 ui.status(_('reopening closed branch head %d\n') % r)
1241 ui.status(_('reopening closed branch head %d\n') % r)
1241
1242
1242 if ui.debugflag:
1243 if ui.debugflag:
1243 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1244 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1244 elif ui.verbose:
1245 elif ui.verbose:
1245 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1246 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1246
1247
1247 @command('copy|cp',
1248 @command('copy|cp',
1248 [('A', 'after', None, _('record a copy that has already occurred')),
1249 [('A', 'after', None, _('record a copy that has already occurred')),
1249 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1250 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1250 ] + walkopts + dryrunopts,
1251 ] + walkopts + dryrunopts,
1251 _('[OPTION]... [SOURCE]... DEST'))
1252 _('[OPTION]... [SOURCE]... DEST'))
1252 def copy(ui, repo, *pats, **opts):
1253 def copy(ui, repo, *pats, **opts):
1253 """mark files as copied for the next commit
1254 """mark files as copied for the next commit
1254
1255
1255 Mark dest as having copies of source files. If dest is a
1256 Mark dest as having copies of source files. If dest is a
1256 directory, copies are put in that directory. If dest is a file,
1257 directory, copies are put in that directory. If dest is a file,
1257 the source must be a single file.
1258 the source must be a single file.
1258
1259
1259 By default, this command copies the contents of files as they
1260 By default, this command copies the contents of files as they
1260 exist in the working directory. If invoked with -A/--after, the
1261 exist in the working directory. If invoked with -A/--after, the
1261 operation is recorded, but no copying is performed.
1262 operation is recorded, but no copying is performed.
1262
1263
1263 This command takes effect with the next commit. To undo a copy
1264 This command takes effect with the next commit. To undo a copy
1264 before that, see :hg:`revert`.
1265 before that, see :hg:`revert`.
1265
1266
1266 Returns 0 on success, 1 if errors are encountered.
1267 Returns 0 on success, 1 if errors are encountered.
1267 """
1268 """
1268 wlock = repo.wlock(False)
1269 wlock = repo.wlock(False)
1269 try:
1270 try:
1270 return cmdutil.copy(ui, repo, pats, opts)
1271 return cmdutil.copy(ui, repo, pats, opts)
1271 finally:
1272 finally:
1272 wlock.release()
1273 wlock.release()
1273
1274
1274 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1275 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1275 def debugancestor(ui, repo, *args):
1276 def debugancestor(ui, repo, *args):
1276 """find the ancestor revision of two revisions in a given index"""
1277 """find the ancestor revision of two revisions in a given index"""
1277 if len(args) == 3:
1278 if len(args) == 3:
1278 index, rev1, rev2 = args
1279 index, rev1, rev2 = args
1279 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1280 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1280 lookup = r.lookup
1281 lookup = r.lookup
1281 elif len(args) == 2:
1282 elif len(args) == 2:
1282 if not repo:
1283 if not repo:
1283 raise util.Abort(_("there is no Mercurial repository here "
1284 raise util.Abort(_("there is no Mercurial repository here "
1284 "(.hg not found)"))
1285 "(.hg not found)"))
1285 rev1, rev2 = args
1286 rev1, rev2 = args
1286 r = repo.changelog
1287 r = repo.changelog
1287 lookup = repo.lookup
1288 lookup = repo.lookup
1288 else:
1289 else:
1289 raise util.Abort(_('either two or three arguments required'))
1290 raise util.Abort(_('either two or three arguments required'))
1290 a = r.ancestor(lookup(rev1), lookup(rev2))
1291 a = r.ancestor(lookup(rev1), lookup(rev2))
1291 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1292 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1292
1293
1293 @command('debugbuilddag',
1294 @command('debugbuilddag',
1294 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1295 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1295 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1296 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1296 ('n', 'new-file', None, _('add new file at each rev'))],
1297 ('n', 'new-file', None, _('add new file at each rev'))],
1297 _('[OPTION]... [TEXT]'))
1298 _('[OPTION]... [TEXT]'))
1298 def debugbuilddag(ui, repo, text=None,
1299 def debugbuilddag(ui, repo, text=None,
1299 mergeable_file=False,
1300 mergeable_file=False,
1300 overwritten_file=False,
1301 overwritten_file=False,
1301 new_file=False):
1302 new_file=False):
1302 """builds a repo with a given DAG from scratch in the current empty repo
1303 """builds a repo with a given DAG from scratch in the current empty repo
1303
1304
1304 The description of the DAG is read from stdin if not given on the
1305 The description of the DAG is read from stdin if not given on the
1305 command line.
1306 command line.
1306
1307
1307 Elements:
1308 Elements:
1308
1309
1309 - "+n" is a linear run of n nodes based on the current default parent
1310 - "+n" is a linear run of n nodes based on the current default parent
1310 - "." is a single node based on the current default parent
1311 - "." is a single node based on the current default parent
1311 - "$" resets the default parent to null (implied at the start);
1312 - "$" resets the default parent to null (implied at the start);
1312 otherwise the default parent is always the last node created
1313 otherwise the default parent is always the last node created
1313 - "<p" sets the default parent to the backref p
1314 - "<p" sets the default parent to the backref p
1314 - "*p" is a fork at parent p, which is a backref
1315 - "*p" is a fork at parent p, which is a backref
1315 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1316 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1316 - "/p2" is a merge of the preceding node and p2
1317 - "/p2" is a merge of the preceding node and p2
1317 - ":tag" defines a local tag for the preceding node
1318 - ":tag" defines a local tag for the preceding node
1318 - "@branch" sets the named branch for subsequent nodes
1319 - "@branch" sets the named branch for subsequent nodes
1319 - "#...\\n" is a comment up to the end of the line
1320 - "#...\\n" is a comment up to the end of the line
1320
1321
1321 Whitespace between the above elements is ignored.
1322 Whitespace between the above elements is ignored.
1322
1323
1323 A backref is either
1324 A backref is either
1324
1325
1325 - a number n, which references the node curr-n, where curr is the current
1326 - a number n, which references the node curr-n, where curr is the current
1326 node, or
1327 node, or
1327 - the name of a local tag you placed earlier using ":tag", or
1328 - the name of a local tag you placed earlier using ":tag", or
1328 - empty to denote the default parent.
1329 - empty to denote the default parent.
1329
1330
1330 All string valued-elements are either strictly alphanumeric, or must
1331 All string valued-elements are either strictly alphanumeric, or must
1331 be enclosed in double quotes ("..."), with "\\" as escape character.
1332 be enclosed in double quotes ("..."), with "\\" as escape character.
1332 """
1333 """
1333
1334
1334 if text is None:
1335 if text is None:
1335 ui.status(_("reading DAG from stdin\n"))
1336 ui.status(_("reading DAG from stdin\n"))
1336 text = ui.fin.read()
1337 text = ui.fin.read()
1337
1338
1338 cl = repo.changelog
1339 cl = repo.changelog
1339 if len(cl) > 0:
1340 if len(cl) > 0:
1340 raise util.Abort(_('repository is not empty'))
1341 raise util.Abort(_('repository is not empty'))
1341
1342
1342 # determine number of revs in DAG
1343 # determine number of revs in DAG
1343 total = 0
1344 total = 0
1344 for type, data in dagparser.parsedag(text):
1345 for type, data in dagparser.parsedag(text):
1345 if type == 'n':
1346 if type == 'n':
1346 total += 1
1347 total += 1
1347
1348
1348 if mergeable_file:
1349 if mergeable_file:
1349 linesperrev = 2
1350 linesperrev = 2
1350 # make a file with k lines per rev
1351 # make a file with k lines per rev
1351 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1352 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1352 initialmergedlines.append("")
1353 initialmergedlines.append("")
1353
1354
1354 tags = []
1355 tags = []
1355
1356
1356 tr = repo.transaction("builddag")
1357 tr = repo.transaction("builddag")
1357 try:
1358 try:
1358
1359
1359 at = -1
1360 at = -1
1360 atbranch = 'default'
1361 atbranch = 'default'
1361 nodeids = []
1362 nodeids = []
1362 ui.progress(_('building'), 0, unit=_('revisions'), total=total)
1363 ui.progress(_('building'), 0, unit=_('revisions'), total=total)
1363 for type, data in dagparser.parsedag(text):
1364 for type, data in dagparser.parsedag(text):
1364 if type == 'n':
1365 if type == 'n':
1365 ui.note('node %s\n' % str(data))
1366 ui.note('node %s\n' % str(data))
1366 id, ps = data
1367 id, ps = data
1367
1368
1368 files = []
1369 files = []
1369 fctxs = {}
1370 fctxs = {}
1370
1371
1371 p2 = None
1372 p2 = None
1372 if mergeable_file:
1373 if mergeable_file:
1373 fn = "mf"
1374 fn = "mf"
1374 p1 = repo[ps[0]]
1375 p1 = repo[ps[0]]
1375 if len(ps) > 1:
1376 if len(ps) > 1:
1376 p2 = repo[ps[1]]
1377 p2 = repo[ps[1]]
1377 pa = p1.ancestor(p2)
1378 pa = p1.ancestor(p2)
1378 base, local, other = [x[fn].data() for x in pa, p1, p2]
1379 base, local, other = [x[fn].data() for x in pa, p1, p2]
1379 m3 = simplemerge.Merge3Text(base, local, other)
1380 m3 = simplemerge.Merge3Text(base, local, other)
1380 ml = [l.strip() for l in m3.merge_lines()]
1381 ml = [l.strip() for l in m3.merge_lines()]
1381 ml.append("")
1382 ml.append("")
1382 elif at > 0:
1383 elif at > 0:
1383 ml = p1[fn].data().split("\n")
1384 ml = p1[fn].data().split("\n")
1384 else:
1385 else:
1385 ml = initialmergedlines
1386 ml = initialmergedlines
1386 ml[id * linesperrev] += " r%i" % id
1387 ml[id * linesperrev] += " r%i" % id
1387 mergedtext = "\n".join(ml)
1388 mergedtext = "\n".join(ml)
1388 files.append(fn)
1389 files.append(fn)
1389 fctxs[fn] = context.memfilectx(fn, mergedtext)
1390 fctxs[fn] = context.memfilectx(fn, mergedtext)
1390
1391
1391 if overwritten_file:
1392 if overwritten_file:
1392 fn = "of"
1393 fn = "of"
1393 files.append(fn)
1394 files.append(fn)
1394 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1395 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1395
1396
1396 if new_file:
1397 if new_file:
1397 fn = "nf%i" % id
1398 fn = "nf%i" % id
1398 files.append(fn)
1399 files.append(fn)
1399 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1400 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1400 if len(ps) > 1:
1401 if len(ps) > 1:
1401 if not p2:
1402 if not p2:
1402 p2 = repo[ps[1]]
1403 p2 = repo[ps[1]]
1403 for fn in p2:
1404 for fn in p2:
1404 if fn.startswith("nf"):
1405 if fn.startswith("nf"):
1405 files.append(fn)
1406 files.append(fn)
1406 fctxs[fn] = p2[fn]
1407 fctxs[fn] = p2[fn]
1407
1408
1408 def fctxfn(repo, cx, path):
1409 def fctxfn(repo, cx, path):
1409 return fctxs.get(path)
1410 return fctxs.get(path)
1410
1411
1411 if len(ps) == 0 or ps[0] < 0:
1412 if len(ps) == 0 or ps[0] < 0:
1412 pars = [None, None]
1413 pars = [None, None]
1413 elif len(ps) == 1:
1414 elif len(ps) == 1:
1414 pars = [nodeids[ps[0]], None]
1415 pars = [nodeids[ps[0]], None]
1415 else:
1416 else:
1416 pars = [nodeids[p] for p in ps]
1417 pars = [nodeids[p] for p in ps]
1417 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1418 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1418 date=(id, 0),
1419 date=(id, 0),
1419 user="debugbuilddag",
1420 user="debugbuilddag",
1420 extra={'branch': atbranch})
1421 extra={'branch': atbranch})
1421 nodeid = repo.commitctx(cx)
1422 nodeid = repo.commitctx(cx)
1422 nodeids.append(nodeid)
1423 nodeids.append(nodeid)
1423 at = id
1424 at = id
1424 elif type == 'l':
1425 elif type == 'l':
1425 id, name = data
1426 id, name = data
1426 ui.note('tag %s\n' % name)
1427 ui.note('tag %s\n' % name)
1427 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1428 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1428 elif type == 'a':
1429 elif type == 'a':
1429 ui.note('branch %s\n' % data)
1430 ui.note('branch %s\n' % data)
1430 atbranch = data
1431 atbranch = data
1431 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1432 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1432 tr.close()
1433 tr.close()
1433 finally:
1434 finally:
1434 ui.progress(_('building'), None)
1435 ui.progress(_('building'), None)
1435 tr.release()
1436 tr.release()
1436
1437
1437 if tags:
1438 if tags:
1438 repo.opener.write("localtags", "".join(tags))
1439 repo.opener.write("localtags", "".join(tags))
1439
1440
1440 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1441 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1441 def debugbundle(ui, bundlepath, all=None, **opts):
1442 def debugbundle(ui, bundlepath, all=None, **opts):
1442 """lists the contents of a bundle"""
1443 """lists the contents of a bundle"""
1443 f = url.open(ui, bundlepath)
1444 f = url.open(ui, bundlepath)
1444 try:
1445 try:
1445 gen = changegroup.readbundle(f, bundlepath)
1446 gen = changegroup.readbundle(f, bundlepath)
1446 if all:
1447 if all:
1447 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1448 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1448
1449
1449 def showchunks(named):
1450 def showchunks(named):
1450 ui.write("\n%s\n" % named)
1451 ui.write("\n%s\n" % named)
1451 chain = None
1452 chain = None
1452 while True:
1453 while True:
1453 chunkdata = gen.deltachunk(chain)
1454 chunkdata = gen.deltachunk(chain)
1454 if not chunkdata:
1455 if not chunkdata:
1455 break
1456 break
1456 node = chunkdata['node']
1457 node = chunkdata['node']
1457 p1 = chunkdata['p1']
1458 p1 = chunkdata['p1']
1458 p2 = chunkdata['p2']
1459 p2 = chunkdata['p2']
1459 cs = chunkdata['cs']
1460 cs = chunkdata['cs']
1460 deltabase = chunkdata['deltabase']
1461 deltabase = chunkdata['deltabase']
1461 delta = chunkdata['delta']
1462 delta = chunkdata['delta']
1462 ui.write("%s %s %s %s %s %s\n" %
1463 ui.write("%s %s %s %s %s %s\n" %
1463 (hex(node), hex(p1), hex(p2),
1464 (hex(node), hex(p1), hex(p2),
1464 hex(cs), hex(deltabase), len(delta)))
1465 hex(cs), hex(deltabase), len(delta)))
1465 chain = node
1466 chain = node
1466
1467
1467 chunkdata = gen.changelogheader()
1468 chunkdata = gen.changelogheader()
1468 showchunks("changelog")
1469 showchunks("changelog")
1469 chunkdata = gen.manifestheader()
1470 chunkdata = gen.manifestheader()
1470 showchunks("manifest")
1471 showchunks("manifest")
1471 while True:
1472 while True:
1472 chunkdata = gen.filelogheader()
1473 chunkdata = gen.filelogheader()
1473 if not chunkdata:
1474 if not chunkdata:
1474 break
1475 break
1475 fname = chunkdata['filename']
1476 fname = chunkdata['filename']
1476 showchunks(fname)
1477 showchunks(fname)
1477 else:
1478 else:
1478 chunkdata = gen.changelogheader()
1479 chunkdata = gen.changelogheader()
1479 chain = None
1480 chain = None
1480 while True:
1481 while True:
1481 chunkdata = gen.deltachunk(chain)
1482 chunkdata = gen.deltachunk(chain)
1482 if not chunkdata:
1483 if not chunkdata:
1483 break
1484 break
1484 node = chunkdata['node']
1485 node = chunkdata['node']
1485 ui.write("%s\n" % hex(node))
1486 ui.write("%s\n" % hex(node))
1486 chain = node
1487 chain = node
1487 finally:
1488 finally:
1488 f.close()
1489 f.close()
1489
1490
1490 @command('debugcheckstate', [], '')
1491 @command('debugcheckstate', [], '')
1491 def debugcheckstate(ui, repo):
1492 def debugcheckstate(ui, repo):
1492 """validate the correctness of the current dirstate"""
1493 """validate the correctness of the current dirstate"""
1493 parent1, parent2 = repo.dirstate.parents()
1494 parent1, parent2 = repo.dirstate.parents()
1494 m1 = repo[parent1].manifest()
1495 m1 = repo[parent1].manifest()
1495 m2 = repo[parent2].manifest()
1496 m2 = repo[parent2].manifest()
1496 errors = 0
1497 errors = 0
1497 for f in repo.dirstate:
1498 for f in repo.dirstate:
1498 state = repo.dirstate[f]
1499 state = repo.dirstate[f]
1499 if state in "nr" and f not in m1:
1500 if state in "nr" and f not in m1:
1500 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1501 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1501 errors += 1
1502 errors += 1
1502 if state in "a" and f in m1:
1503 if state in "a" and f in m1:
1503 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1504 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1504 errors += 1
1505 errors += 1
1505 if state in "m" and f not in m1 and f not in m2:
1506 if state in "m" and f not in m1 and f not in m2:
1506 ui.warn(_("%s in state %s, but not in either manifest\n") %
1507 ui.warn(_("%s in state %s, but not in either manifest\n") %
1507 (f, state))
1508 (f, state))
1508 errors += 1
1509 errors += 1
1509 for f in m1:
1510 for f in m1:
1510 state = repo.dirstate[f]
1511 state = repo.dirstate[f]
1511 if state not in "nrm":
1512 if state not in "nrm":
1512 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1513 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1513 errors += 1
1514 errors += 1
1514 if errors:
1515 if errors:
1515 error = _(".hg/dirstate inconsistent with current parent's manifest")
1516 error = _(".hg/dirstate inconsistent with current parent's manifest")
1516 raise util.Abort(error)
1517 raise util.Abort(error)
1517
1518
1518 @command('debugcommands', [], _('[COMMAND]'))
1519 @command('debugcommands', [], _('[COMMAND]'))
1519 def debugcommands(ui, cmd='', *args):
1520 def debugcommands(ui, cmd='', *args):
1520 """list all available commands and options"""
1521 """list all available commands and options"""
1521 for cmd, vals in sorted(table.iteritems()):
1522 for cmd, vals in sorted(table.iteritems()):
1522 cmd = cmd.split('|')[0].strip('^')
1523 cmd = cmd.split('|')[0].strip('^')
1523 opts = ', '.join([i[1] for i in vals[1]])
1524 opts = ', '.join([i[1] for i in vals[1]])
1524 ui.write('%s: %s\n' % (cmd, opts))
1525 ui.write('%s: %s\n' % (cmd, opts))
1525
1526
1526 @command('debugcomplete',
1527 @command('debugcomplete',
1527 [('o', 'options', None, _('show the command options'))],
1528 [('o', 'options', None, _('show the command options'))],
1528 _('[-o] CMD'))
1529 _('[-o] CMD'))
1529 def debugcomplete(ui, cmd='', **opts):
1530 def debugcomplete(ui, cmd='', **opts):
1530 """returns the completion list associated with the given command"""
1531 """returns the completion list associated with the given command"""
1531
1532
1532 if opts.get('options'):
1533 if opts.get('options'):
1533 options = []
1534 options = []
1534 otables = [globalopts]
1535 otables = [globalopts]
1535 if cmd:
1536 if cmd:
1536 aliases, entry = cmdutil.findcmd(cmd, table, False)
1537 aliases, entry = cmdutil.findcmd(cmd, table, False)
1537 otables.append(entry[1])
1538 otables.append(entry[1])
1538 for t in otables:
1539 for t in otables:
1539 for o in t:
1540 for o in t:
1540 if "(DEPRECATED)" in o[3]:
1541 if "(DEPRECATED)" in o[3]:
1541 continue
1542 continue
1542 if o[0]:
1543 if o[0]:
1543 options.append('-%s' % o[0])
1544 options.append('-%s' % o[0])
1544 options.append('--%s' % o[1])
1545 options.append('--%s' % o[1])
1545 ui.write("%s\n" % "\n".join(options))
1546 ui.write("%s\n" % "\n".join(options))
1546 return
1547 return
1547
1548
1548 cmdlist = cmdutil.findpossible(cmd, table)
1549 cmdlist = cmdutil.findpossible(cmd, table)
1549 if ui.verbose:
1550 if ui.verbose:
1550 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1551 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1551 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1552 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1552
1553
1553 @command('debugdag',
1554 @command('debugdag',
1554 [('t', 'tags', None, _('use tags as labels')),
1555 [('t', 'tags', None, _('use tags as labels')),
1555 ('b', 'branches', None, _('annotate with branch names')),
1556 ('b', 'branches', None, _('annotate with branch names')),
1556 ('', 'dots', None, _('use dots for runs')),
1557 ('', 'dots', None, _('use dots for runs')),
1557 ('s', 'spaces', None, _('separate elements by spaces'))],
1558 ('s', 'spaces', None, _('separate elements by spaces'))],
1558 _('[OPTION]... [FILE [REV]...]'))
1559 _('[OPTION]... [FILE [REV]...]'))
1559 def debugdag(ui, repo, file_=None, *revs, **opts):
1560 def debugdag(ui, repo, file_=None, *revs, **opts):
1560 """format the changelog or an index DAG as a concise textual description
1561 """format the changelog or an index DAG as a concise textual description
1561
1562
1562 If you pass a revlog index, the revlog's DAG is emitted. If you list
1563 If you pass a revlog index, the revlog's DAG is emitted. If you list
1563 revision numbers, they get labelled in the output as rN.
1564 revision numbers, they get labelled in the output as rN.
1564
1565
1565 Otherwise, the changelog DAG of the current repo is emitted.
1566 Otherwise, the changelog DAG of the current repo is emitted.
1566 """
1567 """
1567 spaces = opts.get('spaces')
1568 spaces = opts.get('spaces')
1568 dots = opts.get('dots')
1569 dots = opts.get('dots')
1569 if file_:
1570 if file_:
1570 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1571 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1571 revs = set((int(r) for r in revs))
1572 revs = set((int(r) for r in revs))
1572 def events():
1573 def events():
1573 for r in rlog:
1574 for r in rlog:
1574 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1575 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1575 if r in revs:
1576 if r in revs:
1576 yield 'l', (r, "r%i" % r)
1577 yield 'l', (r, "r%i" % r)
1577 elif repo:
1578 elif repo:
1578 cl = repo.changelog
1579 cl = repo.changelog
1579 tags = opts.get('tags')
1580 tags = opts.get('tags')
1580 branches = opts.get('branches')
1581 branches = opts.get('branches')
1581 if tags:
1582 if tags:
1582 labels = {}
1583 labels = {}
1583 for l, n in repo.tags().items():
1584 for l, n in repo.tags().items():
1584 labels.setdefault(cl.rev(n), []).append(l)
1585 labels.setdefault(cl.rev(n), []).append(l)
1585 def events():
1586 def events():
1586 b = "default"
1587 b = "default"
1587 for r in cl:
1588 for r in cl:
1588 if branches:
1589 if branches:
1589 newb = cl.read(cl.node(r))[5]['branch']
1590 newb = cl.read(cl.node(r))[5]['branch']
1590 if newb != b:
1591 if newb != b:
1591 yield 'a', newb
1592 yield 'a', newb
1592 b = newb
1593 b = newb
1593 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1594 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1594 if tags:
1595 if tags:
1595 ls = labels.get(r)
1596 ls = labels.get(r)
1596 if ls:
1597 if ls:
1597 for l in ls:
1598 for l in ls:
1598 yield 'l', (r, l)
1599 yield 'l', (r, l)
1599 else:
1600 else:
1600 raise util.Abort(_('need repo for changelog dag'))
1601 raise util.Abort(_('need repo for changelog dag'))
1601
1602
1602 for line in dagparser.dagtextlines(events(),
1603 for line in dagparser.dagtextlines(events(),
1603 addspaces=spaces,
1604 addspaces=spaces,
1604 wraplabels=True,
1605 wraplabels=True,
1605 wrapannotations=True,
1606 wrapannotations=True,
1606 wrapnonlinear=dots,
1607 wrapnonlinear=dots,
1607 usedots=dots,
1608 usedots=dots,
1608 maxlinewidth=70):
1609 maxlinewidth=70):
1609 ui.write(line)
1610 ui.write(line)
1610 ui.write("\n")
1611 ui.write("\n")
1611
1612
1612 @command('debugdata',
1613 @command('debugdata',
1613 [('c', 'changelog', False, _('open changelog')),
1614 [('c', 'changelog', False, _('open changelog')),
1614 ('m', 'manifest', False, _('open manifest'))],
1615 ('m', 'manifest', False, _('open manifest'))],
1615 _('-c|-m|FILE REV'))
1616 _('-c|-m|FILE REV'))
1616 def debugdata(ui, repo, file_, rev = None, **opts):
1617 def debugdata(ui, repo, file_, rev = None, **opts):
1617 """dump the contents of a data file revision"""
1618 """dump the contents of a data file revision"""
1618 if opts.get('changelog') or opts.get('manifest'):
1619 if opts.get('changelog') or opts.get('manifest'):
1619 file_, rev = None, file_
1620 file_, rev = None, file_
1620 elif rev is None:
1621 elif rev is None:
1621 raise error.CommandError('debugdata', _('invalid arguments'))
1622 raise error.CommandError('debugdata', _('invalid arguments'))
1622 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1623 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1623 try:
1624 try:
1624 ui.write(r.revision(r.lookup(rev)))
1625 ui.write(r.revision(r.lookup(rev)))
1625 except KeyError:
1626 except KeyError:
1626 raise util.Abort(_('invalid revision identifier %s') % rev)
1627 raise util.Abort(_('invalid revision identifier %s') % rev)
1627
1628
1628 @command('debugdate',
1629 @command('debugdate',
1629 [('e', 'extended', None, _('try extended date formats'))],
1630 [('e', 'extended', None, _('try extended date formats'))],
1630 _('[-e] DATE [RANGE]'))
1631 _('[-e] DATE [RANGE]'))
1631 def debugdate(ui, date, range=None, **opts):
1632 def debugdate(ui, date, range=None, **opts):
1632 """parse and display a date"""
1633 """parse and display a date"""
1633 if opts["extended"]:
1634 if opts["extended"]:
1634 d = util.parsedate(date, util.extendeddateformats)
1635 d = util.parsedate(date, util.extendeddateformats)
1635 else:
1636 else:
1636 d = util.parsedate(date)
1637 d = util.parsedate(date)
1637 ui.write("internal: %s %s\n" % d)
1638 ui.write("internal: %s %s\n" % d)
1638 ui.write("standard: %s\n" % util.datestr(d))
1639 ui.write("standard: %s\n" % util.datestr(d))
1639 if range:
1640 if range:
1640 m = util.matchdate(range)
1641 m = util.matchdate(range)
1641 ui.write("match: %s\n" % m(d[0]))
1642 ui.write("match: %s\n" % m(d[0]))
1642
1643
1643 @command('debugdiscovery',
1644 @command('debugdiscovery',
1644 [('', 'old', None, _('use old-style discovery')),
1645 [('', 'old', None, _('use old-style discovery')),
1645 ('', 'nonheads', None,
1646 ('', 'nonheads', None,
1646 _('use old-style discovery with non-heads included')),
1647 _('use old-style discovery with non-heads included')),
1647 ] + remoteopts,
1648 ] + remoteopts,
1648 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1649 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1649 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1650 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1650 """runs the changeset discovery protocol in isolation"""
1651 """runs the changeset discovery protocol in isolation"""
1651 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl), opts.get('branch'))
1652 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl), opts.get('branch'))
1652 remote = hg.peer(repo, opts, remoteurl)
1653 remote = hg.peer(repo, opts, remoteurl)
1653 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1654 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1654
1655
1655 # make sure tests are repeatable
1656 # make sure tests are repeatable
1656 random.seed(12323)
1657 random.seed(12323)
1657
1658
1658 def doit(localheads, remoteheads):
1659 def doit(localheads, remoteheads):
1659 if opts.get('old'):
1660 if opts.get('old'):
1660 if localheads:
1661 if localheads:
1661 raise util.Abort('cannot use localheads with old style discovery')
1662 raise util.Abort('cannot use localheads with old style discovery')
1662 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1663 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1663 force=True)
1664 force=True)
1664 common = set(common)
1665 common = set(common)
1665 if not opts.get('nonheads'):
1666 if not opts.get('nonheads'):
1666 ui.write("unpruned common: %s\n" % " ".join([short(n)
1667 ui.write("unpruned common: %s\n" % " ".join([short(n)
1667 for n in common]))
1668 for n in common]))
1668 dag = dagutil.revlogdag(repo.changelog)
1669 dag = dagutil.revlogdag(repo.changelog)
1669 all = dag.ancestorset(dag.internalizeall(common))
1670 all = dag.ancestorset(dag.internalizeall(common))
1670 common = dag.externalizeall(dag.headsetofconnecteds(all))
1671 common = dag.externalizeall(dag.headsetofconnecteds(all))
1671 else:
1672 else:
1672 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1673 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1673 common = set(common)
1674 common = set(common)
1674 rheads = set(hds)
1675 rheads = set(hds)
1675 lheads = set(repo.heads())
1676 lheads = set(repo.heads())
1676 ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
1677 ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
1677 if lheads <= common:
1678 if lheads <= common:
1678 ui.write("local is subset\n")
1679 ui.write("local is subset\n")
1679 elif rheads <= common:
1680 elif rheads <= common:
1680 ui.write("remote is subset\n")
1681 ui.write("remote is subset\n")
1681
1682
1682 serverlogs = opts.get('serverlog')
1683 serverlogs = opts.get('serverlog')
1683 if serverlogs:
1684 if serverlogs:
1684 for filename in serverlogs:
1685 for filename in serverlogs:
1685 logfile = open(filename, 'r')
1686 logfile = open(filename, 'r')
1686 try:
1687 try:
1687 line = logfile.readline()
1688 line = logfile.readline()
1688 while line:
1689 while line:
1689 parts = line.strip().split(';')
1690 parts = line.strip().split(';')
1690 op = parts[1]
1691 op = parts[1]
1691 if op == 'cg':
1692 if op == 'cg':
1692 pass
1693 pass
1693 elif op == 'cgss':
1694 elif op == 'cgss':
1694 doit(parts[2].split(' '), parts[3].split(' '))
1695 doit(parts[2].split(' '), parts[3].split(' '))
1695 elif op == 'unb':
1696 elif op == 'unb':
1696 doit(parts[3].split(' '), parts[2].split(' '))
1697 doit(parts[3].split(' '), parts[2].split(' '))
1697 line = logfile.readline()
1698 line = logfile.readline()
1698 finally:
1699 finally:
1699 logfile.close()
1700 logfile.close()
1700
1701
1701 else:
1702 else:
1702 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1703 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1703 opts.get('remote_head'))
1704 opts.get('remote_head'))
1704 localrevs = opts.get('local_head')
1705 localrevs = opts.get('local_head')
1705 doit(localrevs, remoterevs)
1706 doit(localrevs, remoterevs)
1706
1707
1707 @command('debugfileset', [], ('REVSPEC'))
1708 @command('debugfileset', [], ('REVSPEC'))
1708 def debugfileset(ui, repo, expr):
1709 def debugfileset(ui, repo, expr):
1709 '''parse and apply a fileset specification'''
1710 '''parse and apply a fileset specification'''
1710 if ui.verbose:
1711 if ui.verbose:
1711 tree = fileset.parse(expr)[0]
1712 tree = fileset.parse(expr)[0]
1712 ui.note(tree, "\n")
1713 ui.note(tree, "\n")
1713
1714
1714 for f in fileset.getfileset(repo[None], expr):
1715 for f in fileset.getfileset(repo[None], expr):
1715 ui.write("%s\n" % f)
1716 ui.write("%s\n" % f)
1716
1717
1717 @command('debugfsinfo', [], _('[PATH]'))
1718 @command('debugfsinfo', [], _('[PATH]'))
1718 def debugfsinfo(ui, path = "."):
1719 def debugfsinfo(ui, path = "."):
1719 """show information detected about current filesystem"""
1720 """show information detected about current filesystem"""
1720 util.writefile('.debugfsinfo', '')
1721 util.writefile('.debugfsinfo', '')
1721 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1722 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1722 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1723 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1723 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1724 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1724 and 'yes' or 'no'))
1725 and 'yes' or 'no'))
1725 os.unlink('.debugfsinfo')
1726 os.unlink('.debugfsinfo')
1726
1727
1727 @command('debuggetbundle',
1728 @command('debuggetbundle',
1728 [('H', 'head', [], _('id of head node'), _('ID')),
1729 [('H', 'head', [], _('id of head node'), _('ID')),
1729 ('C', 'common', [], _('id of common node'), _('ID')),
1730 ('C', 'common', [], _('id of common node'), _('ID')),
1730 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1731 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1731 _('REPO FILE [-H|-C ID]...'))
1732 _('REPO FILE [-H|-C ID]...'))
1732 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1733 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1733 """retrieves a bundle from a repo
1734 """retrieves a bundle from a repo
1734
1735
1735 Every ID must be a full-length hex node id string. Saves the bundle to the
1736 Every ID must be a full-length hex node id string. Saves the bundle to the
1736 given file.
1737 given file.
1737 """
1738 """
1738 repo = hg.peer(ui, opts, repopath)
1739 repo = hg.peer(ui, opts, repopath)
1739 if not repo.capable('getbundle'):
1740 if not repo.capable('getbundle'):
1740 raise util.Abort("getbundle() not supported by target repository")
1741 raise util.Abort("getbundle() not supported by target repository")
1741 args = {}
1742 args = {}
1742 if common:
1743 if common:
1743 args['common'] = [bin(s) for s in common]
1744 args['common'] = [bin(s) for s in common]
1744 if head:
1745 if head:
1745 args['heads'] = [bin(s) for s in head]
1746 args['heads'] = [bin(s) for s in head]
1746 bundle = repo.getbundle('debug', **args)
1747 bundle = repo.getbundle('debug', **args)
1747
1748
1748 bundletype = opts.get('type', 'bzip2').lower()
1749 bundletype = opts.get('type', 'bzip2').lower()
1749 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1750 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1750 bundletype = btypes.get(bundletype)
1751 bundletype = btypes.get(bundletype)
1751 if bundletype not in changegroup.bundletypes:
1752 if bundletype not in changegroup.bundletypes:
1752 raise util.Abort(_('unknown bundle type specified with --type'))
1753 raise util.Abort(_('unknown bundle type specified with --type'))
1753 changegroup.writebundle(bundle, bundlepath, bundletype)
1754 changegroup.writebundle(bundle, bundlepath, bundletype)
1754
1755
1755 @command('debugignore', [], '')
1756 @command('debugignore', [], '')
1756 def debugignore(ui, repo, *values, **opts):
1757 def debugignore(ui, repo, *values, **opts):
1757 """display the combined ignore pattern"""
1758 """display the combined ignore pattern"""
1758 ignore = repo.dirstate._ignore
1759 ignore = repo.dirstate._ignore
1759 includepat = getattr(ignore, 'includepat', None)
1760 includepat = getattr(ignore, 'includepat', None)
1760 if includepat is not None:
1761 if includepat is not None:
1761 ui.write("%s\n" % includepat)
1762 ui.write("%s\n" % includepat)
1762 else:
1763 else:
1763 raise util.Abort(_("no ignore patterns found"))
1764 raise util.Abort(_("no ignore patterns found"))
1764
1765
1765 @command('debugindex',
1766 @command('debugindex',
1766 [('c', 'changelog', False, _('open changelog')),
1767 [('c', 'changelog', False, _('open changelog')),
1767 ('m', 'manifest', False, _('open manifest')),
1768 ('m', 'manifest', False, _('open manifest')),
1768 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1769 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1769 _('[-f FORMAT] -c|-m|FILE'))
1770 _('[-f FORMAT] -c|-m|FILE'))
1770 def debugindex(ui, repo, file_ = None, **opts):
1771 def debugindex(ui, repo, file_ = None, **opts):
1771 """dump the contents of an index file"""
1772 """dump the contents of an index file"""
1772 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1773 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1773 format = opts.get('format', 0)
1774 format = opts.get('format', 0)
1774 if format not in (0, 1):
1775 if format not in (0, 1):
1775 raise util.Abort(_("unknown format %d") % format)
1776 raise util.Abort(_("unknown format %d") % format)
1776
1777
1777 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1778 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1778 if generaldelta:
1779 if generaldelta:
1779 basehdr = ' delta'
1780 basehdr = ' delta'
1780 else:
1781 else:
1781 basehdr = ' base'
1782 basehdr = ' base'
1782
1783
1783 if format == 0:
1784 if format == 0:
1784 ui.write(" rev offset length " + basehdr + " linkrev"
1785 ui.write(" rev offset length " + basehdr + " linkrev"
1785 " nodeid p1 p2\n")
1786 " nodeid p1 p2\n")
1786 elif format == 1:
1787 elif format == 1:
1787 ui.write(" rev flag offset length"
1788 ui.write(" rev flag offset length"
1788 " size " + basehdr + " link p1 p2 nodeid\n")
1789 " size " + basehdr + " link p1 p2 nodeid\n")
1789
1790
1790 for i in r:
1791 for i in r:
1791 node = r.node(i)
1792 node = r.node(i)
1792 if generaldelta:
1793 if generaldelta:
1793 base = r.deltaparent(i)
1794 base = r.deltaparent(i)
1794 else:
1795 else:
1795 base = r.chainbase(i)
1796 base = r.chainbase(i)
1796 if format == 0:
1797 if format == 0:
1797 try:
1798 try:
1798 pp = r.parents(node)
1799 pp = r.parents(node)
1799 except:
1800 except:
1800 pp = [nullid, nullid]
1801 pp = [nullid, nullid]
1801 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1802 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1802 i, r.start(i), r.length(i), base, r.linkrev(i),
1803 i, r.start(i), r.length(i), base, r.linkrev(i),
1803 short(node), short(pp[0]), short(pp[1])))
1804 short(node), short(pp[0]), short(pp[1])))
1804 elif format == 1:
1805 elif format == 1:
1805 pr = r.parentrevs(i)
1806 pr = r.parentrevs(i)
1806 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1807 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1807 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1808 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1808 base, r.linkrev(i), pr[0], pr[1], short(node)))
1809 base, r.linkrev(i), pr[0], pr[1], short(node)))
1809
1810
1810 @command('debugindexdot', [], _('FILE'))
1811 @command('debugindexdot', [], _('FILE'))
1811 def debugindexdot(ui, repo, file_):
1812 def debugindexdot(ui, repo, file_):
1812 """dump an index DAG as a graphviz dot file"""
1813 """dump an index DAG as a graphviz dot file"""
1813 r = None
1814 r = None
1814 if repo:
1815 if repo:
1815 filelog = repo.file(file_)
1816 filelog = repo.file(file_)
1816 if len(filelog):
1817 if len(filelog):
1817 r = filelog
1818 r = filelog
1818 if not r:
1819 if not r:
1819 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1820 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1820 ui.write("digraph G {\n")
1821 ui.write("digraph G {\n")
1821 for i in r:
1822 for i in r:
1822 node = r.node(i)
1823 node = r.node(i)
1823 pp = r.parents(node)
1824 pp = r.parents(node)
1824 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1825 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1825 if pp[1] != nullid:
1826 if pp[1] != nullid:
1826 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1827 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1827 ui.write("}\n")
1828 ui.write("}\n")
1828
1829
1829 @command('debuginstall', [], '')
1830 @command('debuginstall', [], '')
1830 def debuginstall(ui):
1831 def debuginstall(ui):
1831 '''test Mercurial installation
1832 '''test Mercurial installation
1832
1833
1833 Returns 0 on success.
1834 Returns 0 on success.
1834 '''
1835 '''
1835
1836
1836 def writetemp(contents):
1837 def writetemp(contents):
1837 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1838 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1838 f = os.fdopen(fd, "wb")
1839 f = os.fdopen(fd, "wb")
1839 f.write(contents)
1840 f.write(contents)
1840 f.close()
1841 f.close()
1841 return name
1842 return name
1842
1843
1843 problems = 0
1844 problems = 0
1844
1845
1845 # encoding
1846 # encoding
1846 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1847 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1847 try:
1848 try:
1848 encoding.fromlocal("test")
1849 encoding.fromlocal("test")
1849 except util.Abort, inst:
1850 except util.Abort, inst:
1850 ui.write(" %s\n" % inst)
1851 ui.write(" %s\n" % inst)
1851 ui.write(_(" (check that your locale is properly set)\n"))
1852 ui.write(_(" (check that your locale is properly set)\n"))
1852 problems += 1
1853 problems += 1
1853
1854
1854 # compiled modules
1855 # compiled modules
1855 ui.status(_("Checking installed modules (%s)...\n")
1856 ui.status(_("Checking installed modules (%s)...\n")
1856 % os.path.dirname(__file__))
1857 % os.path.dirname(__file__))
1857 try:
1858 try:
1858 import bdiff, mpatch, base85, osutil
1859 import bdiff, mpatch, base85, osutil
1859 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
1860 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
1860 except Exception, inst:
1861 except Exception, inst:
1861 ui.write(" %s\n" % inst)
1862 ui.write(" %s\n" % inst)
1862 ui.write(_(" One or more extensions could not be found"))
1863 ui.write(_(" One or more extensions could not be found"))
1863 ui.write(_(" (check that you compiled the extensions)\n"))
1864 ui.write(_(" (check that you compiled the extensions)\n"))
1864 problems += 1
1865 problems += 1
1865
1866
1866 # templates
1867 # templates
1867 import templater
1868 import templater
1868 p = templater.templatepath()
1869 p = templater.templatepath()
1869 ui.status(_("Checking templates (%s)...\n") % ' '.join(p))
1870 ui.status(_("Checking templates (%s)...\n") % ' '.join(p))
1870 try:
1871 try:
1871 templater.templater(templater.templatepath("map-cmdline.default"))
1872 templater.templater(templater.templatepath("map-cmdline.default"))
1872 except Exception, inst:
1873 except Exception, inst:
1873 ui.write(" %s\n" % inst)
1874 ui.write(" %s\n" % inst)
1874 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1875 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1875 problems += 1
1876 problems += 1
1876
1877
1877 # editor
1878 # editor
1878 ui.status(_("Checking commit editor...\n"))
1879 ui.status(_("Checking commit editor...\n"))
1879 editor = ui.geteditor()
1880 editor = ui.geteditor()
1880 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
1881 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
1881 if not cmdpath:
1882 if not cmdpath:
1882 if editor == 'vi':
1883 if editor == 'vi':
1883 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1884 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1884 ui.write(_(" (specify a commit editor in your configuration"
1885 ui.write(_(" (specify a commit editor in your configuration"
1885 " file)\n"))
1886 " file)\n"))
1886 else:
1887 else:
1887 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1888 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1888 ui.write(_(" (specify a commit editor in your configuration"
1889 ui.write(_(" (specify a commit editor in your configuration"
1889 " file)\n"))
1890 " file)\n"))
1890 problems += 1
1891 problems += 1
1891
1892
1892 # check username
1893 # check username
1893 ui.status(_("Checking username...\n"))
1894 ui.status(_("Checking username...\n"))
1894 try:
1895 try:
1895 ui.username()
1896 ui.username()
1896 except util.Abort, e:
1897 except util.Abort, e:
1897 ui.write(" %s\n" % e)
1898 ui.write(" %s\n" % e)
1898 ui.write(_(" (specify a username in your configuration file)\n"))
1899 ui.write(_(" (specify a username in your configuration file)\n"))
1899 problems += 1
1900 problems += 1
1900
1901
1901 if not problems:
1902 if not problems:
1902 ui.status(_("No problems detected\n"))
1903 ui.status(_("No problems detected\n"))
1903 else:
1904 else:
1904 ui.write(_("%s problems detected,"
1905 ui.write(_("%s problems detected,"
1905 " please check your install!\n") % problems)
1906 " please check your install!\n") % problems)
1906
1907
1907 return problems
1908 return problems
1908
1909
1909 @command('debugknown', [], _('REPO ID...'))
1910 @command('debugknown', [], _('REPO ID...'))
1910 def debugknown(ui, repopath, *ids, **opts):
1911 def debugknown(ui, repopath, *ids, **opts):
1911 """test whether node ids are known to a repo
1912 """test whether node ids are known to a repo
1912
1913
1913 Every ID must be a full-length hex node id string. Returns a list of 0s and 1s
1914 Every ID must be a full-length hex node id string. Returns a list of 0s and 1s
1914 indicating unknown/known.
1915 indicating unknown/known.
1915 """
1916 """
1916 repo = hg.peer(ui, opts, repopath)
1917 repo = hg.peer(ui, opts, repopath)
1917 if not repo.capable('known'):
1918 if not repo.capable('known'):
1918 raise util.Abort("known() not supported by target repository")
1919 raise util.Abort("known() not supported by target repository")
1919 flags = repo.known([bin(s) for s in ids])
1920 flags = repo.known([bin(s) for s in ids])
1920 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1921 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1921
1922
1922 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
1923 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
1923 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
1924 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
1924 '''access the pushkey key/value protocol
1925 '''access the pushkey key/value protocol
1925
1926
1926 With two args, list the keys in the given namespace.
1927 With two args, list the keys in the given namespace.
1927
1928
1928 With five args, set a key to new if it currently is set to old.
1929 With five args, set a key to new if it currently is set to old.
1929 Reports success or failure.
1930 Reports success or failure.
1930 '''
1931 '''
1931
1932
1932 target = hg.peer(ui, {}, repopath)
1933 target = hg.peer(ui, {}, repopath)
1933 if keyinfo:
1934 if keyinfo:
1934 key, old, new = keyinfo
1935 key, old, new = keyinfo
1935 r = target.pushkey(namespace, key, old, new)
1936 r = target.pushkey(namespace, key, old, new)
1936 ui.status(str(r) + '\n')
1937 ui.status(str(r) + '\n')
1937 return not r
1938 return not r
1938 else:
1939 else:
1939 for k, v in target.listkeys(namespace).iteritems():
1940 for k, v in target.listkeys(namespace).iteritems():
1940 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1941 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1941 v.encode('string-escape')))
1942 v.encode('string-escape')))
1942
1943
1943 @command('debugrebuildstate',
1944 @command('debugrebuildstate',
1944 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
1945 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
1945 _('[-r REV] [REV]'))
1946 _('[-r REV] [REV]'))
1946 def debugrebuildstate(ui, repo, rev="tip"):
1947 def debugrebuildstate(ui, repo, rev="tip"):
1947 """rebuild the dirstate as it would look like for the given revision"""
1948 """rebuild the dirstate as it would look like for the given revision"""
1948 ctx = scmutil.revsingle(repo, rev)
1949 ctx = scmutil.revsingle(repo, rev)
1949 wlock = repo.wlock()
1950 wlock = repo.wlock()
1950 try:
1951 try:
1951 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1952 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1952 finally:
1953 finally:
1953 wlock.release()
1954 wlock.release()
1954
1955
1955 @command('debugrename',
1956 @command('debugrename',
1956 [('r', 'rev', '', _('revision to debug'), _('REV'))],
1957 [('r', 'rev', '', _('revision to debug'), _('REV'))],
1957 _('[-r REV] FILE'))
1958 _('[-r REV] FILE'))
1958 def debugrename(ui, repo, file1, *pats, **opts):
1959 def debugrename(ui, repo, file1, *pats, **opts):
1959 """dump rename information"""
1960 """dump rename information"""
1960
1961
1961 ctx = scmutil.revsingle(repo, opts.get('rev'))
1962 ctx = scmutil.revsingle(repo, opts.get('rev'))
1962 m = scmutil.match(ctx, (file1,) + pats, opts)
1963 m = scmutil.match(ctx, (file1,) + pats, opts)
1963 for abs in ctx.walk(m):
1964 for abs in ctx.walk(m):
1964 fctx = ctx[abs]
1965 fctx = ctx[abs]
1965 o = fctx.filelog().renamed(fctx.filenode())
1966 o = fctx.filelog().renamed(fctx.filenode())
1966 rel = m.rel(abs)
1967 rel = m.rel(abs)
1967 if o:
1968 if o:
1968 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1969 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1969 else:
1970 else:
1970 ui.write(_("%s not renamed\n") % rel)
1971 ui.write(_("%s not renamed\n") % rel)
1971
1972
1972 @command('debugrevlog',
1973 @command('debugrevlog',
1973 [('c', 'changelog', False, _('open changelog')),
1974 [('c', 'changelog', False, _('open changelog')),
1974 ('m', 'manifest', False, _('open manifest')),
1975 ('m', 'manifest', False, _('open manifest')),
1975 ('d', 'dump', False, _('dump index data'))],
1976 ('d', 'dump', False, _('dump index data'))],
1976 _('-c|-m|FILE'))
1977 _('-c|-m|FILE'))
1977 def debugrevlog(ui, repo, file_ = None, **opts):
1978 def debugrevlog(ui, repo, file_ = None, **opts):
1978 """show data and statistics about a revlog"""
1979 """show data and statistics about a revlog"""
1979 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
1980 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
1980
1981
1981 if opts.get("dump"):
1982 if opts.get("dump"):
1982 numrevs = len(r)
1983 numrevs = len(r)
1983 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
1984 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
1984 " rawsize totalsize compression heads\n")
1985 " rawsize totalsize compression heads\n")
1985 ts = 0
1986 ts = 0
1986 heads = set()
1987 heads = set()
1987 for rev in xrange(numrevs):
1988 for rev in xrange(numrevs):
1988 dbase = r.deltaparent(rev)
1989 dbase = r.deltaparent(rev)
1989 if dbase == -1:
1990 if dbase == -1:
1990 dbase = rev
1991 dbase = rev
1991 cbase = r.chainbase(rev)
1992 cbase = r.chainbase(rev)
1992 p1, p2 = r.parentrevs(rev)
1993 p1, p2 = r.parentrevs(rev)
1993 rs = r.rawsize(rev)
1994 rs = r.rawsize(rev)
1994 ts = ts + rs
1995 ts = ts + rs
1995 heads -= set(r.parentrevs(rev))
1996 heads -= set(r.parentrevs(rev))
1996 heads.add(rev)
1997 heads.add(rev)
1997 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
1998 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
1998 (rev, p1, p2, r.start(rev), r.end(rev),
1999 (rev, p1, p2, r.start(rev), r.end(rev),
1999 r.start(dbase), r.start(cbase),
2000 r.start(dbase), r.start(cbase),
2000 r.start(p1), r.start(p2),
2001 r.start(p1), r.start(p2),
2001 rs, ts, ts / r.end(rev), len(heads)))
2002 rs, ts, ts / r.end(rev), len(heads)))
2002 return 0
2003 return 0
2003
2004
2004 v = r.version
2005 v = r.version
2005 format = v & 0xFFFF
2006 format = v & 0xFFFF
2006 flags = []
2007 flags = []
2007 gdelta = False
2008 gdelta = False
2008 if v & revlog.REVLOGNGINLINEDATA:
2009 if v & revlog.REVLOGNGINLINEDATA:
2009 flags.append('inline')
2010 flags.append('inline')
2010 if v & revlog.REVLOGGENERALDELTA:
2011 if v & revlog.REVLOGGENERALDELTA:
2011 gdelta = True
2012 gdelta = True
2012 flags.append('generaldelta')
2013 flags.append('generaldelta')
2013 if not flags:
2014 if not flags:
2014 flags = ['(none)']
2015 flags = ['(none)']
2015
2016
2016 nummerges = 0
2017 nummerges = 0
2017 numfull = 0
2018 numfull = 0
2018 numprev = 0
2019 numprev = 0
2019 nump1 = 0
2020 nump1 = 0
2020 nump2 = 0
2021 nump2 = 0
2021 numother = 0
2022 numother = 0
2022 nump1prev = 0
2023 nump1prev = 0
2023 nump2prev = 0
2024 nump2prev = 0
2024 chainlengths = []
2025 chainlengths = []
2025
2026
2026 datasize = [None, 0, 0L]
2027 datasize = [None, 0, 0L]
2027 fullsize = [None, 0, 0L]
2028 fullsize = [None, 0, 0L]
2028 deltasize = [None, 0, 0L]
2029 deltasize = [None, 0, 0L]
2029
2030
2030 def addsize(size, l):
2031 def addsize(size, l):
2031 if l[0] is None or size < l[0]:
2032 if l[0] is None or size < l[0]:
2032 l[0] = size
2033 l[0] = size
2033 if size > l[1]:
2034 if size > l[1]:
2034 l[1] = size
2035 l[1] = size
2035 l[2] += size
2036 l[2] += size
2036
2037
2037 numrevs = len(r)
2038 numrevs = len(r)
2038 for rev in xrange(numrevs):
2039 for rev in xrange(numrevs):
2039 p1, p2 = r.parentrevs(rev)
2040 p1, p2 = r.parentrevs(rev)
2040 delta = r.deltaparent(rev)
2041 delta = r.deltaparent(rev)
2041 if format > 0:
2042 if format > 0:
2042 addsize(r.rawsize(rev), datasize)
2043 addsize(r.rawsize(rev), datasize)
2043 if p2 != nullrev:
2044 if p2 != nullrev:
2044 nummerges += 1
2045 nummerges += 1
2045 size = r.length(rev)
2046 size = r.length(rev)
2046 if delta == nullrev:
2047 if delta == nullrev:
2047 chainlengths.append(0)
2048 chainlengths.append(0)
2048 numfull += 1
2049 numfull += 1
2049 addsize(size, fullsize)
2050 addsize(size, fullsize)
2050 else:
2051 else:
2051 chainlengths.append(chainlengths[delta] + 1)
2052 chainlengths.append(chainlengths[delta] + 1)
2052 addsize(size, deltasize)
2053 addsize(size, deltasize)
2053 if delta == rev - 1:
2054 if delta == rev - 1:
2054 numprev += 1
2055 numprev += 1
2055 if delta == p1:
2056 if delta == p1:
2056 nump1prev += 1
2057 nump1prev += 1
2057 elif delta == p2:
2058 elif delta == p2:
2058 nump2prev += 1
2059 nump2prev += 1
2059 elif delta == p1:
2060 elif delta == p1:
2060 nump1 += 1
2061 nump1 += 1
2061 elif delta == p2:
2062 elif delta == p2:
2062 nump2 += 1
2063 nump2 += 1
2063 elif delta != nullrev:
2064 elif delta != nullrev:
2064 numother += 1
2065 numother += 1
2065
2066
2066 numdeltas = numrevs - numfull
2067 numdeltas = numrevs - numfull
2067 numoprev = numprev - nump1prev - nump2prev
2068 numoprev = numprev - nump1prev - nump2prev
2068 totalrawsize = datasize[2]
2069 totalrawsize = datasize[2]
2069 datasize[2] /= numrevs
2070 datasize[2] /= numrevs
2070 fulltotal = fullsize[2]
2071 fulltotal = fullsize[2]
2071 fullsize[2] /= numfull
2072 fullsize[2] /= numfull
2072 deltatotal = deltasize[2]
2073 deltatotal = deltasize[2]
2073 deltasize[2] /= numrevs - numfull
2074 deltasize[2] /= numrevs - numfull
2074 totalsize = fulltotal + deltatotal
2075 totalsize = fulltotal + deltatotal
2075 avgchainlen = sum(chainlengths) / numrevs
2076 avgchainlen = sum(chainlengths) / numrevs
2076 compratio = totalrawsize / totalsize
2077 compratio = totalrawsize / totalsize
2077
2078
2078 basedfmtstr = '%%%dd\n'
2079 basedfmtstr = '%%%dd\n'
2079 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2080 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2080
2081
2081 def dfmtstr(max):
2082 def dfmtstr(max):
2082 return basedfmtstr % len(str(max))
2083 return basedfmtstr % len(str(max))
2083 def pcfmtstr(max, padding=0):
2084 def pcfmtstr(max, padding=0):
2084 return basepcfmtstr % (len(str(max)), ' ' * padding)
2085 return basepcfmtstr % (len(str(max)), ' ' * padding)
2085
2086
2086 def pcfmt(value, total):
2087 def pcfmt(value, total):
2087 return (value, 100 * float(value) / total)
2088 return (value, 100 * float(value) / total)
2088
2089
2089 ui.write('format : %d\n' % format)
2090 ui.write('format : %d\n' % format)
2090 ui.write('flags : %s\n' % ', '.join(flags))
2091 ui.write('flags : %s\n' % ', '.join(flags))
2091
2092
2092 ui.write('\n')
2093 ui.write('\n')
2093 fmt = pcfmtstr(totalsize)
2094 fmt = pcfmtstr(totalsize)
2094 fmt2 = dfmtstr(totalsize)
2095 fmt2 = dfmtstr(totalsize)
2095 ui.write('revisions : ' + fmt2 % numrevs)
2096 ui.write('revisions : ' + fmt2 % numrevs)
2096 ui.write(' merges : ' + fmt % pcfmt(nummerges, numrevs))
2097 ui.write(' merges : ' + fmt % pcfmt(nummerges, numrevs))
2097 ui.write(' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs))
2098 ui.write(' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs))
2098 ui.write('revisions : ' + fmt2 % numrevs)
2099 ui.write('revisions : ' + fmt2 % numrevs)
2099 ui.write(' full : ' + fmt % pcfmt(numfull, numrevs))
2100 ui.write(' full : ' + fmt % pcfmt(numfull, numrevs))
2100 ui.write(' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
2101 ui.write(' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
2101 ui.write('revision size : ' + fmt2 % totalsize)
2102 ui.write('revision size : ' + fmt2 % totalsize)
2102 ui.write(' full : ' + fmt % pcfmt(fulltotal, totalsize))
2103 ui.write(' full : ' + fmt % pcfmt(fulltotal, totalsize))
2103 ui.write(' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
2104 ui.write(' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
2104
2105
2105 ui.write('\n')
2106 ui.write('\n')
2106 fmt = dfmtstr(max(avgchainlen, compratio))
2107 fmt = dfmtstr(max(avgchainlen, compratio))
2107 ui.write('avg chain length : ' + fmt % avgchainlen)
2108 ui.write('avg chain length : ' + fmt % avgchainlen)
2108 ui.write('compression ratio : ' + fmt % compratio)
2109 ui.write('compression ratio : ' + fmt % compratio)
2109
2110
2110 if format > 0:
2111 if format > 0:
2111 ui.write('\n')
2112 ui.write('\n')
2112 ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
2113 ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
2113 % tuple(datasize))
2114 % tuple(datasize))
2114 ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
2115 ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
2115 % tuple(fullsize))
2116 % tuple(fullsize))
2116 ui.write('delta size (min/max/avg) : %d / %d / %d\n'
2117 ui.write('delta size (min/max/avg) : %d / %d / %d\n'
2117 % tuple(deltasize))
2118 % tuple(deltasize))
2118
2119
2119 if numdeltas > 0:
2120 if numdeltas > 0:
2120 ui.write('\n')
2121 ui.write('\n')
2121 fmt = pcfmtstr(numdeltas)
2122 fmt = pcfmtstr(numdeltas)
2122 fmt2 = pcfmtstr(numdeltas, 4)
2123 fmt2 = pcfmtstr(numdeltas, 4)
2123 ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
2124 ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
2124 if numprev > 0:
2125 if numprev > 0:
2125 ui.write(' where prev = p1 : ' + fmt2 % pcfmt(nump1prev, numprev))
2126 ui.write(' where prev = p1 : ' + fmt2 % pcfmt(nump1prev, numprev))
2126 ui.write(' where prev = p2 : ' + fmt2 % pcfmt(nump2prev, numprev))
2127 ui.write(' where prev = p2 : ' + fmt2 % pcfmt(nump2prev, numprev))
2127 ui.write(' other : ' + fmt2 % pcfmt(numoprev, numprev))
2128 ui.write(' other : ' + fmt2 % pcfmt(numoprev, numprev))
2128 if gdelta:
2129 if gdelta:
2129 ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
2130 ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
2130 ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
2131 ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
2131 ui.write('deltas against other : ' + fmt % pcfmt(numother, numdeltas))
2132 ui.write('deltas against other : ' + fmt % pcfmt(numother, numdeltas))
2132
2133
2133 @command('debugrevspec', [], ('REVSPEC'))
2134 @command('debugrevspec', [], ('REVSPEC'))
2134 def debugrevspec(ui, repo, expr):
2135 def debugrevspec(ui, repo, expr):
2135 '''parse and apply a revision specification'''
2136 '''parse and apply a revision specification'''
2136 if ui.verbose:
2137 if ui.verbose:
2137 tree = revset.parse(expr)[0]
2138 tree = revset.parse(expr)[0]
2138 ui.note(tree, "\n")
2139 ui.note(tree, "\n")
2139 newtree = revset.findaliases(ui, tree)
2140 newtree = revset.findaliases(ui, tree)
2140 if newtree != tree:
2141 if newtree != tree:
2141 ui.note(newtree, "\n")
2142 ui.note(newtree, "\n")
2142 func = revset.match(ui, expr)
2143 func = revset.match(ui, expr)
2143 for c in func(repo, range(len(repo))):
2144 for c in func(repo, range(len(repo))):
2144 ui.write("%s\n" % c)
2145 ui.write("%s\n" % c)
2145
2146
2146 @command('debugsetparents', [], _('REV1 [REV2]'))
2147 @command('debugsetparents', [], _('REV1 [REV2]'))
2147 def debugsetparents(ui, repo, rev1, rev2=None):
2148 def debugsetparents(ui, repo, rev1, rev2=None):
2148 """manually set the parents of the current working directory
2149 """manually set the parents of the current working directory
2149
2150
2150 This is useful for writing repository conversion tools, but should
2151 This is useful for writing repository conversion tools, but should
2151 be used with care.
2152 be used with care.
2152
2153
2153 Returns 0 on success.
2154 Returns 0 on success.
2154 """
2155 """
2155
2156
2156 r1 = scmutil.revsingle(repo, rev1).node()
2157 r1 = scmutil.revsingle(repo, rev1).node()
2157 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2158 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2158
2159
2159 wlock = repo.wlock()
2160 wlock = repo.wlock()
2160 try:
2161 try:
2161 repo.dirstate.setparents(r1, r2)
2162 repo.dirstate.setparents(r1, r2)
2162 finally:
2163 finally:
2163 wlock.release()
2164 wlock.release()
2164
2165
2165 @command('debugstate',
2166 @command('debugstate',
2166 [('', 'nodates', None, _('do not display the saved mtime')),
2167 [('', 'nodates', None, _('do not display the saved mtime')),
2167 ('', 'datesort', None, _('sort by saved mtime'))],
2168 ('', 'datesort', None, _('sort by saved mtime'))],
2168 _('[OPTION]...'))
2169 _('[OPTION]...'))
2169 def debugstate(ui, repo, nodates=None, datesort=None):
2170 def debugstate(ui, repo, nodates=None, datesort=None):
2170 """show the contents of the current dirstate"""
2171 """show the contents of the current dirstate"""
2171 timestr = ""
2172 timestr = ""
2172 showdate = not nodates
2173 showdate = not nodates
2173 if datesort:
2174 if datesort:
2174 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2175 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2175 else:
2176 else:
2176 keyfunc = None # sort by filename
2177 keyfunc = None # sort by filename
2177 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2178 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2178 if showdate:
2179 if showdate:
2179 if ent[3] == -1:
2180 if ent[3] == -1:
2180 # Pad or slice to locale representation
2181 # Pad or slice to locale representation
2181 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2182 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2182 time.localtime(0)))
2183 time.localtime(0)))
2183 timestr = 'unset'
2184 timestr = 'unset'
2184 timestr = (timestr[:locale_len] +
2185 timestr = (timestr[:locale_len] +
2185 ' ' * (locale_len - len(timestr)))
2186 ' ' * (locale_len - len(timestr)))
2186 else:
2187 else:
2187 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2188 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2188 time.localtime(ent[3]))
2189 time.localtime(ent[3]))
2189 if ent[1] & 020000:
2190 if ent[1] & 020000:
2190 mode = 'lnk'
2191 mode = 'lnk'
2191 else:
2192 else:
2192 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2193 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2193 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2194 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2194 for f in repo.dirstate.copies():
2195 for f in repo.dirstate.copies():
2195 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2196 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2196
2197
2197 @command('debugsub',
2198 @command('debugsub',
2198 [('r', 'rev', '',
2199 [('r', 'rev', '',
2199 _('revision to check'), _('REV'))],
2200 _('revision to check'), _('REV'))],
2200 _('[-r REV] [REV]'))
2201 _('[-r REV] [REV]'))
2201 def debugsub(ui, repo, rev=None):
2202 def debugsub(ui, repo, rev=None):
2202 ctx = scmutil.revsingle(repo, rev, None)
2203 ctx = scmutil.revsingle(repo, rev, None)
2203 for k, v in sorted(ctx.substate.items()):
2204 for k, v in sorted(ctx.substate.items()):
2204 ui.write('path %s\n' % k)
2205 ui.write('path %s\n' % k)
2205 ui.write(' source %s\n' % v[0])
2206 ui.write(' source %s\n' % v[0])
2206 ui.write(' revision %s\n' % v[1])
2207 ui.write(' revision %s\n' % v[1])
2207
2208
2208 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2209 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2209 def debugwalk(ui, repo, *pats, **opts):
2210 def debugwalk(ui, repo, *pats, **opts):
2210 """show how files match on given patterns"""
2211 """show how files match on given patterns"""
2211 m = scmutil.match(repo[None], pats, opts)
2212 m = scmutil.match(repo[None], pats, opts)
2212 items = list(repo.walk(m))
2213 items = list(repo.walk(m))
2213 if not items:
2214 if not items:
2214 return
2215 return
2215 fmt = 'f %%-%ds %%-%ds %%s' % (
2216 fmt = 'f %%-%ds %%-%ds %%s' % (
2216 max([len(abs) for abs in items]),
2217 max([len(abs) for abs in items]),
2217 max([len(m.rel(abs)) for abs in items]))
2218 max([len(m.rel(abs)) for abs in items]))
2218 for abs in items:
2219 for abs in items:
2219 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
2220 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
2220 ui.write("%s\n" % line.rstrip())
2221 ui.write("%s\n" % line.rstrip())
2221
2222
2222 @command('debugwireargs',
2223 @command('debugwireargs',
2223 [('', 'three', '', 'three'),
2224 [('', 'three', '', 'three'),
2224 ('', 'four', '', 'four'),
2225 ('', 'four', '', 'four'),
2225 ('', 'five', '', 'five'),
2226 ('', 'five', '', 'five'),
2226 ] + remoteopts,
2227 ] + remoteopts,
2227 _('REPO [OPTIONS]... [ONE [TWO]]'))
2228 _('REPO [OPTIONS]... [ONE [TWO]]'))
2228 def debugwireargs(ui, repopath, *vals, **opts):
2229 def debugwireargs(ui, repopath, *vals, **opts):
2229 repo = hg.peer(ui, opts, repopath)
2230 repo = hg.peer(ui, opts, repopath)
2230 for opt in remoteopts:
2231 for opt in remoteopts:
2231 del opts[opt[1]]
2232 del opts[opt[1]]
2232 args = {}
2233 args = {}
2233 for k, v in opts.iteritems():
2234 for k, v in opts.iteritems():
2234 if v:
2235 if v:
2235 args[k] = v
2236 args[k] = v
2236 # run twice to check that we don't mess up the stream for the next command
2237 # run twice to check that we don't mess up the stream for the next command
2237 res1 = repo.debugwireargs(*vals, **args)
2238 res1 = repo.debugwireargs(*vals, **args)
2238 res2 = repo.debugwireargs(*vals, **args)
2239 res2 = repo.debugwireargs(*vals, **args)
2239 ui.write("%s\n" % res1)
2240 ui.write("%s\n" % res1)
2240 if res1 != res2:
2241 if res1 != res2:
2241 ui.warn("%s\n" % res2)
2242 ui.warn("%s\n" % res2)
2242
2243
2243 @command('^diff',
2244 @command('^diff',
2244 [('r', 'rev', [], _('revision'), _('REV')),
2245 [('r', 'rev', [], _('revision'), _('REV')),
2245 ('c', 'change', '', _('change made by revision'), _('REV'))
2246 ('c', 'change', '', _('change made by revision'), _('REV'))
2246 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2247 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2247 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2248 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2248 def diff(ui, repo, *pats, **opts):
2249 def diff(ui, repo, *pats, **opts):
2249 """diff repository (or selected files)
2250 """diff repository (or selected files)
2250
2251
2251 Show differences between revisions for the specified files.
2252 Show differences between revisions for the specified files.
2252
2253
2253 Differences between files are shown using the unified diff format.
2254 Differences between files are shown using the unified diff format.
2254
2255
2255 .. note::
2256 .. note::
2256 diff may generate unexpected results for merges, as it will
2257 diff may generate unexpected results for merges, as it will
2257 default to comparing against the working directory's first
2258 default to comparing against the working directory's first
2258 parent changeset if no revisions are specified.
2259 parent changeset if no revisions are specified.
2259
2260
2260 When two revision arguments are given, then changes are shown
2261 When two revision arguments are given, then changes are shown
2261 between those revisions. If only one revision is specified then
2262 between those revisions. If only one revision is specified then
2262 that revision is compared to the working directory, and, when no
2263 that revision is compared to the working directory, and, when no
2263 revisions are specified, the working directory files are compared
2264 revisions are specified, the working directory files are compared
2264 to its parent.
2265 to its parent.
2265
2266
2266 Alternatively you can specify -c/--change with a revision to see
2267 Alternatively you can specify -c/--change with a revision to see
2267 the changes in that changeset relative to its first parent.
2268 the changes in that changeset relative to its first parent.
2268
2269
2269 Without the -a/--text option, diff will avoid generating diffs of
2270 Without the -a/--text option, diff will avoid generating diffs of
2270 files it detects as binary. With -a, diff will generate a diff
2271 files it detects as binary. With -a, diff will generate a diff
2271 anyway, probably with undesirable results.
2272 anyway, probably with undesirable results.
2272
2273
2273 Use the -g/--git option to generate diffs in the git extended diff
2274 Use the -g/--git option to generate diffs in the git extended diff
2274 format. For more information, read :hg:`help diffs`.
2275 format. For more information, read :hg:`help diffs`.
2275
2276
2276 .. container:: verbose
2277 .. container:: verbose
2277
2278
2278 Examples:
2279 Examples:
2279
2280
2280 - compare a file in the current working directory to its parent::
2281 - compare a file in the current working directory to its parent::
2281
2282
2282 hg diff foo.c
2283 hg diff foo.c
2283
2284
2284 - compare two historical versions of a directory, with rename info::
2285 - compare two historical versions of a directory, with rename info::
2285
2286
2286 hg diff --git -r 1.0:1.2 lib/
2287 hg diff --git -r 1.0:1.2 lib/
2287
2288
2288 - get change stats relative to the last change on some date::
2289 - get change stats relative to the last change on some date::
2289
2290
2290 hg diff --stat -r "date('may 2')"
2291 hg diff --stat -r "date('may 2')"
2291
2292
2292 - diff all newly-added files that contain a keyword::
2293 - diff all newly-added files that contain a keyword::
2293
2294
2294 hg diff "set:added() and grep(GNU)"
2295 hg diff "set:added() and grep(GNU)"
2295
2296
2296 - compare a revision and its parents::
2297 - compare a revision and its parents::
2297
2298
2298 hg diff -c 9353 # compare against first parent
2299 hg diff -c 9353 # compare against first parent
2299 hg diff -r 9353^:9353 # same using revset syntax
2300 hg diff -r 9353^:9353 # same using revset syntax
2300 hg diff -r 9353^2:9353 # compare against the second parent
2301 hg diff -r 9353^2:9353 # compare against the second parent
2301
2302
2302 Returns 0 on success.
2303 Returns 0 on success.
2303 """
2304 """
2304
2305
2305 revs = opts.get('rev')
2306 revs = opts.get('rev')
2306 change = opts.get('change')
2307 change = opts.get('change')
2307 stat = opts.get('stat')
2308 stat = opts.get('stat')
2308 reverse = opts.get('reverse')
2309 reverse = opts.get('reverse')
2309
2310
2310 if revs and change:
2311 if revs and change:
2311 msg = _('cannot specify --rev and --change at the same time')
2312 msg = _('cannot specify --rev and --change at the same time')
2312 raise util.Abort(msg)
2313 raise util.Abort(msg)
2313 elif change:
2314 elif change:
2314 node2 = scmutil.revsingle(repo, change, None).node()
2315 node2 = scmutil.revsingle(repo, change, None).node()
2315 node1 = repo[node2].p1().node()
2316 node1 = repo[node2].p1().node()
2316 else:
2317 else:
2317 node1, node2 = scmutil.revpair(repo, revs)
2318 node1, node2 = scmutil.revpair(repo, revs)
2318
2319
2319 if reverse:
2320 if reverse:
2320 node1, node2 = node2, node1
2321 node1, node2 = node2, node1
2321
2322
2322 diffopts = patch.diffopts(ui, opts)
2323 diffopts = patch.diffopts(ui, opts)
2323 m = scmutil.match(repo[node2], pats, opts)
2324 m = scmutil.match(repo[node2], pats, opts)
2324 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2325 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2325 listsubrepos=opts.get('subrepos'))
2326 listsubrepos=opts.get('subrepos'))
2326
2327
2327 @command('^export',
2328 @command('^export',
2328 [('o', 'output', '',
2329 [('o', 'output', '',
2329 _('print output to file with formatted name'), _('FORMAT')),
2330 _('print output to file with formatted name'), _('FORMAT')),
2330 ('', 'switch-parent', None, _('diff against the second parent')),
2331 ('', 'switch-parent', None, _('diff against the second parent')),
2331 ('r', 'rev', [], _('revisions to export'), _('REV')),
2332 ('r', 'rev', [], _('revisions to export'), _('REV')),
2332 ] + diffopts,
2333 ] + diffopts,
2333 _('[OPTION]... [-o OUTFILESPEC] REV...'))
2334 _('[OPTION]... [-o OUTFILESPEC] REV...'))
2334 def export(ui, repo, *changesets, **opts):
2335 def export(ui, repo, *changesets, **opts):
2335 """dump the header and diffs for one or more changesets
2336 """dump the header and diffs for one or more changesets
2336
2337
2337 Print the changeset header and diffs for one or more revisions.
2338 Print the changeset header and diffs for one or more revisions.
2338
2339
2339 The information shown in the changeset header is: author, date,
2340 The information shown in the changeset header is: author, date,
2340 branch name (if non-default), changeset hash, parent(s) and commit
2341 branch name (if non-default), changeset hash, parent(s) and commit
2341 comment.
2342 comment.
2342
2343
2343 .. note::
2344 .. note::
2344 export may generate unexpected diff output for merge
2345 export may generate unexpected diff output for merge
2345 changesets, as it will compare the merge changeset against its
2346 changesets, as it will compare the merge changeset against its
2346 first parent only.
2347 first parent only.
2347
2348
2348 Output may be to a file, in which case the name of the file is
2349 Output may be to a file, in which case the name of the file is
2349 given using a format string. The formatting rules are as follows:
2350 given using a format string. The formatting rules are as follows:
2350
2351
2351 :``%%``: literal "%" character
2352 :``%%``: literal "%" character
2352 :``%H``: changeset hash (40 hexadecimal digits)
2353 :``%H``: changeset hash (40 hexadecimal digits)
2353 :``%N``: number of patches being generated
2354 :``%N``: number of patches being generated
2354 :``%R``: changeset revision number
2355 :``%R``: changeset revision number
2355 :``%b``: basename of the exporting repository
2356 :``%b``: basename of the exporting repository
2356 :``%h``: short-form changeset hash (12 hexadecimal digits)
2357 :``%h``: short-form changeset hash (12 hexadecimal digits)
2357 :``%m``: first line of the commit message (only alphanumeric characters)
2358 :``%m``: first line of the commit message (only alphanumeric characters)
2358 :``%n``: zero-padded sequence number, starting at 1
2359 :``%n``: zero-padded sequence number, starting at 1
2359 :``%r``: zero-padded changeset revision number
2360 :``%r``: zero-padded changeset revision number
2360
2361
2361 Without the -a/--text option, export will avoid generating diffs
2362 Without the -a/--text option, export will avoid generating diffs
2362 of files it detects as binary. With -a, export will generate a
2363 of files it detects as binary. With -a, export will generate a
2363 diff anyway, probably with undesirable results.
2364 diff anyway, probably with undesirable results.
2364
2365
2365 Use the -g/--git option to generate diffs in the git extended diff
2366 Use the -g/--git option to generate diffs in the git extended diff
2366 format. See :hg:`help diffs` for more information.
2367 format. See :hg:`help diffs` for more information.
2367
2368
2368 With the --switch-parent option, the diff will be against the
2369 With the --switch-parent option, the diff will be against the
2369 second parent. It can be useful to review a merge.
2370 second parent. It can be useful to review a merge.
2370
2371
2371 .. container:: verbose
2372 .. container:: verbose
2372
2373
2373 Examples:
2374 Examples:
2374
2375
2375 - use export and import to transplant a bugfix to the current
2376 - use export and import to transplant a bugfix to the current
2376 branch::
2377 branch::
2377
2378
2378 hg export -r 9353 | hg import -
2379 hg export -r 9353 | hg import -
2379
2380
2380 - export all the changesets between two revisions to a file with
2381 - export all the changesets between two revisions to a file with
2381 rename information::
2382 rename information::
2382
2383
2383 hg export --git -r 123:150 > changes.txt
2384 hg export --git -r 123:150 > changes.txt
2384
2385
2385 - split outgoing changes into a series of patches with
2386 - split outgoing changes into a series of patches with
2386 descriptive names::
2387 descriptive names::
2387
2388
2388 hg export -r "outgoing()" -o "%n-%m.patch"
2389 hg export -r "outgoing()" -o "%n-%m.patch"
2389
2390
2390 Returns 0 on success.
2391 Returns 0 on success.
2391 """
2392 """
2392 changesets += tuple(opts.get('rev', []))
2393 changesets += tuple(opts.get('rev', []))
2393 if not changesets:
2394 if not changesets:
2394 raise util.Abort(_("export requires at least one changeset"))
2395 raise util.Abort(_("export requires at least one changeset"))
2395 revs = scmutil.revrange(repo, changesets)
2396 revs = scmutil.revrange(repo, changesets)
2396 if len(revs) > 1:
2397 if len(revs) > 1:
2397 ui.note(_('exporting patches:\n'))
2398 ui.note(_('exporting patches:\n'))
2398 else:
2399 else:
2399 ui.note(_('exporting patch:\n'))
2400 ui.note(_('exporting patch:\n'))
2400 cmdutil.export(repo, revs, template=opts.get('output'),
2401 cmdutil.export(repo, revs, template=opts.get('output'),
2401 switch_parent=opts.get('switch_parent'),
2402 switch_parent=opts.get('switch_parent'),
2402 opts=patch.diffopts(ui, opts))
2403 opts=patch.diffopts(ui, opts))
2403
2404
2404 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2405 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2405 def forget(ui, repo, *pats, **opts):
2406 def forget(ui, repo, *pats, **opts):
2406 """forget the specified files on the next commit
2407 """forget the specified files on the next commit
2407
2408
2408 Mark the specified files so they will no longer be tracked
2409 Mark the specified files so they will no longer be tracked
2409 after the next commit.
2410 after the next commit.
2410
2411
2411 This only removes files from the current branch, not from the
2412 This only removes files from the current branch, not from the
2412 entire project history, and it does not delete them from the
2413 entire project history, and it does not delete them from the
2413 working directory.
2414 working directory.
2414
2415
2415 To undo a forget before the next commit, see :hg:`add`.
2416 To undo a forget before the next commit, see :hg:`add`.
2416
2417
2417 .. container:: verbose
2418 .. container:: verbose
2418
2419
2419 Examples:
2420 Examples:
2420
2421
2421 - forget newly-added binary files::
2422 - forget newly-added binary files::
2422
2423
2423 hg forget "set:added() and binary()"
2424 hg forget "set:added() and binary()"
2424
2425
2425 - forget files that would be excluded by .hgignore::
2426 - forget files that would be excluded by .hgignore::
2426
2427
2427 hg forget "set:hgignore()"
2428 hg forget "set:hgignore()"
2428
2429
2429 Returns 0 on success.
2430 Returns 0 on success.
2430 """
2431 """
2431
2432
2432 if not pats:
2433 if not pats:
2433 raise util.Abort(_('no files specified'))
2434 raise util.Abort(_('no files specified'))
2434
2435
2435 m = scmutil.match(repo[None], pats, opts)
2436 wctx = repo[None]
2437 m = scmutil.match(wctx, pats, opts)
2436 s = repo.status(match=m, clean=True)
2438 s = repo.status(match=m, clean=True)
2437 forget = sorted(s[0] + s[1] + s[3] + s[6])
2439 forget = sorted(s[0] + s[1] + s[3] + s[6])
2440 subforget = {}
2438 errs = 0
2441 errs = 0
2439
2442
2443 for subpath in wctx.substate:
2444 sub = wctx.sub(subpath)
2445 try:
2446 submatch = matchmod.narrowmatcher(subpath, m)
2447 for fsub in sub.walk(submatch):
2448 if submatch.exact(fsub):
2449 subforget[os.path.join(subpath, fsub)] = (fsub, sub)
2450 except error.LookupError:
2451 ui.status(_("skipping missing subrepository: %s\n") % subpath)
2452
2440 for f in m.files():
2453 for f in m.files():
2441 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
2454 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
2442 if os.path.exists(m.rel(f)):
2455 if f not in subforget:
2443 ui.warn(_('not removing %s: file is already untracked\n')
2456 if os.path.exists(m.rel(f)):
2444 % m.rel(f))
2457 ui.warn(_('not removing %s: file is already untracked\n')
2445 errs = 1
2458 % m.rel(f))
2459 errs = 1
2446
2460
2447 for f in forget:
2461 for f in forget:
2448 if ui.verbose or not m.exact(f):
2462 if ui.verbose or not m.exact(f):
2449 ui.status(_('removing %s\n') % m.rel(f))
2463 ui.status(_('removing %s\n') % m.rel(f))
2450
2464
2451 repo[None].forget(forget)
2465 if ui.verbose:
2466 for f in sorted(subforget.keys()):
2467 ui.status(_('removing %s\n') % m.rel(f))
2468
2469 wctx.forget(forget)
2470
2471 for f in sorted(subforget.keys()):
2472 fsub, sub = subforget[f]
2473 sub.forget([fsub])
2474
2452 return errs
2475 return errs
2453
2476
2454 @command(
2477 @command(
2455 'graft',
2478 'graft',
2456 [('c', 'continue', False, _('resume interrupted graft')),
2479 [('c', 'continue', False, _('resume interrupted graft')),
2457 ('e', 'edit', False, _('invoke editor on commit messages')),
2480 ('e', 'edit', False, _('invoke editor on commit messages')),
2458 ('D', 'currentdate', False,
2481 ('D', 'currentdate', False,
2459 _('record the current date as commit date')),
2482 _('record the current date as commit date')),
2460 ('U', 'currentuser', False,
2483 ('U', 'currentuser', False,
2461 _('record the current user as committer'), _('DATE'))]
2484 _('record the current user as committer'), _('DATE'))]
2462 + commitopts2 + mergetoolopts,
2485 + commitopts2 + mergetoolopts,
2463 _('[OPTION]... REVISION...'))
2486 _('[OPTION]... REVISION...'))
2464 def graft(ui, repo, *revs, **opts):
2487 def graft(ui, repo, *revs, **opts):
2465 '''copy changes from other branches onto the current branch
2488 '''copy changes from other branches onto the current branch
2466
2489
2467 This command uses Mercurial's merge logic to copy individual
2490 This command uses Mercurial's merge logic to copy individual
2468 changes from other branches without merging branches in the
2491 changes from other branches without merging branches in the
2469 history graph. This is sometimes known as 'backporting' or
2492 history graph. This is sometimes known as 'backporting' or
2470 'cherry-picking'. By default, graft will copy user, date, and
2493 'cherry-picking'. By default, graft will copy user, date, and
2471 description from the source changesets.
2494 description from the source changesets.
2472
2495
2473 Changesets that are ancestors of the current revision, that have
2496 Changesets that are ancestors of the current revision, that have
2474 already been grafted, or that are merges will be skipped.
2497 already been grafted, or that are merges will be skipped.
2475
2498
2476 If a graft merge results in conflicts, the graft process is
2499 If a graft merge results in conflicts, the graft process is
2477 aborted so that the current merge can be manually resolved. Once
2500 aborted so that the current merge can be manually resolved. Once
2478 all conflicts are addressed, the graft process can be continued
2501 all conflicts are addressed, the graft process can be continued
2479 with the -c/--continue option.
2502 with the -c/--continue option.
2480
2503
2481 .. note::
2504 .. note::
2482 The -c/--continue option does not reapply earlier options.
2505 The -c/--continue option does not reapply earlier options.
2483
2506
2484 .. container:: verbose
2507 .. container:: verbose
2485
2508
2486 Examples:
2509 Examples:
2487
2510
2488 - copy a single change to the stable branch and edit its description::
2511 - copy a single change to the stable branch and edit its description::
2489
2512
2490 hg update stable
2513 hg update stable
2491 hg graft --edit 9393
2514 hg graft --edit 9393
2492
2515
2493 - graft a range of changesets with one exception, updating dates::
2516 - graft a range of changesets with one exception, updating dates::
2494
2517
2495 hg graft -D "2085::2093 and not 2091"
2518 hg graft -D "2085::2093 and not 2091"
2496
2519
2497 - continue a graft after resolving conflicts::
2520 - continue a graft after resolving conflicts::
2498
2521
2499 hg graft -c
2522 hg graft -c
2500
2523
2501 - show the source of a grafted changeset::
2524 - show the source of a grafted changeset::
2502
2525
2503 hg log --debug -r tip
2526 hg log --debug -r tip
2504
2527
2505 Returns 0 on successful completion.
2528 Returns 0 on successful completion.
2506 '''
2529 '''
2507
2530
2508 if not opts.get('user') and opts.get('currentuser'):
2531 if not opts.get('user') and opts.get('currentuser'):
2509 opts['user'] = ui.username()
2532 opts['user'] = ui.username()
2510 if not opts.get('date') and opts.get('currentdate'):
2533 if not opts.get('date') and opts.get('currentdate'):
2511 opts['date'] = "%d %d" % util.makedate()
2534 opts['date'] = "%d %d" % util.makedate()
2512
2535
2513 editor = None
2536 editor = None
2514 if opts.get('edit'):
2537 if opts.get('edit'):
2515 editor = cmdutil.commitforceeditor
2538 editor = cmdutil.commitforceeditor
2516
2539
2517 cont = False
2540 cont = False
2518 if opts['continue']:
2541 if opts['continue']:
2519 cont = True
2542 cont = True
2520 if revs:
2543 if revs:
2521 raise util.Abort(_("can't specify --continue and revisions"))
2544 raise util.Abort(_("can't specify --continue and revisions"))
2522 # read in unfinished revisions
2545 # read in unfinished revisions
2523 try:
2546 try:
2524 nodes = repo.opener.read('graftstate').splitlines()
2547 nodes = repo.opener.read('graftstate').splitlines()
2525 revs = [repo[node].rev() for node in nodes]
2548 revs = [repo[node].rev() for node in nodes]
2526 except IOError, inst:
2549 except IOError, inst:
2527 if inst.errno != errno.ENOENT:
2550 if inst.errno != errno.ENOENT:
2528 raise
2551 raise
2529 raise util.Abort(_("no graft state found, can't continue"))
2552 raise util.Abort(_("no graft state found, can't continue"))
2530 else:
2553 else:
2531 cmdutil.bailifchanged(repo)
2554 cmdutil.bailifchanged(repo)
2532 if not revs:
2555 if not revs:
2533 raise util.Abort(_('no revisions specified'))
2556 raise util.Abort(_('no revisions specified'))
2534 revs = scmutil.revrange(repo, revs)
2557 revs = scmutil.revrange(repo, revs)
2535
2558
2536 # check for merges
2559 # check for merges
2537 for rev in repo.revs('%ld and merge()', revs):
2560 for rev in repo.revs('%ld and merge()', revs):
2538 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2561 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2539 revs.remove(rev)
2562 revs.remove(rev)
2540 if not revs:
2563 if not revs:
2541 return -1
2564 return -1
2542
2565
2543 # check for ancestors of dest branch
2566 # check for ancestors of dest branch
2544 for rev in repo.revs('::. and %ld', revs):
2567 for rev in repo.revs('::. and %ld', revs):
2545 ui.warn(_('skipping ancestor revision %s\n') % rev)
2568 ui.warn(_('skipping ancestor revision %s\n') % rev)
2546 revs.remove(rev)
2569 revs.remove(rev)
2547 if not revs:
2570 if not revs:
2548 return -1
2571 return -1
2549
2572
2550 # check ancestors for earlier grafts
2573 # check ancestors for earlier grafts
2551 ui.debug('scanning for duplicate grafts\n')
2574 ui.debug('scanning for duplicate grafts\n')
2552 for ctx in repo.set("::. - ::%ld", revs):
2575 for ctx in repo.set("::. - ::%ld", revs):
2553 n = ctx.extra().get('source')
2576 n = ctx.extra().get('source')
2554 if n and n in repo:
2577 if n and n in repo:
2555 r = repo[n].rev()
2578 r = repo[n].rev()
2556 if r in revs:
2579 if r in revs:
2557 ui.warn(_('skipping already grafted revision %s\n') % r)
2580 ui.warn(_('skipping already grafted revision %s\n') % r)
2558 revs.remove(r)
2581 revs.remove(r)
2559 if not revs:
2582 if not revs:
2560 return -1
2583 return -1
2561
2584
2562 for pos, ctx in enumerate(repo.set("%ld", revs)):
2585 for pos, ctx in enumerate(repo.set("%ld", revs)):
2563 current = repo['.']
2586 current = repo['.']
2564 ui.status(_('grafting revision %s\n') % ctx.rev())
2587 ui.status(_('grafting revision %s\n') % ctx.rev())
2565
2588
2566 # we don't merge the first commit when continuing
2589 # we don't merge the first commit when continuing
2567 if not cont:
2590 if not cont:
2568 # perform the graft merge with p1(rev) as 'ancestor'
2591 # perform the graft merge with p1(rev) as 'ancestor'
2569 try:
2592 try:
2570 # ui.forcemerge is an internal variable, do not document
2593 # ui.forcemerge is an internal variable, do not document
2571 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2594 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2572 stats = mergemod.update(repo, ctx.node(), True, True, False,
2595 stats = mergemod.update(repo, ctx.node(), True, True, False,
2573 ctx.p1().node())
2596 ctx.p1().node())
2574 finally:
2597 finally:
2575 ui.setconfig('ui', 'forcemerge', '')
2598 ui.setconfig('ui', 'forcemerge', '')
2576 # drop the second merge parent
2599 # drop the second merge parent
2577 repo.dirstate.setparents(current.node(), nullid)
2600 repo.dirstate.setparents(current.node(), nullid)
2578 repo.dirstate.write()
2601 repo.dirstate.write()
2579 # fix up dirstate for copies and renames
2602 # fix up dirstate for copies and renames
2580 cmdutil.duplicatecopies(repo, ctx.rev(), current.node(), nullid)
2603 cmdutil.duplicatecopies(repo, ctx.rev(), current.node(), nullid)
2581 # report any conflicts
2604 # report any conflicts
2582 if stats and stats[3] > 0:
2605 if stats and stats[3] > 0:
2583 # write out state for --continue
2606 # write out state for --continue
2584 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2607 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2585 repo.opener.write('graftstate', ''.join(nodelines))
2608 repo.opener.write('graftstate', ''.join(nodelines))
2586 raise util.Abort(
2609 raise util.Abort(
2587 _("unresolved conflicts, can't continue"),
2610 _("unresolved conflicts, can't continue"),
2588 hint=_('use hg resolve and hg graft --continue'))
2611 hint=_('use hg resolve and hg graft --continue'))
2589 else:
2612 else:
2590 cont = False
2613 cont = False
2591
2614
2592 # commit
2615 # commit
2593 extra = {'source': ctx.hex()}
2616 extra = {'source': ctx.hex()}
2594 user = ctx.user()
2617 user = ctx.user()
2595 if opts.get('user'):
2618 if opts.get('user'):
2596 user = opts['user']
2619 user = opts['user']
2597 date = ctx.date()
2620 date = ctx.date()
2598 if opts.get('date'):
2621 if opts.get('date'):
2599 date = opts['date']
2622 date = opts['date']
2600 repo.commit(text=ctx.description(), user=user,
2623 repo.commit(text=ctx.description(), user=user,
2601 date=date, extra=extra, editor=editor)
2624 date=date, extra=extra, editor=editor)
2602
2625
2603 # remove state when we complete successfully
2626 # remove state when we complete successfully
2604 if os.path.exists(repo.join('graftstate')):
2627 if os.path.exists(repo.join('graftstate')):
2605 util.unlinkpath(repo.join('graftstate'))
2628 util.unlinkpath(repo.join('graftstate'))
2606
2629
2607 return 0
2630 return 0
2608
2631
2609 @command('grep',
2632 @command('grep',
2610 [('0', 'print0', None, _('end fields with NUL')),
2633 [('0', 'print0', None, _('end fields with NUL')),
2611 ('', 'all', None, _('print all revisions that match')),
2634 ('', 'all', None, _('print all revisions that match')),
2612 ('a', 'text', None, _('treat all files as text')),
2635 ('a', 'text', None, _('treat all files as text')),
2613 ('f', 'follow', None,
2636 ('f', 'follow', None,
2614 _('follow changeset history,'
2637 _('follow changeset history,'
2615 ' or file history across copies and renames')),
2638 ' or file history across copies and renames')),
2616 ('i', 'ignore-case', None, _('ignore case when matching')),
2639 ('i', 'ignore-case', None, _('ignore case when matching')),
2617 ('l', 'files-with-matches', None,
2640 ('l', 'files-with-matches', None,
2618 _('print only filenames and revisions that match')),
2641 _('print only filenames and revisions that match')),
2619 ('n', 'line-number', None, _('print matching line numbers')),
2642 ('n', 'line-number', None, _('print matching line numbers')),
2620 ('r', 'rev', [],
2643 ('r', 'rev', [],
2621 _('only search files changed within revision range'), _('REV')),
2644 _('only search files changed within revision range'), _('REV')),
2622 ('u', 'user', None, _('list the author (long with -v)')),
2645 ('u', 'user', None, _('list the author (long with -v)')),
2623 ('d', 'date', None, _('list the date (short with -q)')),
2646 ('d', 'date', None, _('list the date (short with -q)')),
2624 ] + walkopts,
2647 ] + walkopts,
2625 _('[OPTION]... PATTERN [FILE]...'))
2648 _('[OPTION]... PATTERN [FILE]...'))
2626 def grep(ui, repo, pattern, *pats, **opts):
2649 def grep(ui, repo, pattern, *pats, **opts):
2627 """search for a pattern in specified files and revisions
2650 """search for a pattern in specified files and revisions
2628
2651
2629 Search revisions of files for a regular expression.
2652 Search revisions of files for a regular expression.
2630
2653
2631 This command behaves differently than Unix grep. It only accepts
2654 This command behaves differently than Unix grep. It only accepts
2632 Python/Perl regexps. It searches repository history, not the
2655 Python/Perl regexps. It searches repository history, not the
2633 working directory. It always prints the revision number in which a
2656 working directory. It always prints the revision number in which a
2634 match appears.
2657 match appears.
2635
2658
2636 By default, grep only prints output for the first revision of a
2659 By default, grep only prints output for the first revision of a
2637 file in which it finds a match. To get it to print every revision
2660 file in which it finds a match. To get it to print every revision
2638 that contains a change in match status ("-" for a match that
2661 that contains a change in match status ("-" for a match that
2639 becomes a non-match, or "+" for a non-match that becomes a match),
2662 becomes a non-match, or "+" for a non-match that becomes a match),
2640 use the --all flag.
2663 use the --all flag.
2641
2664
2642 Returns 0 if a match is found, 1 otherwise.
2665 Returns 0 if a match is found, 1 otherwise.
2643 """
2666 """
2644 reflags = 0
2667 reflags = 0
2645 if opts.get('ignore_case'):
2668 if opts.get('ignore_case'):
2646 reflags |= re.I
2669 reflags |= re.I
2647 try:
2670 try:
2648 regexp = re.compile(pattern, reflags)
2671 regexp = re.compile(pattern, reflags)
2649 except re.error, inst:
2672 except re.error, inst:
2650 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2673 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2651 return 1
2674 return 1
2652 sep, eol = ':', '\n'
2675 sep, eol = ':', '\n'
2653 if opts.get('print0'):
2676 if opts.get('print0'):
2654 sep = eol = '\0'
2677 sep = eol = '\0'
2655
2678
2656 getfile = util.lrucachefunc(repo.file)
2679 getfile = util.lrucachefunc(repo.file)
2657
2680
2658 def matchlines(body):
2681 def matchlines(body):
2659 begin = 0
2682 begin = 0
2660 linenum = 0
2683 linenum = 0
2661 while True:
2684 while True:
2662 match = regexp.search(body, begin)
2685 match = regexp.search(body, begin)
2663 if not match:
2686 if not match:
2664 break
2687 break
2665 mstart, mend = match.span()
2688 mstart, mend = match.span()
2666 linenum += body.count('\n', begin, mstart) + 1
2689 linenum += body.count('\n', begin, mstart) + 1
2667 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2690 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2668 begin = body.find('\n', mend) + 1 or len(body) + 1
2691 begin = body.find('\n', mend) + 1 or len(body) + 1
2669 lend = begin - 1
2692 lend = begin - 1
2670 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2693 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2671
2694
2672 class linestate(object):
2695 class linestate(object):
2673 def __init__(self, line, linenum, colstart, colend):
2696 def __init__(self, line, linenum, colstart, colend):
2674 self.line = line
2697 self.line = line
2675 self.linenum = linenum
2698 self.linenum = linenum
2676 self.colstart = colstart
2699 self.colstart = colstart
2677 self.colend = colend
2700 self.colend = colend
2678
2701
2679 def __hash__(self):
2702 def __hash__(self):
2680 return hash((self.linenum, self.line))
2703 return hash((self.linenum, self.line))
2681
2704
2682 def __eq__(self, other):
2705 def __eq__(self, other):
2683 return self.line == other.line
2706 return self.line == other.line
2684
2707
2685 matches = {}
2708 matches = {}
2686 copies = {}
2709 copies = {}
2687 def grepbody(fn, rev, body):
2710 def grepbody(fn, rev, body):
2688 matches[rev].setdefault(fn, [])
2711 matches[rev].setdefault(fn, [])
2689 m = matches[rev][fn]
2712 m = matches[rev][fn]
2690 for lnum, cstart, cend, line in matchlines(body):
2713 for lnum, cstart, cend, line in matchlines(body):
2691 s = linestate(line, lnum, cstart, cend)
2714 s = linestate(line, lnum, cstart, cend)
2692 m.append(s)
2715 m.append(s)
2693
2716
2694 def difflinestates(a, b):
2717 def difflinestates(a, b):
2695 sm = difflib.SequenceMatcher(None, a, b)
2718 sm = difflib.SequenceMatcher(None, a, b)
2696 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2719 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2697 if tag == 'insert':
2720 if tag == 'insert':
2698 for i in xrange(blo, bhi):
2721 for i in xrange(blo, bhi):
2699 yield ('+', b[i])
2722 yield ('+', b[i])
2700 elif tag == 'delete':
2723 elif tag == 'delete':
2701 for i in xrange(alo, ahi):
2724 for i in xrange(alo, ahi):
2702 yield ('-', a[i])
2725 yield ('-', a[i])
2703 elif tag == 'replace':
2726 elif tag == 'replace':
2704 for i in xrange(alo, ahi):
2727 for i in xrange(alo, ahi):
2705 yield ('-', a[i])
2728 yield ('-', a[i])
2706 for i in xrange(blo, bhi):
2729 for i in xrange(blo, bhi):
2707 yield ('+', b[i])
2730 yield ('+', b[i])
2708
2731
2709 def display(fn, ctx, pstates, states):
2732 def display(fn, ctx, pstates, states):
2710 rev = ctx.rev()
2733 rev = ctx.rev()
2711 datefunc = ui.quiet and util.shortdate or util.datestr
2734 datefunc = ui.quiet and util.shortdate or util.datestr
2712 found = False
2735 found = False
2713 filerevmatches = {}
2736 filerevmatches = {}
2714 def binary():
2737 def binary():
2715 flog = getfile(fn)
2738 flog = getfile(fn)
2716 return util.binary(flog.read(ctx.filenode(fn)))
2739 return util.binary(flog.read(ctx.filenode(fn)))
2717
2740
2718 if opts.get('all'):
2741 if opts.get('all'):
2719 iter = difflinestates(pstates, states)
2742 iter = difflinestates(pstates, states)
2720 else:
2743 else:
2721 iter = [('', l) for l in states]
2744 iter = [('', l) for l in states]
2722 for change, l in iter:
2745 for change, l in iter:
2723 cols = [fn, str(rev)]
2746 cols = [fn, str(rev)]
2724 before, match, after = None, None, None
2747 before, match, after = None, None, None
2725 if opts.get('line_number'):
2748 if opts.get('line_number'):
2726 cols.append(str(l.linenum))
2749 cols.append(str(l.linenum))
2727 if opts.get('all'):
2750 if opts.get('all'):
2728 cols.append(change)
2751 cols.append(change)
2729 if opts.get('user'):
2752 if opts.get('user'):
2730 cols.append(ui.shortuser(ctx.user()))
2753 cols.append(ui.shortuser(ctx.user()))
2731 if opts.get('date'):
2754 if opts.get('date'):
2732 cols.append(datefunc(ctx.date()))
2755 cols.append(datefunc(ctx.date()))
2733 if opts.get('files_with_matches'):
2756 if opts.get('files_with_matches'):
2734 c = (fn, rev)
2757 c = (fn, rev)
2735 if c in filerevmatches:
2758 if c in filerevmatches:
2736 continue
2759 continue
2737 filerevmatches[c] = 1
2760 filerevmatches[c] = 1
2738 else:
2761 else:
2739 before = l.line[:l.colstart]
2762 before = l.line[:l.colstart]
2740 match = l.line[l.colstart:l.colend]
2763 match = l.line[l.colstart:l.colend]
2741 after = l.line[l.colend:]
2764 after = l.line[l.colend:]
2742 ui.write(sep.join(cols))
2765 ui.write(sep.join(cols))
2743 if before is not None:
2766 if before is not None:
2744 if not opts.get('text') and binary():
2767 if not opts.get('text') and binary():
2745 ui.write(sep + " Binary file matches")
2768 ui.write(sep + " Binary file matches")
2746 else:
2769 else:
2747 ui.write(sep + before)
2770 ui.write(sep + before)
2748 ui.write(match, label='grep.match')
2771 ui.write(match, label='grep.match')
2749 ui.write(after)
2772 ui.write(after)
2750 ui.write(eol)
2773 ui.write(eol)
2751 found = True
2774 found = True
2752 return found
2775 return found
2753
2776
2754 skip = {}
2777 skip = {}
2755 revfiles = {}
2778 revfiles = {}
2756 matchfn = scmutil.match(repo[None], pats, opts)
2779 matchfn = scmutil.match(repo[None], pats, opts)
2757 found = False
2780 found = False
2758 follow = opts.get('follow')
2781 follow = opts.get('follow')
2759
2782
2760 def prep(ctx, fns):
2783 def prep(ctx, fns):
2761 rev = ctx.rev()
2784 rev = ctx.rev()
2762 pctx = ctx.p1()
2785 pctx = ctx.p1()
2763 parent = pctx.rev()
2786 parent = pctx.rev()
2764 matches.setdefault(rev, {})
2787 matches.setdefault(rev, {})
2765 matches.setdefault(parent, {})
2788 matches.setdefault(parent, {})
2766 files = revfiles.setdefault(rev, [])
2789 files = revfiles.setdefault(rev, [])
2767 for fn in fns:
2790 for fn in fns:
2768 flog = getfile(fn)
2791 flog = getfile(fn)
2769 try:
2792 try:
2770 fnode = ctx.filenode(fn)
2793 fnode = ctx.filenode(fn)
2771 except error.LookupError:
2794 except error.LookupError:
2772 continue
2795 continue
2773
2796
2774 copied = flog.renamed(fnode)
2797 copied = flog.renamed(fnode)
2775 copy = follow and copied and copied[0]
2798 copy = follow and copied and copied[0]
2776 if copy:
2799 if copy:
2777 copies.setdefault(rev, {})[fn] = copy
2800 copies.setdefault(rev, {})[fn] = copy
2778 if fn in skip:
2801 if fn in skip:
2779 if copy:
2802 if copy:
2780 skip[copy] = True
2803 skip[copy] = True
2781 continue
2804 continue
2782 files.append(fn)
2805 files.append(fn)
2783
2806
2784 if fn not in matches[rev]:
2807 if fn not in matches[rev]:
2785 grepbody(fn, rev, flog.read(fnode))
2808 grepbody(fn, rev, flog.read(fnode))
2786
2809
2787 pfn = copy or fn
2810 pfn = copy or fn
2788 if pfn not in matches[parent]:
2811 if pfn not in matches[parent]:
2789 try:
2812 try:
2790 fnode = pctx.filenode(pfn)
2813 fnode = pctx.filenode(pfn)
2791 grepbody(pfn, parent, flog.read(fnode))
2814 grepbody(pfn, parent, flog.read(fnode))
2792 except error.LookupError:
2815 except error.LookupError:
2793 pass
2816 pass
2794
2817
2795 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2818 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2796 rev = ctx.rev()
2819 rev = ctx.rev()
2797 parent = ctx.p1().rev()
2820 parent = ctx.p1().rev()
2798 for fn in sorted(revfiles.get(rev, [])):
2821 for fn in sorted(revfiles.get(rev, [])):
2799 states = matches[rev][fn]
2822 states = matches[rev][fn]
2800 copy = copies.get(rev, {}).get(fn)
2823 copy = copies.get(rev, {}).get(fn)
2801 if fn in skip:
2824 if fn in skip:
2802 if copy:
2825 if copy:
2803 skip[copy] = True
2826 skip[copy] = True
2804 continue
2827 continue
2805 pstates = matches.get(parent, {}).get(copy or fn, [])
2828 pstates = matches.get(parent, {}).get(copy or fn, [])
2806 if pstates or states:
2829 if pstates or states:
2807 r = display(fn, ctx, pstates, states)
2830 r = display(fn, ctx, pstates, states)
2808 found = found or r
2831 found = found or r
2809 if r and not opts.get('all'):
2832 if r and not opts.get('all'):
2810 skip[fn] = True
2833 skip[fn] = True
2811 if copy:
2834 if copy:
2812 skip[copy] = True
2835 skip[copy] = True
2813 del matches[rev]
2836 del matches[rev]
2814 del revfiles[rev]
2837 del revfiles[rev]
2815
2838
2816 return not found
2839 return not found
2817
2840
2818 @command('heads',
2841 @command('heads',
2819 [('r', 'rev', '',
2842 [('r', 'rev', '',
2820 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2843 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2821 ('t', 'topo', False, _('show topological heads only')),
2844 ('t', 'topo', False, _('show topological heads only')),
2822 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2845 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2823 ('c', 'closed', False, _('show normal and closed branch heads')),
2846 ('c', 'closed', False, _('show normal and closed branch heads')),
2824 ] + templateopts,
2847 ] + templateopts,
2825 _('[-ac] [-r STARTREV] [REV]...'))
2848 _('[-ac] [-r STARTREV] [REV]...'))
2826 def heads(ui, repo, *branchrevs, **opts):
2849 def heads(ui, repo, *branchrevs, **opts):
2827 """show current repository heads or show branch heads
2850 """show current repository heads or show branch heads
2828
2851
2829 With no arguments, show all repository branch heads.
2852 With no arguments, show all repository branch heads.
2830
2853
2831 Repository "heads" are changesets with no child changesets. They are
2854 Repository "heads" are changesets with no child changesets. They are
2832 where development generally takes place and are the usual targets
2855 where development generally takes place and are the usual targets
2833 for update and merge operations. Branch heads are changesets that have
2856 for update and merge operations. Branch heads are changesets that have
2834 no child changeset on the same branch.
2857 no child changeset on the same branch.
2835
2858
2836 If one or more REVs are given, only branch heads on the branches
2859 If one or more REVs are given, only branch heads on the branches
2837 associated with the specified changesets are shown. This means
2860 associated with the specified changesets are shown. This means
2838 that you can use :hg:`heads foo` to see the heads on a branch
2861 that you can use :hg:`heads foo` to see the heads on a branch
2839 named ``foo``.
2862 named ``foo``.
2840
2863
2841 If -c/--closed is specified, also show branch heads marked closed
2864 If -c/--closed is specified, also show branch heads marked closed
2842 (see :hg:`commit --close-branch`).
2865 (see :hg:`commit --close-branch`).
2843
2866
2844 If STARTREV is specified, only those heads that are descendants of
2867 If STARTREV is specified, only those heads that are descendants of
2845 STARTREV will be displayed.
2868 STARTREV will be displayed.
2846
2869
2847 If -t/--topo is specified, named branch mechanics will be ignored and only
2870 If -t/--topo is specified, named branch mechanics will be ignored and only
2848 changesets without children will be shown.
2871 changesets without children will be shown.
2849
2872
2850 Returns 0 if matching heads are found, 1 if not.
2873 Returns 0 if matching heads are found, 1 if not.
2851 """
2874 """
2852
2875
2853 start = None
2876 start = None
2854 if 'rev' in opts:
2877 if 'rev' in opts:
2855 start = scmutil.revsingle(repo, opts['rev'], None).node()
2878 start = scmutil.revsingle(repo, opts['rev'], None).node()
2856
2879
2857 if opts.get('topo'):
2880 if opts.get('topo'):
2858 heads = [repo[h] for h in repo.heads(start)]
2881 heads = [repo[h] for h in repo.heads(start)]
2859 else:
2882 else:
2860 heads = []
2883 heads = []
2861 for branch in repo.branchmap():
2884 for branch in repo.branchmap():
2862 heads += repo.branchheads(branch, start, opts.get('closed'))
2885 heads += repo.branchheads(branch, start, opts.get('closed'))
2863 heads = [repo[h] for h in heads]
2886 heads = [repo[h] for h in heads]
2864
2887
2865 if branchrevs:
2888 if branchrevs:
2866 branches = set(repo[br].branch() for br in branchrevs)
2889 branches = set(repo[br].branch() for br in branchrevs)
2867 heads = [h for h in heads if h.branch() in branches]
2890 heads = [h for h in heads if h.branch() in branches]
2868
2891
2869 if opts.get('active') and branchrevs:
2892 if opts.get('active') and branchrevs:
2870 dagheads = repo.heads(start)
2893 dagheads = repo.heads(start)
2871 heads = [h for h in heads if h.node() in dagheads]
2894 heads = [h for h in heads if h.node() in dagheads]
2872
2895
2873 if branchrevs:
2896 if branchrevs:
2874 haveheads = set(h.branch() for h in heads)
2897 haveheads = set(h.branch() for h in heads)
2875 if branches - haveheads:
2898 if branches - haveheads:
2876 headless = ', '.join(b for b in branches - haveheads)
2899 headless = ', '.join(b for b in branches - haveheads)
2877 msg = _('no open branch heads found on branches %s')
2900 msg = _('no open branch heads found on branches %s')
2878 if opts.get('rev'):
2901 if opts.get('rev'):
2879 msg += _(' (started at %s)' % opts['rev'])
2902 msg += _(' (started at %s)' % opts['rev'])
2880 ui.warn((msg + '\n') % headless)
2903 ui.warn((msg + '\n') % headless)
2881
2904
2882 if not heads:
2905 if not heads:
2883 return 1
2906 return 1
2884
2907
2885 heads = sorted(heads, key=lambda x: -x.rev())
2908 heads = sorted(heads, key=lambda x: -x.rev())
2886 displayer = cmdutil.show_changeset(ui, repo, opts)
2909 displayer = cmdutil.show_changeset(ui, repo, opts)
2887 for ctx in heads:
2910 for ctx in heads:
2888 displayer.show(ctx)
2911 displayer.show(ctx)
2889 displayer.close()
2912 displayer.close()
2890
2913
2891 @command('help',
2914 @command('help',
2892 [('e', 'extension', None, _('show only help for extensions')),
2915 [('e', 'extension', None, _('show only help for extensions')),
2893 ('c', 'command', None, _('show only help for commands'))],
2916 ('c', 'command', None, _('show only help for commands'))],
2894 _('[-ec] [TOPIC]'))
2917 _('[-ec] [TOPIC]'))
2895 def help_(ui, name=None, unknowncmd=False, full=True, **opts):
2918 def help_(ui, name=None, unknowncmd=False, full=True, **opts):
2896 """show help for a given topic or a help overview
2919 """show help for a given topic or a help overview
2897
2920
2898 With no arguments, print a list of commands with short help messages.
2921 With no arguments, print a list of commands with short help messages.
2899
2922
2900 Given a topic, extension, or command name, print help for that
2923 Given a topic, extension, or command name, print help for that
2901 topic.
2924 topic.
2902
2925
2903 Returns 0 if successful.
2926 Returns 0 if successful.
2904 """
2927 """
2905
2928
2906 textwidth = min(ui.termwidth(), 80) - 2
2929 textwidth = min(ui.termwidth(), 80) - 2
2907
2930
2908 def optrst(options):
2931 def optrst(options):
2909 data = []
2932 data = []
2910 multioccur = False
2933 multioccur = False
2911 for option in options:
2934 for option in options:
2912 if len(option) == 5:
2935 if len(option) == 5:
2913 shortopt, longopt, default, desc, optlabel = option
2936 shortopt, longopt, default, desc, optlabel = option
2914 else:
2937 else:
2915 shortopt, longopt, default, desc = option
2938 shortopt, longopt, default, desc = option
2916 optlabel = _("VALUE") # default label
2939 optlabel = _("VALUE") # default label
2917
2940
2918 if _("DEPRECATED") in desc and not ui.verbose:
2941 if _("DEPRECATED") in desc and not ui.verbose:
2919 continue
2942 continue
2920
2943
2921 so = ''
2944 so = ''
2922 if shortopt:
2945 if shortopt:
2923 so = '-' + shortopt
2946 so = '-' + shortopt
2924 lo = '--' + longopt
2947 lo = '--' + longopt
2925 if default:
2948 if default:
2926 desc += _(" (default: %s)") % default
2949 desc += _(" (default: %s)") % default
2927
2950
2928 if isinstance(default, list):
2951 if isinstance(default, list):
2929 lo += " %s [+]" % optlabel
2952 lo += " %s [+]" % optlabel
2930 multioccur = True
2953 multioccur = True
2931 elif (default is not None) and not isinstance(default, bool):
2954 elif (default is not None) and not isinstance(default, bool):
2932 lo += " %s" % optlabel
2955 lo += " %s" % optlabel
2933
2956
2934 data.append((so, lo, desc))
2957 data.append((so, lo, desc))
2935
2958
2936 rst = minirst.maketable(data, 1)
2959 rst = minirst.maketable(data, 1)
2937
2960
2938 if multioccur:
2961 if multioccur:
2939 rst += _("\n[+] marked option can be specified multiple times\n")
2962 rst += _("\n[+] marked option can be specified multiple times\n")
2940
2963
2941 return rst
2964 return rst
2942
2965
2943 # list all option lists
2966 # list all option lists
2944 def opttext(optlist, width):
2967 def opttext(optlist, width):
2945 rst = ''
2968 rst = ''
2946 if not optlist:
2969 if not optlist:
2947 return ''
2970 return ''
2948
2971
2949 for title, options in optlist:
2972 for title, options in optlist:
2950 rst += '\n%s\n' % title
2973 rst += '\n%s\n' % title
2951 if options:
2974 if options:
2952 rst += "\n"
2975 rst += "\n"
2953 rst += optrst(options)
2976 rst += optrst(options)
2954 rst += '\n'
2977 rst += '\n'
2955
2978
2956 return '\n' + minirst.format(rst, width)
2979 return '\n' + minirst.format(rst, width)
2957
2980
2958 def addglobalopts(optlist, aliases):
2981 def addglobalopts(optlist, aliases):
2959 if ui.quiet:
2982 if ui.quiet:
2960 return []
2983 return []
2961
2984
2962 if ui.verbose:
2985 if ui.verbose:
2963 optlist.append((_("global options:"), globalopts))
2986 optlist.append((_("global options:"), globalopts))
2964 if name == 'shortlist':
2987 if name == 'shortlist':
2965 optlist.append((_('use "hg help" for the full list '
2988 optlist.append((_('use "hg help" for the full list '
2966 'of commands'), ()))
2989 'of commands'), ()))
2967 else:
2990 else:
2968 if name == 'shortlist':
2991 if name == 'shortlist':
2969 msg = _('use "hg help" for the full list of commands '
2992 msg = _('use "hg help" for the full list of commands '
2970 'or "hg -v" for details')
2993 'or "hg -v" for details')
2971 elif name and not full:
2994 elif name and not full:
2972 msg = _('use "hg help %s" to show the full help text' % name)
2995 msg = _('use "hg help %s" to show the full help text' % name)
2973 elif aliases:
2996 elif aliases:
2974 msg = _('use "hg -v help%s" to show builtin aliases and '
2997 msg = _('use "hg -v help%s" to show builtin aliases and '
2975 'global options') % (name and " " + name or "")
2998 'global options') % (name and " " + name or "")
2976 else:
2999 else:
2977 msg = _('use "hg -v help %s" to show more info') % name
3000 msg = _('use "hg -v help %s" to show more info') % name
2978 optlist.append((msg, ()))
3001 optlist.append((msg, ()))
2979
3002
2980 def helpcmd(name):
3003 def helpcmd(name):
2981 try:
3004 try:
2982 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
3005 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
2983 except error.AmbiguousCommand, inst:
3006 except error.AmbiguousCommand, inst:
2984 # py3k fix: except vars can't be used outside the scope of the
3007 # py3k fix: except vars can't be used outside the scope of the
2985 # except block, nor can be used inside a lambda. python issue4617
3008 # except block, nor can be used inside a lambda. python issue4617
2986 prefix = inst.args[0]
3009 prefix = inst.args[0]
2987 select = lambda c: c.lstrip('^').startswith(prefix)
3010 select = lambda c: c.lstrip('^').startswith(prefix)
2988 helplist(select)
3011 helplist(select)
2989 return
3012 return
2990
3013
2991 # check if it's an invalid alias and display its error if it is
3014 # check if it's an invalid alias and display its error if it is
2992 if getattr(entry[0], 'badalias', False):
3015 if getattr(entry[0], 'badalias', False):
2993 if not unknowncmd:
3016 if not unknowncmd:
2994 entry[0](ui)
3017 entry[0](ui)
2995 return
3018 return
2996
3019
2997 rst = ""
3020 rst = ""
2998
3021
2999 # synopsis
3022 # synopsis
3000 if len(entry) > 2:
3023 if len(entry) > 2:
3001 if entry[2].startswith('hg'):
3024 if entry[2].startswith('hg'):
3002 rst += "%s\n" % entry[2]
3025 rst += "%s\n" % entry[2]
3003 else:
3026 else:
3004 rst += 'hg %s %s\n' % (aliases[0], entry[2])
3027 rst += 'hg %s %s\n' % (aliases[0], entry[2])
3005 else:
3028 else:
3006 rst += 'hg %s\n' % aliases[0]
3029 rst += 'hg %s\n' % aliases[0]
3007
3030
3008 # aliases
3031 # aliases
3009 if full and not ui.quiet and len(aliases) > 1:
3032 if full and not ui.quiet and len(aliases) > 1:
3010 rst += _("\naliases: %s\n") % ', '.join(aliases[1:])
3033 rst += _("\naliases: %s\n") % ', '.join(aliases[1:])
3011
3034
3012 # description
3035 # description
3013 doc = gettext(entry[0].__doc__)
3036 doc = gettext(entry[0].__doc__)
3014 if not doc:
3037 if not doc:
3015 doc = _("(no help text available)")
3038 doc = _("(no help text available)")
3016 if util.safehasattr(entry[0], 'definition'): # aliased command
3039 if util.safehasattr(entry[0], 'definition'): # aliased command
3017 if entry[0].definition.startswith('!'): # shell alias
3040 if entry[0].definition.startswith('!'): # shell alias
3018 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
3041 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
3019 else:
3042 else:
3020 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
3043 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
3021 if ui.quiet or not full:
3044 if ui.quiet or not full:
3022 doc = doc.splitlines()[0]
3045 doc = doc.splitlines()[0]
3023 rst += "\n" + doc + "\n"
3046 rst += "\n" + doc + "\n"
3024
3047
3025 # check if this command shadows a non-trivial (multi-line)
3048 # check if this command shadows a non-trivial (multi-line)
3026 # extension help text
3049 # extension help text
3027 try:
3050 try:
3028 mod = extensions.find(name)
3051 mod = extensions.find(name)
3029 doc = gettext(mod.__doc__) or ''
3052 doc = gettext(mod.__doc__) or ''
3030 if '\n' in doc.strip():
3053 if '\n' in doc.strip():
3031 msg = _('use "hg help -e %s" to show help for '
3054 msg = _('use "hg help -e %s" to show help for '
3032 'the %s extension') % (name, name)
3055 'the %s extension') % (name, name)
3033 rst += '\n%s\n' % msg
3056 rst += '\n%s\n' % msg
3034 except KeyError:
3057 except KeyError:
3035 pass
3058 pass
3036
3059
3037 # options
3060 # options
3038 if not ui.quiet and entry[1]:
3061 if not ui.quiet and entry[1]:
3039 rst += '\noptions:\n\n'
3062 rst += '\noptions:\n\n'
3040 rst += optrst(entry[1])
3063 rst += optrst(entry[1])
3041
3064
3042 if ui.verbose:
3065 if ui.verbose:
3043 rst += '\nglobal options:\n\n'
3066 rst += '\nglobal options:\n\n'
3044 rst += optrst(globalopts)
3067 rst += optrst(globalopts)
3045
3068
3046 keep = ui.verbose and ['verbose'] or []
3069 keep = ui.verbose and ['verbose'] or []
3047 formatted, pruned = minirst.format(rst, textwidth, keep=keep)
3070 formatted, pruned = minirst.format(rst, textwidth, keep=keep)
3048 ui.write(formatted)
3071 ui.write(formatted)
3049
3072
3050 if not ui.verbose:
3073 if not ui.verbose:
3051 if not full:
3074 if not full:
3052 ui.write(_('\nuse "hg help %s" to show the full help text\n')
3075 ui.write(_('\nuse "hg help %s" to show the full help text\n')
3053 % name)
3076 % name)
3054 elif not ui.quiet:
3077 elif not ui.quiet:
3055 ui.write(_('\nuse "hg -v help %s" to show more info\n') % name)
3078 ui.write(_('\nuse "hg -v help %s" to show more info\n') % name)
3056
3079
3057
3080
3058 def helplist(select=None):
3081 def helplist(select=None):
3059 # list of commands
3082 # list of commands
3060 if name == "shortlist":
3083 if name == "shortlist":
3061 header = _('basic commands:\n\n')
3084 header = _('basic commands:\n\n')
3062 else:
3085 else:
3063 header = _('list of commands:\n\n')
3086 header = _('list of commands:\n\n')
3064
3087
3065 h = {}
3088 h = {}
3066 cmds = {}
3089 cmds = {}
3067 for c, e in table.iteritems():
3090 for c, e in table.iteritems():
3068 f = c.split("|", 1)[0]
3091 f = c.split("|", 1)[0]
3069 if select and not select(f):
3092 if select and not select(f):
3070 continue
3093 continue
3071 if (not select and name != 'shortlist' and
3094 if (not select and name != 'shortlist' and
3072 e[0].__module__ != __name__):
3095 e[0].__module__ != __name__):
3073 continue
3096 continue
3074 if name == "shortlist" and not f.startswith("^"):
3097 if name == "shortlist" and not f.startswith("^"):
3075 continue
3098 continue
3076 f = f.lstrip("^")
3099 f = f.lstrip("^")
3077 if not ui.debugflag and f.startswith("debug"):
3100 if not ui.debugflag and f.startswith("debug"):
3078 continue
3101 continue
3079 doc = e[0].__doc__
3102 doc = e[0].__doc__
3080 if doc and 'DEPRECATED' in doc and not ui.verbose:
3103 if doc and 'DEPRECATED' in doc and not ui.verbose:
3081 continue
3104 continue
3082 doc = gettext(doc)
3105 doc = gettext(doc)
3083 if not doc:
3106 if not doc:
3084 doc = _("(no help text available)")
3107 doc = _("(no help text available)")
3085 h[f] = doc.splitlines()[0].rstrip()
3108 h[f] = doc.splitlines()[0].rstrip()
3086 cmds[f] = c.lstrip("^")
3109 cmds[f] = c.lstrip("^")
3087
3110
3088 if not h:
3111 if not h:
3089 ui.status(_('no commands defined\n'))
3112 ui.status(_('no commands defined\n'))
3090 return
3113 return
3091
3114
3092 ui.status(header)
3115 ui.status(header)
3093 fns = sorted(h)
3116 fns = sorted(h)
3094 m = max(map(len, fns))
3117 m = max(map(len, fns))
3095 for f in fns:
3118 for f in fns:
3096 if ui.verbose:
3119 if ui.verbose:
3097 commands = cmds[f].replace("|",", ")
3120 commands = cmds[f].replace("|",", ")
3098 ui.write(" %s:\n %s\n"%(commands, h[f]))
3121 ui.write(" %s:\n %s\n"%(commands, h[f]))
3099 else:
3122 else:
3100 ui.write('%s\n' % (util.wrap(h[f], textwidth,
3123 ui.write('%s\n' % (util.wrap(h[f], textwidth,
3101 initindent=' %-*s ' % (m, f),
3124 initindent=' %-*s ' % (m, f),
3102 hangindent=' ' * (m + 4))))
3125 hangindent=' ' * (m + 4))))
3103
3126
3104 if not name:
3127 if not name:
3105 text = help.listexts(_('enabled extensions:'), extensions.enabled())
3128 text = help.listexts(_('enabled extensions:'), extensions.enabled())
3106 if text:
3129 if text:
3107 ui.write("\n%s" % minirst.format(text, textwidth))
3130 ui.write("\n%s" % minirst.format(text, textwidth))
3108
3131
3109 ui.write(_("\nadditional help topics:\n\n"))
3132 ui.write(_("\nadditional help topics:\n\n"))
3110 topics = []
3133 topics = []
3111 for names, header, doc in help.helptable:
3134 for names, header, doc in help.helptable:
3112 topics.append((sorted(names, key=len, reverse=True)[0], header))
3135 topics.append((sorted(names, key=len, reverse=True)[0], header))
3113 topics_len = max([len(s[0]) for s in topics])
3136 topics_len = max([len(s[0]) for s in topics])
3114 for t, desc in topics:
3137 for t, desc in topics:
3115 ui.write(" %-*s %s\n" % (topics_len, t, desc))
3138 ui.write(" %-*s %s\n" % (topics_len, t, desc))
3116
3139
3117 optlist = []
3140 optlist = []
3118 addglobalopts(optlist, True)
3141 addglobalopts(optlist, True)
3119 ui.write(opttext(optlist, textwidth))
3142 ui.write(opttext(optlist, textwidth))
3120
3143
3121 def helptopic(name):
3144 def helptopic(name):
3122 for names, header, doc in help.helptable:
3145 for names, header, doc in help.helptable:
3123 if name in names:
3146 if name in names:
3124 break
3147 break
3125 else:
3148 else:
3126 raise error.UnknownCommand(name)
3149 raise error.UnknownCommand(name)
3127
3150
3128 # description
3151 # description
3129 if not doc:
3152 if not doc:
3130 doc = _("(no help text available)")
3153 doc = _("(no help text available)")
3131 if util.safehasattr(doc, '__call__'):
3154 if util.safehasattr(doc, '__call__'):
3132 doc = doc()
3155 doc = doc()
3133
3156
3134 ui.write("%s\n\n" % header)
3157 ui.write("%s\n\n" % header)
3135 ui.write("%s" % minirst.format(doc, textwidth, indent=4))
3158 ui.write("%s" % minirst.format(doc, textwidth, indent=4))
3136 try:
3159 try:
3137 cmdutil.findcmd(name, table)
3160 cmdutil.findcmd(name, table)
3138 ui.write(_('\nuse "hg help -c %s" to see help for '
3161 ui.write(_('\nuse "hg help -c %s" to see help for '
3139 'the %s command\n') % (name, name))
3162 'the %s command\n') % (name, name))
3140 except error.UnknownCommand:
3163 except error.UnknownCommand:
3141 pass
3164 pass
3142
3165
3143 def helpext(name):
3166 def helpext(name):
3144 try:
3167 try:
3145 mod = extensions.find(name)
3168 mod = extensions.find(name)
3146 doc = gettext(mod.__doc__) or _('no help text available')
3169 doc = gettext(mod.__doc__) or _('no help text available')
3147 except KeyError:
3170 except KeyError:
3148 mod = None
3171 mod = None
3149 doc = extensions.disabledext(name)
3172 doc = extensions.disabledext(name)
3150 if not doc:
3173 if not doc:
3151 raise error.UnknownCommand(name)
3174 raise error.UnknownCommand(name)
3152
3175
3153 if '\n' not in doc:
3176 if '\n' not in doc:
3154 head, tail = doc, ""
3177 head, tail = doc, ""
3155 else:
3178 else:
3156 head, tail = doc.split('\n', 1)
3179 head, tail = doc.split('\n', 1)
3157 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
3180 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
3158 if tail:
3181 if tail:
3159 ui.write(minirst.format(tail, textwidth))
3182 ui.write(minirst.format(tail, textwidth))
3160 ui.status('\n')
3183 ui.status('\n')
3161
3184
3162 if mod:
3185 if mod:
3163 try:
3186 try:
3164 ct = mod.cmdtable
3187 ct = mod.cmdtable
3165 except AttributeError:
3188 except AttributeError:
3166 ct = {}
3189 ct = {}
3167 modcmds = set([c.split('|', 1)[0] for c in ct])
3190 modcmds = set([c.split('|', 1)[0] for c in ct])
3168 helplist(modcmds.__contains__)
3191 helplist(modcmds.__contains__)
3169 else:
3192 else:
3170 ui.write(_('use "hg help extensions" for information on enabling '
3193 ui.write(_('use "hg help extensions" for information on enabling '
3171 'extensions\n'))
3194 'extensions\n'))
3172
3195
3173 def helpextcmd(name):
3196 def helpextcmd(name):
3174 cmd, ext, mod = extensions.disabledcmd(ui, name, ui.config('ui', 'strict'))
3197 cmd, ext, mod = extensions.disabledcmd(ui, name, ui.config('ui', 'strict'))
3175 doc = gettext(mod.__doc__).splitlines()[0]
3198 doc = gettext(mod.__doc__).splitlines()[0]
3176
3199
3177 msg = help.listexts(_("'%s' is provided by the following "
3200 msg = help.listexts(_("'%s' is provided by the following "
3178 "extension:") % cmd, {ext: doc}, indent=4)
3201 "extension:") % cmd, {ext: doc}, indent=4)
3179 ui.write(minirst.format(msg, textwidth))
3202 ui.write(minirst.format(msg, textwidth))
3180 ui.write('\n')
3203 ui.write('\n')
3181 ui.write(_('use "hg help extensions" for information on enabling '
3204 ui.write(_('use "hg help extensions" for information on enabling '
3182 'extensions\n'))
3205 'extensions\n'))
3183
3206
3184 if name and name != 'shortlist':
3207 if name and name != 'shortlist':
3185 i = None
3208 i = None
3186 if unknowncmd:
3209 if unknowncmd:
3187 queries = (helpextcmd,)
3210 queries = (helpextcmd,)
3188 elif opts.get('extension'):
3211 elif opts.get('extension'):
3189 queries = (helpext,)
3212 queries = (helpext,)
3190 elif opts.get('command'):
3213 elif opts.get('command'):
3191 queries = (helpcmd,)
3214 queries = (helpcmd,)
3192 else:
3215 else:
3193 queries = (helptopic, helpcmd, helpext, helpextcmd)
3216 queries = (helptopic, helpcmd, helpext, helpextcmd)
3194 for f in queries:
3217 for f in queries:
3195 try:
3218 try:
3196 f(name)
3219 f(name)
3197 i = None
3220 i = None
3198 break
3221 break
3199 except error.UnknownCommand, inst:
3222 except error.UnknownCommand, inst:
3200 i = inst
3223 i = inst
3201 if i:
3224 if i:
3202 raise i
3225 raise i
3203 else:
3226 else:
3204 # program name
3227 # program name
3205 ui.status(_("Mercurial Distributed SCM\n"))
3228 ui.status(_("Mercurial Distributed SCM\n"))
3206 ui.status('\n')
3229 ui.status('\n')
3207 helplist()
3230 helplist()
3208
3231
3209
3232
3210 @command('identify|id',
3233 @command('identify|id',
3211 [('r', 'rev', '',
3234 [('r', 'rev', '',
3212 _('identify the specified revision'), _('REV')),
3235 _('identify the specified revision'), _('REV')),
3213 ('n', 'num', None, _('show local revision number')),
3236 ('n', 'num', None, _('show local revision number')),
3214 ('i', 'id', None, _('show global revision id')),
3237 ('i', 'id', None, _('show global revision id')),
3215 ('b', 'branch', None, _('show branch')),
3238 ('b', 'branch', None, _('show branch')),
3216 ('t', 'tags', None, _('show tags')),
3239 ('t', 'tags', None, _('show tags')),
3217 ('B', 'bookmarks', None, _('show bookmarks'))],
3240 ('B', 'bookmarks', None, _('show bookmarks'))],
3218 _('[-nibtB] [-r REV] [SOURCE]'))
3241 _('[-nibtB] [-r REV] [SOURCE]'))
3219 def identify(ui, repo, source=None, rev=None,
3242 def identify(ui, repo, source=None, rev=None,
3220 num=None, id=None, branch=None, tags=None, bookmarks=None):
3243 num=None, id=None, branch=None, tags=None, bookmarks=None):
3221 """identify the working copy or specified revision
3244 """identify the working copy or specified revision
3222
3245
3223 Print a summary identifying the repository state at REV using one or
3246 Print a summary identifying the repository state at REV using one or
3224 two parent hash identifiers, followed by a "+" if the working
3247 two parent hash identifiers, followed by a "+" if the working
3225 directory has uncommitted changes, the branch name (if not default),
3248 directory has uncommitted changes, the branch name (if not default),
3226 a list of tags, and a list of bookmarks.
3249 a list of tags, and a list of bookmarks.
3227
3250
3228 When REV is not given, print a summary of the current state of the
3251 When REV is not given, print a summary of the current state of the
3229 repository.
3252 repository.
3230
3253
3231 Specifying a path to a repository root or Mercurial bundle will
3254 Specifying a path to a repository root or Mercurial bundle will
3232 cause lookup to operate on that repository/bundle.
3255 cause lookup to operate on that repository/bundle.
3233
3256
3234 .. container:: verbose
3257 .. container:: verbose
3235
3258
3236 Examples:
3259 Examples:
3237
3260
3238 - generate a build identifier for the working directory::
3261 - generate a build identifier for the working directory::
3239
3262
3240 hg id --id > build-id.dat
3263 hg id --id > build-id.dat
3241
3264
3242 - find the revision corresponding to a tag::
3265 - find the revision corresponding to a tag::
3243
3266
3244 hg id -n -r 1.3
3267 hg id -n -r 1.3
3245
3268
3246 - check the most recent revision of a remote repository::
3269 - check the most recent revision of a remote repository::
3247
3270
3248 hg id -r tip http://selenic.com/hg/
3271 hg id -r tip http://selenic.com/hg/
3249
3272
3250 Returns 0 if successful.
3273 Returns 0 if successful.
3251 """
3274 """
3252
3275
3253 if not repo and not source:
3276 if not repo and not source:
3254 raise util.Abort(_("there is no Mercurial repository here "
3277 raise util.Abort(_("there is no Mercurial repository here "
3255 "(.hg not found)"))
3278 "(.hg not found)"))
3256
3279
3257 hexfunc = ui.debugflag and hex or short
3280 hexfunc = ui.debugflag and hex or short
3258 default = not (num or id or branch or tags or bookmarks)
3281 default = not (num or id or branch or tags or bookmarks)
3259 output = []
3282 output = []
3260 revs = []
3283 revs = []
3261
3284
3262 if source:
3285 if source:
3263 source, branches = hg.parseurl(ui.expandpath(source))
3286 source, branches = hg.parseurl(ui.expandpath(source))
3264 repo = hg.peer(ui, {}, source)
3287 repo = hg.peer(ui, {}, source)
3265 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
3288 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
3266
3289
3267 if not repo.local():
3290 if not repo.local():
3268 if num or branch or tags:
3291 if num or branch or tags:
3269 raise util.Abort(
3292 raise util.Abort(
3270 _("can't query remote revision number, branch, or tags"))
3293 _("can't query remote revision number, branch, or tags"))
3271 if not rev and revs:
3294 if not rev and revs:
3272 rev = revs[0]
3295 rev = revs[0]
3273 if not rev:
3296 if not rev:
3274 rev = "tip"
3297 rev = "tip"
3275
3298
3276 remoterev = repo.lookup(rev)
3299 remoterev = repo.lookup(rev)
3277 if default or id:
3300 if default or id:
3278 output = [hexfunc(remoterev)]
3301 output = [hexfunc(remoterev)]
3279
3302
3280 def getbms():
3303 def getbms():
3281 bms = []
3304 bms = []
3282
3305
3283 if 'bookmarks' in repo.listkeys('namespaces'):
3306 if 'bookmarks' in repo.listkeys('namespaces'):
3284 hexremoterev = hex(remoterev)
3307 hexremoterev = hex(remoterev)
3285 bms = [bm for bm, bmr in repo.listkeys('bookmarks').iteritems()
3308 bms = [bm for bm, bmr in repo.listkeys('bookmarks').iteritems()
3286 if bmr == hexremoterev]
3309 if bmr == hexremoterev]
3287
3310
3288 return bms
3311 return bms
3289
3312
3290 if bookmarks:
3313 if bookmarks:
3291 output.extend(getbms())
3314 output.extend(getbms())
3292 elif default and not ui.quiet:
3315 elif default and not ui.quiet:
3293 # multiple bookmarks for a single parent separated by '/'
3316 # multiple bookmarks for a single parent separated by '/'
3294 bm = '/'.join(getbms())
3317 bm = '/'.join(getbms())
3295 if bm:
3318 if bm:
3296 output.append(bm)
3319 output.append(bm)
3297 else:
3320 else:
3298 if not rev:
3321 if not rev:
3299 ctx = repo[None]
3322 ctx = repo[None]
3300 parents = ctx.parents()
3323 parents = ctx.parents()
3301 changed = ""
3324 changed = ""
3302 if default or id or num:
3325 if default or id or num:
3303 changed = util.any(repo.status()) and "+" or ""
3326 changed = util.any(repo.status()) and "+" or ""
3304 if default or id:
3327 if default or id:
3305 output = ["%s%s" %
3328 output = ["%s%s" %
3306 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3329 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3307 if num:
3330 if num:
3308 output.append("%s%s" %
3331 output.append("%s%s" %
3309 ('+'.join([str(p.rev()) for p in parents]), changed))
3332 ('+'.join([str(p.rev()) for p in parents]), changed))
3310 else:
3333 else:
3311 ctx = scmutil.revsingle(repo, rev)
3334 ctx = scmutil.revsingle(repo, rev)
3312 if default or id:
3335 if default or id:
3313 output = [hexfunc(ctx.node())]
3336 output = [hexfunc(ctx.node())]
3314 if num:
3337 if num:
3315 output.append(str(ctx.rev()))
3338 output.append(str(ctx.rev()))
3316
3339
3317 if default and not ui.quiet:
3340 if default and not ui.quiet:
3318 b = ctx.branch()
3341 b = ctx.branch()
3319 if b != 'default':
3342 if b != 'default':
3320 output.append("(%s)" % b)
3343 output.append("(%s)" % b)
3321
3344
3322 # multiple tags for a single parent separated by '/'
3345 # multiple tags for a single parent separated by '/'
3323 t = '/'.join(ctx.tags())
3346 t = '/'.join(ctx.tags())
3324 if t:
3347 if t:
3325 output.append(t)
3348 output.append(t)
3326
3349
3327 # multiple bookmarks for a single parent separated by '/'
3350 # multiple bookmarks for a single parent separated by '/'
3328 bm = '/'.join(ctx.bookmarks())
3351 bm = '/'.join(ctx.bookmarks())
3329 if bm:
3352 if bm:
3330 output.append(bm)
3353 output.append(bm)
3331 else:
3354 else:
3332 if branch:
3355 if branch:
3333 output.append(ctx.branch())
3356 output.append(ctx.branch())
3334
3357
3335 if tags:
3358 if tags:
3336 output.extend(ctx.tags())
3359 output.extend(ctx.tags())
3337
3360
3338 if bookmarks:
3361 if bookmarks:
3339 output.extend(ctx.bookmarks())
3362 output.extend(ctx.bookmarks())
3340
3363
3341 ui.write("%s\n" % ' '.join(output))
3364 ui.write("%s\n" % ' '.join(output))
3342
3365
3343 @command('import|patch',
3366 @command('import|patch',
3344 [('p', 'strip', 1,
3367 [('p', 'strip', 1,
3345 _('directory strip option for patch. This has the same '
3368 _('directory strip option for patch. This has the same '
3346 'meaning as the corresponding patch option'), _('NUM')),
3369 'meaning as the corresponding patch option'), _('NUM')),
3347 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3370 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3348 ('e', 'edit', False, _('invoke editor on commit messages')),
3371 ('e', 'edit', False, _('invoke editor on commit messages')),
3349 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3372 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3350 ('', 'no-commit', None,
3373 ('', 'no-commit', None,
3351 _("don't commit, just update the working directory")),
3374 _("don't commit, just update the working directory")),
3352 ('', 'bypass', None,
3375 ('', 'bypass', None,
3353 _("apply patch without touching the working directory")),
3376 _("apply patch without touching the working directory")),
3354 ('', 'exact', None,
3377 ('', 'exact', None,
3355 _('apply patch to the nodes from which it was generated')),
3378 _('apply patch to the nodes from which it was generated')),
3356 ('', 'import-branch', None,
3379 ('', 'import-branch', None,
3357 _('use any branch information in patch (implied by --exact)'))] +
3380 _('use any branch information in patch (implied by --exact)'))] +
3358 commitopts + commitopts2 + similarityopts,
3381 commitopts + commitopts2 + similarityopts,
3359 _('[OPTION]... PATCH...'))
3382 _('[OPTION]... PATCH...'))
3360 def import_(ui, repo, patch1=None, *patches, **opts):
3383 def import_(ui, repo, patch1=None, *patches, **opts):
3361 """import an ordered set of patches
3384 """import an ordered set of patches
3362
3385
3363 Import a list of patches and commit them individually (unless
3386 Import a list of patches and commit them individually (unless
3364 --no-commit is specified).
3387 --no-commit is specified).
3365
3388
3366 If there are outstanding changes in the working directory, import
3389 If there are outstanding changes in the working directory, import
3367 will abort unless given the -f/--force flag.
3390 will abort unless given the -f/--force flag.
3368
3391
3369 You can import a patch straight from a mail message. Even patches
3392 You can import a patch straight from a mail message. Even patches
3370 as attachments work (to use the body part, it must have type
3393 as attachments work (to use the body part, it must have type
3371 text/plain or text/x-patch). From and Subject headers of email
3394 text/plain or text/x-patch). From and Subject headers of email
3372 message are used as default committer and commit message. All
3395 message are used as default committer and commit message. All
3373 text/plain body parts before first diff are added to commit
3396 text/plain body parts before first diff are added to commit
3374 message.
3397 message.
3375
3398
3376 If the imported patch was generated by :hg:`export`, user and
3399 If the imported patch was generated by :hg:`export`, user and
3377 description from patch override values from message headers and
3400 description from patch override values from message headers and
3378 body. Values given on command line with -m/--message and -u/--user
3401 body. Values given on command line with -m/--message and -u/--user
3379 override these.
3402 override these.
3380
3403
3381 If --exact is specified, import will set the working directory to
3404 If --exact is specified, import will set the working directory to
3382 the parent of each patch before applying it, and will abort if the
3405 the parent of each patch before applying it, and will abort if the
3383 resulting changeset has a different ID than the one recorded in
3406 resulting changeset has a different ID than the one recorded in
3384 the patch. This may happen due to character set problems or other
3407 the patch. This may happen due to character set problems or other
3385 deficiencies in the text patch format.
3408 deficiencies in the text patch format.
3386
3409
3387 Use --bypass to apply and commit patches directly to the
3410 Use --bypass to apply and commit patches directly to the
3388 repository, not touching the working directory. Without --exact,
3411 repository, not touching the working directory. Without --exact,
3389 patches will be applied on top of the working directory parent
3412 patches will be applied on top of the working directory parent
3390 revision.
3413 revision.
3391
3414
3392 With -s/--similarity, hg will attempt to discover renames and
3415 With -s/--similarity, hg will attempt to discover renames and
3393 copies in the patch in the same way as 'addremove'.
3416 copies in the patch in the same way as 'addremove'.
3394
3417
3395 To read a patch from standard input, use "-" as the patch name. If
3418 To read a patch from standard input, use "-" as the patch name. If
3396 a URL is specified, the patch will be downloaded from it.
3419 a URL is specified, the patch will be downloaded from it.
3397 See :hg:`help dates` for a list of formats valid for -d/--date.
3420 See :hg:`help dates` for a list of formats valid for -d/--date.
3398
3421
3399 .. container:: verbose
3422 .. container:: verbose
3400
3423
3401 Examples:
3424 Examples:
3402
3425
3403 - import a traditional patch from a website and detect renames::
3426 - import a traditional patch from a website and detect renames::
3404
3427
3405 hg import -s 80 http://example.com/bugfix.patch
3428 hg import -s 80 http://example.com/bugfix.patch
3406
3429
3407 - import a changeset from an hgweb server::
3430 - import a changeset from an hgweb server::
3408
3431
3409 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3432 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3410
3433
3411 - import all the patches in an Unix-style mbox::
3434 - import all the patches in an Unix-style mbox::
3412
3435
3413 hg import incoming-patches.mbox
3436 hg import incoming-patches.mbox
3414
3437
3415 - attempt to exactly restore an exported changeset (not always
3438 - attempt to exactly restore an exported changeset (not always
3416 possible)::
3439 possible)::
3417
3440
3418 hg import --exact proposed-fix.patch
3441 hg import --exact proposed-fix.patch
3419
3442
3420 Returns 0 on success.
3443 Returns 0 on success.
3421 """
3444 """
3422
3445
3423 if not patch1:
3446 if not patch1:
3424 raise util.Abort(_('need at least one patch to import'))
3447 raise util.Abort(_('need at least one patch to import'))
3425
3448
3426 patches = (patch1,) + patches
3449 patches = (patch1,) + patches
3427
3450
3428 date = opts.get('date')
3451 date = opts.get('date')
3429 if date:
3452 if date:
3430 opts['date'] = util.parsedate(date)
3453 opts['date'] = util.parsedate(date)
3431
3454
3432 editor = cmdutil.commiteditor
3455 editor = cmdutil.commiteditor
3433 if opts.get('edit'):
3456 if opts.get('edit'):
3434 editor = cmdutil.commitforceeditor
3457 editor = cmdutil.commitforceeditor
3435
3458
3436 update = not opts.get('bypass')
3459 update = not opts.get('bypass')
3437 if not update and opts.get('no_commit'):
3460 if not update and opts.get('no_commit'):
3438 raise util.Abort(_('cannot use --no-commit with --bypass'))
3461 raise util.Abort(_('cannot use --no-commit with --bypass'))
3439 try:
3462 try:
3440 sim = float(opts.get('similarity') or 0)
3463 sim = float(opts.get('similarity') or 0)
3441 except ValueError:
3464 except ValueError:
3442 raise util.Abort(_('similarity must be a number'))
3465 raise util.Abort(_('similarity must be a number'))
3443 if sim < 0 or sim > 100:
3466 if sim < 0 or sim > 100:
3444 raise util.Abort(_('similarity must be between 0 and 100'))
3467 raise util.Abort(_('similarity must be between 0 and 100'))
3445 if sim and not update:
3468 if sim and not update:
3446 raise util.Abort(_('cannot use --similarity with --bypass'))
3469 raise util.Abort(_('cannot use --similarity with --bypass'))
3447
3470
3448 if (opts.get('exact') or not opts.get('force')) and update:
3471 if (opts.get('exact') or not opts.get('force')) and update:
3449 cmdutil.bailifchanged(repo)
3472 cmdutil.bailifchanged(repo)
3450
3473
3451 base = opts["base"]
3474 base = opts["base"]
3452 strip = opts["strip"]
3475 strip = opts["strip"]
3453 wlock = lock = tr = None
3476 wlock = lock = tr = None
3454 msgs = []
3477 msgs = []
3455
3478
3456 def checkexact(repo, n, nodeid):
3479 def checkexact(repo, n, nodeid):
3457 if opts.get('exact') and hex(n) != nodeid:
3480 if opts.get('exact') and hex(n) != nodeid:
3458 repo.rollback()
3481 repo.rollback()
3459 raise util.Abort(_('patch is damaged or loses information'))
3482 raise util.Abort(_('patch is damaged or loses information'))
3460
3483
3461 def tryone(ui, hunk, parents):
3484 def tryone(ui, hunk, parents):
3462 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3485 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3463 patch.extract(ui, hunk)
3486 patch.extract(ui, hunk)
3464
3487
3465 if not tmpname:
3488 if not tmpname:
3466 return (None, None)
3489 return (None, None)
3467 msg = _('applied to working directory')
3490 msg = _('applied to working directory')
3468
3491
3469 try:
3492 try:
3470 cmdline_message = cmdutil.logmessage(ui, opts)
3493 cmdline_message = cmdutil.logmessage(ui, opts)
3471 if cmdline_message:
3494 if cmdline_message:
3472 # pickup the cmdline msg
3495 # pickup the cmdline msg
3473 message = cmdline_message
3496 message = cmdline_message
3474 elif message:
3497 elif message:
3475 # pickup the patch msg
3498 # pickup the patch msg
3476 message = message.strip()
3499 message = message.strip()
3477 else:
3500 else:
3478 # launch the editor
3501 # launch the editor
3479 message = None
3502 message = None
3480 ui.debug('message:\n%s\n' % message)
3503 ui.debug('message:\n%s\n' % message)
3481
3504
3482 if len(parents) == 1:
3505 if len(parents) == 1:
3483 parents.append(repo[nullid])
3506 parents.append(repo[nullid])
3484 if opts.get('exact'):
3507 if opts.get('exact'):
3485 if not nodeid or not p1:
3508 if not nodeid or not p1:
3486 raise util.Abort(_('not a Mercurial patch'))
3509 raise util.Abort(_('not a Mercurial patch'))
3487 p1 = repo[p1]
3510 p1 = repo[p1]
3488 p2 = repo[p2 or nullid]
3511 p2 = repo[p2 or nullid]
3489 elif p2:
3512 elif p2:
3490 try:
3513 try:
3491 p1 = repo[p1]
3514 p1 = repo[p1]
3492 p2 = repo[p2]
3515 p2 = repo[p2]
3493 except error.RepoError:
3516 except error.RepoError:
3494 p1, p2 = parents
3517 p1, p2 = parents
3495 else:
3518 else:
3496 p1, p2 = parents
3519 p1, p2 = parents
3497
3520
3498 n = None
3521 n = None
3499 if update:
3522 if update:
3500 if opts.get('exact') and p1 != parents[0]:
3523 if opts.get('exact') and p1 != parents[0]:
3501 hg.clean(repo, p1.node())
3524 hg.clean(repo, p1.node())
3502 if p1 != parents[0] and p2 != parents[1]:
3525 if p1 != parents[0] and p2 != parents[1]:
3503 repo.dirstate.setparents(p1.node(), p2.node())
3526 repo.dirstate.setparents(p1.node(), p2.node())
3504
3527
3505 if opts.get('exact') or opts.get('import_branch'):
3528 if opts.get('exact') or opts.get('import_branch'):
3506 repo.dirstate.setbranch(branch or 'default')
3529 repo.dirstate.setbranch(branch or 'default')
3507
3530
3508 files = set()
3531 files = set()
3509 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3532 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3510 eolmode=None, similarity=sim / 100.0)
3533 eolmode=None, similarity=sim / 100.0)
3511 files = list(files)
3534 files = list(files)
3512 if opts.get('no_commit'):
3535 if opts.get('no_commit'):
3513 if message:
3536 if message:
3514 msgs.append(message)
3537 msgs.append(message)
3515 else:
3538 else:
3516 if opts.get('exact'):
3539 if opts.get('exact'):
3517 m = None
3540 m = None
3518 else:
3541 else:
3519 m = scmutil.matchfiles(repo, files or [])
3542 m = scmutil.matchfiles(repo, files or [])
3520 n = repo.commit(message, opts.get('user') or user,
3543 n = repo.commit(message, opts.get('user') or user,
3521 opts.get('date') or date, match=m,
3544 opts.get('date') or date, match=m,
3522 editor=editor)
3545 editor=editor)
3523 checkexact(repo, n, nodeid)
3546 checkexact(repo, n, nodeid)
3524 else:
3547 else:
3525 if opts.get('exact') or opts.get('import_branch'):
3548 if opts.get('exact') or opts.get('import_branch'):
3526 branch = branch or 'default'
3549 branch = branch or 'default'
3527 else:
3550 else:
3528 branch = p1.branch()
3551 branch = p1.branch()
3529 store = patch.filestore()
3552 store = patch.filestore()
3530 try:
3553 try:
3531 files = set()
3554 files = set()
3532 try:
3555 try:
3533 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3556 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3534 files, eolmode=None)
3557 files, eolmode=None)
3535 except patch.PatchError, e:
3558 except patch.PatchError, e:
3536 raise util.Abort(str(e))
3559 raise util.Abort(str(e))
3537 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3560 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3538 message,
3561 message,
3539 opts.get('user') or user,
3562 opts.get('user') or user,
3540 opts.get('date') or date,
3563 opts.get('date') or date,
3541 branch, files, store,
3564 branch, files, store,
3542 editor=cmdutil.commiteditor)
3565 editor=cmdutil.commiteditor)
3543 repo.savecommitmessage(memctx.description())
3566 repo.savecommitmessage(memctx.description())
3544 n = memctx.commit()
3567 n = memctx.commit()
3545 checkexact(repo, n, nodeid)
3568 checkexact(repo, n, nodeid)
3546 finally:
3569 finally:
3547 store.close()
3570 store.close()
3548 if n:
3571 if n:
3549 # i18n: refers to a short changeset id
3572 # i18n: refers to a short changeset id
3550 msg = _('created %s') % short(n)
3573 msg = _('created %s') % short(n)
3551 return (msg, n)
3574 return (msg, n)
3552 finally:
3575 finally:
3553 os.unlink(tmpname)
3576 os.unlink(tmpname)
3554
3577
3555 try:
3578 try:
3556 try:
3579 try:
3557 wlock = repo.wlock()
3580 wlock = repo.wlock()
3558 lock = repo.lock()
3581 lock = repo.lock()
3559 tr = repo.transaction('import')
3582 tr = repo.transaction('import')
3560 parents = repo.parents()
3583 parents = repo.parents()
3561 for patchurl in patches:
3584 for patchurl in patches:
3562 if patchurl == '-':
3585 if patchurl == '-':
3563 ui.status(_('applying patch from stdin\n'))
3586 ui.status(_('applying patch from stdin\n'))
3564 patchfile = ui.fin
3587 patchfile = ui.fin
3565 patchurl = 'stdin' # for error message
3588 patchurl = 'stdin' # for error message
3566 else:
3589 else:
3567 patchurl = os.path.join(base, patchurl)
3590 patchurl = os.path.join(base, patchurl)
3568 ui.status(_('applying %s\n') % patchurl)
3591 ui.status(_('applying %s\n') % patchurl)
3569 patchfile = url.open(ui, patchurl)
3592 patchfile = url.open(ui, patchurl)
3570
3593
3571 haspatch = False
3594 haspatch = False
3572 for hunk in patch.split(patchfile):
3595 for hunk in patch.split(patchfile):
3573 (msg, node) = tryone(ui, hunk, parents)
3596 (msg, node) = tryone(ui, hunk, parents)
3574 if msg:
3597 if msg:
3575 haspatch = True
3598 haspatch = True
3576 ui.note(msg + '\n')
3599 ui.note(msg + '\n')
3577 if update or opts.get('exact'):
3600 if update or opts.get('exact'):
3578 parents = repo.parents()
3601 parents = repo.parents()
3579 else:
3602 else:
3580 parents = [repo[node]]
3603 parents = [repo[node]]
3581
3604
3582 if not haspatch:
3605 if not haspatch:
3583 raise util.Abort(_('%s: no diffs found') % patchurl)
3606 raise util.Abort(_('%s: no diffs found') % patchurl)
3584
3607
3585 tr.close()
3608 tr.close()
3586 if msgs:
3609 if msgs:
3587 repo.savecommitmessage('\n* * *\n'.join(msgs))
3610 repo.savecommitmessage('\n* * *\n'.join(msgs))
3588 except:
3611 except:
3589 # wlock.release() indirectly calls dirstate.write(): since
3612 # wlock.release() indirectly calls dirstate.write(): since
3590 # we're crashing, we do not want to change the working dir
3613 # we're crashing, we do not want to change the working dir
3591 # parent after all, so make sure it writes nothing
3614 # parent after all, so make sure it writes nothing
3592 repo.dirstate.invalidate()
3615 repo.dirstate.invalidate()
3593 raise
3616 raise
3594 finally:
3617 finally:
3595 if tr:
3618 if tr:
3596 tr.release()
3619 tr.release()
3597 release(lock, wlock)
3620 release(lock, wlock)
3598
3621
3599 @command('incoming|in',
3622 @command('incoming|in',
3600 [('f', 'force', None,
3623 [('f', 'force', None,
3601 _('run even if remote repository is unrelated')),
3624 _('run even if remote repository is unrelated')),
3602 ('n', 'newest-first', None, _('show newest record first')),
3625 ('n', 'newest-first', None, _('show newest record first')),
3603 ('', 'bundle', '',
3626 ('', 'bundle', '',
3604 _('file to store the bundles into'), _('FILE')),
3627 _('file to store the bundles into'), _('FILE')),
3605 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3628 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3606 ('B', 'bookmarks', False, _("compare bookmarks")),
3629 ('B', 'bookmarks', False, _("compare bookmarks")),
3607 ('b', 'branch', [],
3630 ('b', 'branch', [],
3608 _('a specific branch you would like to pull'), _('BRANCH')),
3631 _('a specific branch you would like to pull'), _('BRANCH')),
3609 ] + logopts + remoteopts + subrepoopts,
3632 ] + logopts + remoteopts + subrepoopts,
3610 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3633 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3611 def incoming(ui, repo, source="default", **opts):
3634 def incoming(ui, repo, source="default", **opts):
3612 """show new changesets found in source
3635 """show new changesets found in source
3613
3636
3614 Show new changesets found in the specified path/URL or the default
3637 Show new changesets found in the specified path/URL or the default
3615 pull location. These are the changesets that would have been pulled
3638 pull location. These are the changesets that would have been pulled
3616 if a pull at the time you issued this command.
3639 if a pull at the time you issued this command.
3617
3640
3618 For remote repository, using --bundle avoids downloading the
3641 For remote repository, using --bundle avoids downloading the
3619 changesets twice if the incoming is followed by a pull.
3642 changesets twice if the incoming is followed by a pull.
3620
3643
3621 See pull for valid source format details.
3644 See pull for valid source format details.
3622
3645
3623 Returns 0 if there are incoming changes, 1 otherwise.
3646 Returns 0 if there are incoming changes, 1 otherwise.
3624 """
3647 """
3625 if opts.get('bundle') and opts.get('subrepos'):
3648 if opts.get('bundle') and opts.get('subrepos'):
3626 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3649 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3627
3650
3628 if opts.get('bookmarks'):
3651 if opts.get('bookmarks'):
3629 source, branches = hg.parseurl(ui.expandpath(source),
3652 source, branches = hg.parseurl(ui.expandpath(source),
3630 opts.get('branch'))
3653 opts.get('branch'))
3631 other = hg.peer(repo, opts, source)
3654 other = hg.peer(repo, opts, source)
3632 if 'bookmarks' not in other.listkeys('namespaces'):
3655 if 'bookmarks' not in other.listkeys('namespaces'):
3633 ui.warn(_("remote doesn't support bookmarks\n"))
3656 ui.warn(_("remote doesn't support bookmarks\n"))
3634 return 0
3657 return 0
3635 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3658 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3636 return bookmarks.diff(ui, repo, other)
3659 return bookmarks.diff(ui, repo, other)
3637
3660
3638 repo._subtoppath = ui.expandpath(source)
3661 repo._subtoppath = ui.expandpath(source)
3639 try:
3662 try:
3640 return hg.incoming(ui, repo, source, opts)
3663 return hg.incoming(ui, repo, source, opts)
3641 finally:
3664 finally:
3642 del repo._subtoppath
3665 del repo._subtoppath
3643
3666
3644
3667
3645 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3668 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3646 def init(ui, dest=".", **opts):
3669 def init(ui, dest=".", **opts):
3647 """create a new repository in the given directory
3670 """create a new repository in the given directory
3648
3671
3649 Initialize a new repository in the given directory. If the given
3672 Initialize a new repository in the given directory. If the given
3650 directory does not exist, it will be created.
3673 directory does not exist, it will be created.
3651
3674
3652 If no directory is given, the current directory is used.
3675 If no directory is given, the current directory is used.
3653
3676
3654 It is possible to specify an ``ssh://`` URL as the destination.
3677 It is possible to specify an ``ssh://`` URL as the destination.
3655 See :hg:`help urls` for more information.
3678 See :hg:`help urls` for more information.
3656
3679
3657 Returns 0 on success.
3680 Returns 0 on success.
3658 """
3681 """
3659 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3682 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3660
3683
3661 @command('locate',
3684 @command('locate',
3662 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3685 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3663 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3686 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3664 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3687 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3665 ] + walkopts,
3688 ] + walkopts,
3666 _('[OPTION]... [PATTERN]...'))
3689 _('[OPTION]... [PATTERN]...'))
3667 def locate(ui, repo, *pats, **opts):
3690 def locate(ui, repo, *pats, **opts):
3668 """locate files matching specific patterns
3691 """locate files matching specific patterns
3669
3692
3670 Print files under Mercurial control in the working directory whose
3693 Print files under Mercurial control in the working directory whose
3671 names match the given patterns.
3694 names match the given patterns.
3672
3695
3673 By default, this command searches all directories in the working
3696 By default, this command searches all directories in the working
3674 directory. To search just the current directory and its
3697 directory. To search just the current directory and its
3675 subdirectories, use "--include .".
3698 subdirectories, use "--include .".
3676
3699
3677 If no patterns are given to match, this command prints the names
3700 If no patterns are given to match, this command prints the names
3678 of all files under Mercurial control in the working directory.
3701 of all files under Mercurial control in the working directory.
3679
3702
3680 If you want to feed the output of this command into the "xargs"
3703 If you want to feed the output of this command into the "xargs"
3681 command, use the -0 option to both this command and "xargs". This
3704 command, use the -0 option to both this command and "xargs". This
3682 will avoid the problem of "xargs" treating single filenames that
3705 will avoid the problem of "xargs" treating single filenames that
3683 contain whitespace as multiple filenames.
3706 contain whitespace as multiple filenames.
3684
3707
3685 Returns 0 if a match is found, 1 otherwise.
3708 Returns 0 if a match is found, 1 otherwise.
3686 """
3709 """
3687 end = opts.get('print0') and '\0' or '\n'
3710 end = opts.get('print0') and '\0' or '\n'
3688 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3711 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3689
3712
3690 ret = 1
3713 ret = 1
3691 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3714 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3692 m.bad = lambda x, y: False
3715 m.bad = lambda x, y: False
3693 for abs in repo[rev].walk(m):
3716 for abs in repo[rev].walk(m):
3694 if not rev and abs not in repo.dirstate:
3717 if not rev and abs not in repo.dirstate:
3695 continue
3718 continue
3696 if opts.get('fullpath'):
3719 if opts.get('fullpath'):
3697 ui.write(repo.wjoin(abs), end)
3720 ui.write(repo.wjoin(abs), end)
3698 else:
3721 else:
3699 ui.write(((pats and m.rel(abs)) or abs), end)
3722 ui.write(((pats and m.rel(abs)) or abs), end)
3700 ret = 0
3723 ret = 0
3701
3724
3702 return ret
3725 return ret
3703
3726
3704 @command('^log|history',
3727 @command('^log|history',
3705 [('f', 'follow', None,
3728 [('f', 'follow', None,
3706 _('follow changeset history, or file history across copies and renames')),
3729 _('follow changeset history, or file history across copies and renames')),
3707 ('', 'follow-first', None,
3730 ('', 'follow-first', None,
3708 _('only follow the first parent of merge changesets (DEPRECATED)')),
3731 _('only follow the first parent of merge changesets (DEPRECATED)')),
3709 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3732 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3710 ('C', 'copies', None, _('show copied files')),
3733 ('C', 'copies', None, _('show copied files')),
3711 ('k', 'keyword', [],
3734 ('k', 'keyword', [],
3712 _('do case-insensitive search for a given text'), _('TEXT')),
3735 _('do case-insensitive search for a given text'), _('TEXT')),
3713 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3736 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3714 ('', 'removed', None, _('include revisions where files were removed')),
3737 ('', 'removed', None, _('include revisions where files were removed')),
3715 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3738 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3716 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3739 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3717 ('', 'only-branch', [],
3740 ('', 'only-branch', [],
3718 _('show only changesets within the given named branch (DEPRECATED)'),
3741 _('show only changesets within the given named branch (DEPRECATED)'),
3719 _('BRANCH')),
3742 _('BRANCH')),
3720 ('b', 'branch', [],
3743 ('b', 'branch', [],
3721 _('show changesets within the given named branch'), _('BRANCH')),
3744 _('show changesets within the given named branch'), _('BRANCH')),
3722 ('P', 'prune', [],
3745 ('P', 'prune', [],
3723 _('do not display revision or any of its ancestors'), _('REV')),
3746 _('do not display revision or any of its ancestors'), _('REV')),
3724 ('', 'hidden', False, _('show hidden changesets (DEPRECATED)')),
3747 ('', 'hidden', False, _('show hidden changesets (DEPRECATED)')),
3725 ] + logopts + walkopts,
3748 ] + logopts + walkopts,
3726 _('[OPTION]... [FILE]'))
3749 _('[OPTION]... [FILE]'))
3727 def log(ui, repo, *pats, **opts):
3750 def log(ui, repo, *pats, **opts):
3728 """show revision history of entire repository or files
3751 """show revision history of entire repository or files
3729
3752
3730 Print the revision history of the specified files or the entire
3753 Print the revision history of the specified files or the entire
3731 project.
3754 project.
3732
3755
3733 If no revision range is specified, the default is ``tip:0`` unless
3756 If no revision range is specified, the default is ``tip:0`` unless
3734 --follow is set, in which case the working directory parent is
3757 --follow is set, in which case the working directory parent is
3735 used as the starting revision.
3758 used as the starting revision.
3736
3759
3737 File history is shown without following rename or copy history of
3760 File history is shown without following rename or copy history of
3738 files. Use -f/--follow with a filename to follow history across
3761 files. Use -f/--follow with a filename to follow history across
3739 renames and copies. --follow without a filename will only show
3762 renames and copies. --follow without a filename will only show
3740 ancestors or descendants of the starting revision.
3763 ancestors or descendants of the starting revision.
3741
3764
3742 By default this command prints revision number and changeset id,
3765 By default this command prints revision number and changeset id,
3743 tags, non-trivial parents, user, date and time, and a summary for
3766 tags, non-trivial parents, user, date and time, and a summary for
3744 each commit. When the -v/--verbose switch is used, the list of
3767 each commit. When the -v/--verbose switch is used, the list of
3745 changed files and full commit message are shown.
3768 changed files and full commit message are shown.
3746
3769
3747 .. note::
3770 .. note::
3748 log -p/--patch may generate unexpected diff output for merge
3771 log -p/--patch may generate unexpected diff output for merge
3749 changesets, as it will only compare the merge changeset against
3772 changesets, as it will only compare the merge changeset against
3750 its first parent. Also, only files different from BOTH parents
3773 its first parent. Also, only files different from BOTH parents
3751 will appear in files:.
3774 will appear in files:.
3752
3775
3753 .. note::
3776 .. note::
3754 for performance reasons, log FILE may omit duplicate changes
3777 for performance reasons, log FILE may omit duplicate changes
3755 made on branches and will not show deletions. To see all
3778 made on branches and will not show deletions. To see all
3756 changes including duplicates and deletions, use the --removed
3779 changes including duplicates and deletions, use the --removed
3757 switch.
3780 switch.
3758
3781
3759 .. container:: verbose
3782 .. container:: verbose
3760
3783
3761 Some examples:
3784 Some examples:
3762
3785
3763 - changesets with full descriptions and file lists::
3786 - changesets with full descriptions and file lists::
3764
3787
3765 hg log -v
3788 hg log -v
3766
3789
3767 - changesets ancestral to the working directory::
3790 - changesets ancestral to the working directory::
3768
3791
3769 hg log -f
3792 hg log -f
3770
3793
3771 - last 10 commits on the current branch::
3794 - last 10 commits on the current branch::
3772
3795
3773 hg log -l 10 -b .
3796 hg log -l 10 -b .
3774
3797
3775 - changesets showing all modifications of a file, including removals::
3798 - changesets showing all modifications of a file, including removals::
3776
3799
3777 hg log --removed file.c
3800 hg log --removed file.c
3778
3801
3779 - all changesets that touch a directory, with diffs, excluding merges::
3802 - all changesets that touch a directory, with diffs, excluding merges::
3780
3803
3781 hg log -Mp lib/
3804 hg log -Mp lib/
3782
3805
3783 - all revision numbers that match a keyword::
3806 - all revision numbers that match a keyword::
3784
3807
3785 hg log -k bug --template "{rev}\\n"
3808 hg log -k bug --template "{rev}\\n"
3786
3809
3787 - check if a given changeset is included is a tagged release::
3810 - check if a given changeset is included is a tagged release::
3788
3811
3789 hg log -r "a21ccf and ancestor(1.9)"
3812 hg log -r "a21ccf and ancestor(1.9)"
3790
3813
3791 - find all changesets by some user in a date range::
3814 - find all changesets by some user in a date range::
3792
3815
3793 hg log -k alice -d "may 2008 to jul 2008"
3816 hg log -k alice -d "may 2008 to jul 2008"
3794
3817
3795 - summary of all changesets after the last tag::
3818 - summary of all changesets after the last tag::
3796
3819
3797 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3820 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3798
3821
3799 See :hg:`help dates` for a list of formats valid for -d/--date.
3822 See :hg:`help dates` for a list of formats valid for -d/--date.
3800
3823
3801 See :hg:`help revisions` and :hg:`help revsets` for more about
3824 See :hg:`help revisions` and :hg:`help revsets` for more about
3802 specifying revisions.
3825 specifying revisions.
3803
3826
3804 Returns 0 on success.
3827 Returns 0 on success.
3805 """
3828 """
3806
3829
3807 matchfn = scmutil.match(repo[None], pats, opts)
3830 matchfn = scmutil.match(repo[None], pats, opts)
3808 limit = cmdutil.loglimit(opts)
3831 limit = cmdutil.loglimit(opts)
3809 count = 0
3832 count = 0
3810
3833
3811 endrev = None
3834 endrev = None
3812 if opts.get('copies') and opts.get('rev'):
3835 if opts.get('copies') and opts.get('rev'):
3813 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
3836 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
3814
3837
3815 df = False
3838 df = False
3816 if opts["date"]:
3839 if opts["date"]:
3817 df = util.matchdate(opts["date"])
3840 df = util.matchdate(opts["date"])
3818
3841
3819 branches = opts.get('branch', []) + opts.get('only_branch', [])
3842 branches = opts.get('branch', []) + opts.get('only_branch', [])
3820 opts['branch'] = [repo.lookupbranch(b) for b in branches]
3843 opts['branch'] = [repo.lookupbranch(b) for b in branches]
3821
3844
3822 displayer = cmdutil.show_changeset(ui, repo, opts, True)
3845 displayer = cmdutil.show_changeset(ui, repo, opts, True)
3823 def prep(ctx, fns):
3846 def prep(ctx, fns):
3824 rev = ctx.rev()
3847 rev = ctx.rev()
3825 parents = [p for p in repo.changelog.parentrevs(rev)
3848 parents = [p for p in repo.changelog.parentrevs(rev)
3826 if p != nullrev]
3849 if p != nullrev]
3827 if opts.get('no_merges') and len(parents) == 2:
3850 if opts.get('no_merges') and len(parents) == 2:
3828 return
3851 return
3829 if opts.get('only_merges') and len(parents) != 2:
3852 if opts.get('only_merges') and len(parents) != 2:
3830 return
3853 return
3831 if opts.get('branch') and ctx.branch() not in opts['branch']:
3854 if opts.get('branch') and ctx.branch() not in opts['branch']:
3832 return
3855 return
3833 if not opts.get('hidden') and ctx.hidden():
3856 if not opts.get('hidden') and ctx.hidden():
3834 return
3857 return
3835 if df and not df(ctx.date()[0]):
3858 if df and not df(ctx.date()[0]):
3836 return
3859 return
3837 if opts['user'] and not [k for k in opts['user']
3860 if opts['user'] and not [k for k in opts['user']
3838 if k.lower() in ctx.user().lower()]:
3861 if k.lower() in ctx.user().lower()]:
3839 return
3862 return
3840 if opts.get('keyword'):
3863 if opts.get('keyword'):
3841 for k in [kw.lower() for kw in opts['keyword']]:
3864 for k in [kw.lower() for kw in opts['keyword']]:
3842 if (k in ctx.user().lower() or
3865 if (k in ctx.user().lower() or
3843 k in ctx.description().lower() or
3866 k in ctx.description().lower() or
3844 k in " ".join(ctx.files()).lower()):
3867 k in " ".join(ctx.files()).lower()):
3845 break
3868 break
3846 else:
3869 else:
3847 return
3870 return
3848
3871
3849 copies = None
3872 copies = None
3850 if opts.get('copies') and rev:
3873 if opts.get('copies') and rev:
3851 copies = []
3874 copies = []
3852 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3875 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3853 for fn in ctx.files():
3876 for fn in ctx.files():
3854 rename = getrenamed(fn, rev)
3877 rename = getrenamed(fn, rev)
3855 if rename:
3878 if rename:
3856 copies.append((fn, rename[0]))
3879 copies.append((fn, rename[0]))
3857
3880
3858 revmatchfn = None
3881 revmatchfn = None
3859 if opts.get('patch') or opts.get('stat'):
3882 if opts.get('patch') or opts.get('stat'):
3860 if opts.get('follow') or opts.get('follow_first'):
3883 if opts.get('follow') or opts.get('follow_first'):
3861 # note: this might be wrong when following through merges
3884 # note: this might be wrong when following through merges
3862 revmatchfn = scmutil.match(repo[None], fns, default='path')
3885 revmatchfn = scmutil.match(repo[None], fns, default='path')
3863 else:
3886 else:
3864 revmatchfn = matchfn
3887 revmatchfn = matchfn
3865
3888
3866 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3889 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3867
3890
3868 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3891 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3869 if count == limit:
3892 if count == limit:
3870 break
3893 break
3871 if displayer.flush(ctx.rev()):
3894 if displayer.flush(ctx.rev()):
3872 count += 1
3895 count += 1
3873 displayer.close()
3896 displayer.close()
3874
3897
3875 @command('manifest',
3898 @command('manifest',
3876 [('r', 'rev', '', _('revision to display'), _('REV')),
3899 [('r', 'rev', '', _('revision to display'), _('REV')),
3877 ('', 'all', False, _("list files from all revisions"))],
3900 ('', 'all', False, _("list files from all revisions"))],
3878 _('[-r REV]'))
3901 _('[-r REV]'))
3879 def manifest(ui, repo, node=None, rev=None, **opts):
3902 def manifest(ui, repo, node=None, rev=None, **opts):
3880 """output the current or given revision of the project manifest
3903 """output the current or given revision of the project manifest
3881
3904
3882 Print a list of version controlled files for the given revision.
3905 Print a list of version controlled files for the given revision.
3883 If no revision is given, the first parent of the working directory
3906 If no revision is given, the first parent of the working directory
3884 is used, or the null revision if no revision is checked out.
3907 is used, or the null revision if no revision is checked out.
3885
3908
3886 With -v, print file permissions, symlink and executable bits.
3909 With -v, print file permissions, symlink and executable bits.
3887 With --debug, print file revision hashes.
3910 With --debug, print file revision hashes.
3888
3911
3889 If option --all is specified, the list of all files from all revisions
3912 If option --all is specified, the list of all files from all revisions
3890 is printed. This includes deleted and renamed files.
3913 is printed. This includes deleted and renamed files.
3891
3914
3892 Returns 0 on success.
3915 Returns 0 on success.
3893 """
3916 """
3894 if opts.get('all'):
3917 if opts.get('all'):
3895 if rev or node:
3918 if rev or node:
3896 raise util.Abort(_("can't specify a revision with --all"))
3919 raise util.Abort(_("can't specify a revision with --all"))
3897
3920
3898 res = []
3921 res = []
3899 prefix = "data/"
3922 prefix = "data/"
3900 suffix = ".i"
3923 suffix = ".i"
3901 plen = len(prefix)
3924 plen = len(prefix)
3902 slen = len(suffix)
3925 slen = len(suffix)
3903 lock = repo.lock()
3926 lock = repo.lock()
3904 try:
3927 try:
3905 for fn, b, size in repo.store.datafiles():
3928 for fn, b, size in repo.store.datafiles():
3906 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3929 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3907 res.append(fn[plen:-slen])
3930 res.append(fn[plen:-slen])
3908 finally:
3931 finally:
3909 lock.release()
3932 lock.release()
3910 for f in sorted(res):
3933 for f in sorted(res):
3911 ui.write("%s\n" % f)
3934 ui.write("%s\n" % f)
3912 return
3935 return
3913
3936
3914 if rev and node:
3937 if rev and node:
3915 raise util.Abort(_("please specify just one revision"))
3938 raise util.Abort(_("please specify just one revision"))
3916
3939
3917 if not node:
3940 if not node:
3918 node = rev
3941 node = rev
3919
3942
3920 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
3943 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
3921 ctx = scmutil.revsingle(repo, node)
3944 ctx = scmutil.revsingle(repo, node)
3922 for f in ctx:
3945 for f in ctx:
3923 if ui.debugflag:
3946 if ui.debugflag:
3924 ui.write("%40s " % hex(ctx.manifest()[f]))
3947 ui.write("%40s " % hex(ctx.manifest()[f]))
3925 if ui.verbose:
3948 if ui.verbose:
3926 ui.write(decor[ctx.flags(f)])
3949 ui.write(decor[ctx.flags(f)])
3927 ui.write("%s\n" % f)
3950 ui.write("%s\n" % f)
3928
3951
3929 @command('^merge',
3952 @command('^merge',
3930 [('f', 'force', None, _('force a merge with outstanding changes')),
3953 [('f', 'force', None, _('force a merge with outstanding changes')),
3931 ('r', 'rev', '', _('revision to merge'), _('REV')),
3954 ('r', 'rev', '', _('revision to merge'), _('REV')),
3932 ('P', 'preview', None,
3955 ('P', 'preview', None,
3933 _('review revisions to merge (no merge is performed)'))
3956 _('review revisions to merge (no merge is performed)'))
3934 ] + mergetoolopts,
3957 ] + mergetoolopts,
3935 _('[-P] [-f] [[-r] REV]'))
3958 _('[-P] [-f] [[-r] REV]'))
3936 def merge(ui, repo, node=None, **opts):
3959 def merge(ui, repo, node=None, **opts):
3937 """merge working directory with another revision
3960 """merge working directory with another revision
3938
3961
3939 The current working directory is updated with all changes made in
3962 The current working directory is updated with all changes made in
3940 the requested revision since the last common predecessor revision.
3963 the requested revision since the last common predecessor revision.
3941
3964
3942 Files that changed between either parent are marked as changed for
3965 Files that changed between either parent are marked as changed for
3943 the next commit and a commit must be performed before any further
3966 the next commit and a commit must be performed before any further
3944 updates to the repository are allowed. The next commit will have
3967 updates to the repository are allowed. The next commit will have
3945 two parents.
3968 two parents.
3946
3969
3947 ``--tool`` can be used to specify the merge tool used for file
3970 ``--tool`` can be used to specify the merge tool used for file
3948 merges. It overrides the HGMERGE environment variable and your
3971 merges. It overrides the HGMERGE environment variable and your
3949 configuration files. See :hg:`help merge-tools` for options.
3972 configuration files. See :hg:`help merge-tools` for options.
3950
3973
3951 If no revision is specified, the working directory's parent is a
3974 If no revision is specified, the working directory's parent is a
3952 head revision, and the current branch contains exactly one other
3975 head revision, and the current branch contains exactly one other
3953 head, the other head is merged with by default. Otherwise, an
3976 head, the other head is merged with by default. Otherwise, an
3954 explicit revision with which to merge with must be provided.
3977 explicit revision with which to merge with must be provided.
3955
3978
3956 :hg:`resolve` must be used to resolve unresolved files.
3979 :hg:`resolve` must be used to resolve unresolved files.
3957
3980
3958 To undo an uncommitted merge, use :hg:`update --clean .` which
3981 To undo an uncommitted merge, use :hg:`update --clean .` which
3959 will check out a clean copy of the original merge parent, losing
3982 will check out a clean copy of the original merge parent, losing
3960 all changes.
3983 all changes.
3961
3984
3962 Returns 0 on success, 1 if there are unresolved files.
3985 Returns 0 on success, 1 if there are unresolved files.
3963 """
3986 """
3964
3987
3965 if opts.get('rev') and node:
3988 if opts.get('rev') and node:
3966 raise util.Abort(_("please specify just one revision"))
3989 raise util.Abort(_("please specify just one revision"))
3967 if not node:
3990 if not node:
3968 node = opts.get('rev')
3991 node = opts.get('rev')
3969
3992
3970 if not node:
3993 if not node:
3971 branch = repo[None].branch()
3994 branch = repo[None].branch()
3972 bheads = repo.branchheads(branch)
3995 bheads = repo.branchheads(branch)
3973 if len(bheads) > 2:
3996 if len(bheads) > 2:
3974 raise util.Abort(_("branch '%s' has %d heads - "
3997 raise util.Abort(_("branch '%s' has %d heads - "
3975 "please merge with an explicit rev")
3998 "please merge with an explicit rev")
3976 % (branch, len(bheads)),
3999 % (branch, len(bheads)),
3977 hint=_("run 'hg heads .' to see heads"))
4000 hint=_("run 'hg heads .' to see heads"))
3978
4001
3979 parent = repo.dirstate.p1()
4002 parent = repo.dirstate.p1()
3980 if len(bheads) == 1:
4003 if len(bheads) == 1:
3981 if len(repo.heads()) > 1:
4004 if len(repo.heads()) > 1:
3982 raise util.Abort(_("branch '%s' has one head - "
4005 raise util.Abort(_("branch '%s' has one head - "
3983 "please merge with an explicit rev")
4006 "please merge with an explicit rev")
3984 % branch,
4007 % branch,
3985 hint=_("run 'hg heads' to see all heads"))
4008 hint=_("run 'hg heads' to see all heads"))
3986 msg = _('there is nothing to merge')
4009 msg = _('there is nothing to merge')
3987 if parent != repo.lookup(repo[None].branch()):
4010 if parent != repo.lookup(repo[None].branch()):
3988 msg = _('%s - use "hg update" instead') % msg
4011 msg = _('%s - use "hg update" instead') % msg
3989 raise util.Abort(msg)
4012 raise util.Abort(msg)
3990
4013
3991 if parent not in bheads:
4014 if parent not in bheads:
3992 raise util.Abort(_('working directory not at a head revision'),
4015 raise util.Abort(_('working directory not at a head revision'),
3993 hint=_("use 'hg update' or merge with an "
4016 hint=_("use 'hg update' or merge with an "
3994 "explicit revision"))
4017 "explicit revision"))
3995 node = parent == bheads[0] and bheads[-1] or bheads[0]
4018 node = parent == bheads[0] and bheads[-1] or bheads[0]
3996 else:
4019 else:
3997 node = scmutil.revsingle(repo, node).node()
4020 node = scmutil.revsingle(repo, node).node()
3998
4021
3999 if opts.get('preview'):
4022 if opts.get('preview'):
4000 # find nodes that are ancestors of p2 but not of p1
4023 # find nodes that are ancestors of p2 but not of p1
4001 p1 = repo.lookup('.')
4024 p1 = repo.lookup('.')
4002 p2 = repo.lookup(node)
4025 p2 = repo.lookup(node)
4003 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4026 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4004
4027
4005 displayer = cmdutil.show_changeset(ui, repo, opts)
4028 displayer = cmdutil.show_changeset(ui, repo, opts)
4006 for node in nodes:
4029 for node in nodes:
4007 displayer.show(repo[node])
4030 displayer.show(repo[node])
4008 displayer.close()
4031 displayer.close()
4009 return 0
4032 return 0
4010
4033
4011 try:
4034 try:
4012 # ui.forcemerge is an internal variable, do not document
4035 # ui.forcemerge is an internal variable, do not document
4013 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4036 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4014 return hg.merge(repo, node, force=opts.get('force'))
4037 return hg.merge(repo, node, force=opts.get('force'))
4015 finally:
4038 finally:
4016 ui.setconfig('ui', 'forcemerge', '')
4039 ui.setconfig('ui', 'forcemerge', '')
4017
4040
4018 @command('outgoing|out',
4041 @command('outgoing|out',
4019 [('f', 'force', None, _('run even when the destination is unrelated')),
4042 [('f', 'force', None, _('run even when the destination is unrelated')),
4020 ('r', 'rev', [],
4043 ('r', 'rev', [],
4021 _('a changeset intended to be included in the destination'), _('REV')),
4044 _('a changeset intended to be included in the destination'), _('REV')),
4022 ('n', 'newest-first', None, _('show newest record first')),
4045 ('n', 'newest-first', None, _('show newest record first')),
4023 ('B', 'bookmarks', False, _('compare bookmarks')),
4046 ('B', 'bookmarks', False, _('compare bookmarks')),
4024 ('b', 'branch', [], _('a specific branch you would like to push'),
4047 ('b', 'branch', [], _('a specific branch you would like to push'),
4025 _('BRANCH')),
4048 _('BRANCH')),
4026 ] + logopts + remoteopts + subrepoopts,
4049 ] + logopts + remoteopts + subrepoopts,
4027 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4050 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4028 def outgoing(ui, repo, dest=None, **opts):
4051 def outgoing(ui, repo, dest=None, **opts):
4029 """show changesets not found in the destination
4052 """show changesets not found in the destination
4030
4053
4031 Show changesets not found in the specified destination repository
4054 Show changesets not found in the specified destination repository
4032 or the default push location. These are the changesets that would
4055 or the default push location. These are the changesets that would
4033 be pushed if a push was requested.
4056 be pushed if a push was requested.
4034
4057
4035 See pull for details of valid destination formats.
4058 See pull for details of valid destination formats.
4036
4059
4037 Returns 0 if there are outgoing changes, 1 otherwise.
4060 Returns 0 if there are outgoing changes, 1 otherwise.
4038 """
4061 """
4039
4062
4040 if opts.get('bookmarks'):
4063 if opts.get('bookmarks'):
4041 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4064 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4042 dest, branches = hg.parseurl(dest, opts.get('branch'))
4065 dest, branches = hg.parseurl(dest, opts.get('branch'))
4043 other = hg.peer(repo, opts, dest)
4066 other = hg.peer(repo, opts, dest)
4044 if 'bookmarks' not in other.listkeys('namespaces'):
4067 if 'bookmarks' not in other.listkeys('namespaces'):
4045 ui.warn(_("remote doesn't support bookmarks\n"))
4068 ui.warn(_("remote doesn't support bookmarks\n"))
4046 return 0
4069 return 0
4047 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4070 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4048 return bookmarks.diff(ui, other, repo)
4071 return bookmarks.diff(ui, other, repo)
4049
4072
4050 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4073 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4051 try:
4074 try:
4052 return hg.outgoing(ui, repo, dest, opts)
4075 return hg.outgoing(ui, repo, dest, opts)
4053 finally:
4076 finally:
4054 del repo._subtoppath
4077 del repo._subtoppath
4055
4078
4056 @command('parents',
4079 @command('parents',
4057 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4080 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4058 ] + templateopts,
4081 ] + templateopts,
4059 _('[-r REV] [FILE]'))
4082 _('[-r REV] [FILE]'))
4060 def parents(ui, repo, file_=None, **opts):
4083 def parents(ui, repo, file_=None, **opts):
4061 """show the parents of the working directory or revision
4084 """show the parents of the working directory or revision
4062
4085
4063 Print the working directory's parent revisions. If a revision is
4086 Print the working directory's parent revisions. If a revision is
4064 given via -r/--rev, the parent of that revision will be printed.
4087 given via -r/--rev, the parent of that revision will be printed.
4065 If a file argument is given, the revision in which the file was
4088 If a file argument is given, the revision in which the file was
4066 last changed (before the working directory revision or the
4089 last changed (before the working directory revision or the
4067 argument to --rev if given) is printed.
4090 argument to --rev if given) is printed.
4068
4091
4069 Returns 0 on success.
4092 Returns 0 on success.
4070 """
4093 """
4071
4094
4072 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4095 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4073
4096
4074 if file_:
4097 if file_:
4075 m = scmutil.match(ctx, (file_,), opts)
4098 m = scmutil.match(ctx, (file_,), opts)
4076 if m.anypats() or len(m.files()) != 1:
4099 if m.anypats() or len(m.files()) != 1:
4077 raise util.Abort(_('can only specify an explicit filename'))
4100 raise util.Abort(_('can only specify an explicit filename'))
4078 file_ = m.files()[0]
4101 file_ = m.files()[0]
4079 filenodes = []
4102 filenodes = []
4080 for cp in ctx.parents():
4103 for cp in ctx.parents():
4081 if not cp:
4104 if not cp:
4082 continue
4105 continue
4083 try:
4106 try:
4084 filenodes.append(cp.filenode(file_))
4107 filenodes.append(cp.filenode(file_))
4085 except error.LookupError:
4108 except error.LookupError:
4086 pass
4109 pass
4087 if not filenodes:
4110 if not filenodes:
4088 raise util.Abort(_("'%s' not found in manifest!") % file_)
4111 raise util.Abort(_("'%s' not found in manifest!") % file_)
4089 fl = repo.file(file_)
4112 fl = repo.file(file_)
4090 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
4113 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
4091 else:
4114 else:
4092 p = [cp.node() for cp in ctx.parents()]
4115 p = [cp.node() for cp in ctx.parents()]
4093
4116
4094 displayer = cmdutil.show_changeset(ui, repo, opts)
4117 displayer = cmdutil.show_changeset(ui, repo, opts)
4095 for n in p:
4118 for n in p:
4096 if n != nullid:
4119 if n != nullid:
4097 displayer.show(repo[n])
4120 displayer.show(repo[n])
4098 displayer.close()
4121 displayer.close()
4099
4122
4100 @command('paths', [], _('[NAME]'))
4123 @command('paths', [], _('[NAME]'))
4101 def paths(ui, repo, search=None):
4124 def paths(ui, repo, search=None):
4102 """show aliases for remote repositories
4125 """show aliases for remote repositories
4103
4126
4104 Show definition of symbolic path name NAME. If no name is given,
4127 Show definition of symbolic path name NAME. If no name is given,
4105 show definition of all available names.
4128 show definition of all available names.
4106
4129
4107 Option -q/--quiet suppresses all output when searching for NAME
4130 Option -q/--quiet suppresses all output when searching for NAME
4108 and shows only the path names when listing all definitions.
4131 and shows only the path names when listing all definitions.
4109
4132
4110 Path names are defined in the [paths] section of your
4133 Path names are defined in the [paths] section of your
4111 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4134 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4112 repository, ``.hg/hgrc`` is used, too.
4135 repository, ``.hg/hgrc`` is used, too.
4113
4136
4114 The path names ``default`` and ``default-push`` have a special
4137 The path names ``default`` and ``default-push`` have a special
4115 meaning. When performing a push or pull operation, they are used
4138 meaning. When performing a push or pull operation, they are used
4116 as fallbacks if no location is specified on the command-line.
4139 as fallbacks if no location is specified on the command-line.
4117 When ``default-push`` is set, it will be used for push and
4140 When ``default-push`` is set, it will be used for push and
4118 ``default`` will be used for pull; otherwise ``default`` is used
4141 ``default`` will be used for pull; otherwise ``default`` is used
4119 as the fallback for both. When cloning a repository, the clone
4142 as the fallback for both. When cloning a repository, the clone
4120 source is written as ``default`` in ``.hg/hgrc``. Note that
4143 source is written as ``default`` in ``.hg/hgrc``. Note that
4121 ``default`` and ``default-push`` apply to all inbound (e.g.
4144 ``default`` and ``default-push`` apply to all inbound (e.g.
4122 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4145 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4123 :hg:`bundle`) operations.
4146 :hg:`bundle`) operations.
4124
4147
4125 See :hg:`help urls` for more information.
4148 See :hg:`help urls` for more information.
4126
4149
4127 Returns 0 on success.
4150 Returns 0 on success.
4128 """
4151 """
4129 if search:
4152 if search:
4130 for name, path in ui.configitems("paths"):
4153 for name, path in ui.configitems("paths"):
4131 if name == search:
4154 if name == search:
4132 ui.status("%s\n" % util.hidepassword(path))
4155 ui.status("%s\n" % util.hidepassword(path))
4133 return
4156 return
4134 if not ui.quiet:
4157 if not ui.quiet:
4135 ui.warn(_("not found!\n"))
4158 ui.warn(_("not found!\n"))
4136 return 1
4159 return 1
4137 else:
4160 else:
4138 for name, path in ui.configitems("paths"):
4161 for name, path in ui.configitems("paths"):
4139 if ui.quiet:
4162 if ui.quiet:
4140 ui.write("%s\n" % name)
4163 ui.write("%s\n" % name)
4141 else:
4164 else:
4142 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4165 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4143
4166
4144 def postincoming(ui, repo, modheads, optupdate, checkout):
4167 def postincoming(ui, repo, modheads, optupdate, checkout):
4145 if modheads == 0:
4168 if modheads == 0:
4146 return
4169 return
4147 if optupdate:
4170 if optupdate:
4148 try:
4171 try:
4149 return hg.update(repo, checkout)
4172 return hg.update(repo, checkout)
4150 except util.Abort, inst:
4173 except util.Abort, inst:
4151 ui.warn(_("not updating: %s\n" % str(inst)))
4174 ui.warn(_("not updating: %s\n" % str(inst)))
4152 return 0
4175 return 0
4153 if modheads > 1:
4176 if modheads > 1:
4154 currentbranchheads = len(repo.branchheads())
4177 currentbranchheads = len(repo.branchheads())
4155 if currentbranchheads == modheads:
4178 if currentbranchheads == modheads:
4156 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4179 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4157 elif currentbranchheads > 1:
4180 elif currentbranchheads > 1:
4158 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to merge)\n"))
4181 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to merge)\n"))
4159 else:
4182 else:
4160 ui.status(_("(run 'hg heads' to see heads)\n"))
4183 ui.status(_("(run 'hg heads' to see heads)\n"))
4161 else:
4184 else:
4162 ui.status(_("(run 'hg update' to get a working copy)\n"))
4185 ui.status(_("(run 'hg update' to get a working copy)\n"))
4163
4186
4164 @command('^pull',
4187 @command('^pull',
4165 [('u', 'update', None,
4188 [('u', 'update', None,
4166 _('update to new branch head if changesets were pulled')),
4189 _('update to new branch head if changesets were pulled')),
4167 ('f', 'force', None, _('run even when remote repository is unrelated')),
4190 ('f', 'force', None, _('run even when remote repository is unrelated')),
4168 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4191 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4169 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4192 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4170 ('b', 'branch', [], _('a specific branch you would like to pull'),
4193 ('b', 'branch', [], _('a specific branch you would like to pull'),
4171 _('BRANCH')),
4194 _('BRANCH')),
4172 ] + remoteopts,
4195 ] + remoteopts,
4173 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4196 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4174 def pull(ui, repo, source="default", **opts):
4197 def pull(ui, repo, source="default", **opts):
4175 """pull changes from the specified source
4198 """pull changes from the specified source
4176
4199
4177 Pull changes from a remote repository to a local one.
4200 Pull changes from a remote repository to a local one.
4178
4201
4179 This finds all changes from the repository at the specified path
4202 This finds all changes from the repository at the specified path
4180 or URL and adds them to a local repository (the current one unless
4203 or URL and adds them to a local repository (the current one unless
4181 -R is specified). By default, this does not update the copy of the
4204 -R is specified). By default, this does not update the copy of the
4182 project in the working directory.
4205 project in the working directory.
4183
4206
4184 Use :hg:`incoming` if you want to see what would have been added
4207 Use :hg:`incoming` if you want to see what would have been added
4185 by a pull at the time you issued this command. If you then decide
4208 by a pull at the time you issued this command. If you then decide
4186 to add those changes to the repository, you should use :hg:`pull
4209 to add those changes to the repository, you should use :hg:`pull
4187 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4210 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4188
4211
4189 If SOURCE is omitted, the 'default' path will be used.
4212 If SOURCE is omitted, the 'default' path will be used.
4190 See :hg:`help urls` for more information.
4213 See :hg:`help urls` for more information.
4191
4214
4192 Returns 0 on success, 1 if an update had unresolved files.
4215 Returns 0 on success, 1 if an update had unresolved files.
4193 """
4216 """
4194 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4217 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4195 other = hg.peer(repo, opts, source)
4218 other = hg.peer(repo, opts, source)
4196 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4219 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4197 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4220 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4198
4221
4199 if opts.get('bookmark'):
4222 if opts.get('bookmark'):
4200 if not revs:
4223 if not revs:
4201 revs = []
4224 revs = []
4202 rb = other.listkeys('bookmarks')
4225 rb = other.listkeys('bookmarks')
4203 for b in opts['bookmark']:
4226 for b in opts['bookmark']:
4204 if b not in rb:
4227 if b not in rb:
4205 raise util.Abort(_('remote bookmark %s not found!') % b)
4228 raise util.Abort(_('remote bookmark %s not found!') % b)
4206 revs.append(rb[b])
4229 revs.append(rb[b])
4207
4230
4208 if revs:
4231 if revs:
4209 try:
4232 try:
4210 revs = [other.lookup(rev) for rev in revs]
4233 revs = [other.lookup(rev) for rev in revs]
4211 except error.CapabilityError:
4234 except error.CapabilityError:
4212 err = _("other repository doesn't support revision lookup, "
4235 err = _("other repository doesn't support revision lookup, "
4213 "so a rev cannot be specified.")
4236 "so a rev cannot be specified.")
4214 raise util.Abort(err)
4237 raise util.Abort(err)
4215
4238
4216 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4239 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4217 bookmarks.updatefromremote(ui, repo, other)
4240 bookmarks.updatefromremote(ui, repo, other)
4218 if checkout:
4241 if checkout:
4219 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4242 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4220 repo._subtoppath = source
4243 repo._subtoppath = source
4221 try:
4244 try:
4222 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4245 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4223
4246
4224 finally:
4247 finally:
4225 del repo._subtoppath
4248 del repo._subtoppath
4226
4249
4227 # update specified bookmarks
4250 # update specified bookmarks
4228 if opts.get('bookmark'):
4251 if opts.get('bookmark'):
4229 for b in opts['bookmark']:
4252 for b in opts['bookmark']:
4230 # explicit pull overrides local bookmark if any
4253 # explicit pull overrides local bookmark if any
4231 ui.status(_("importing bookmark %s\n") % b)
4254 ui.status(_("importing bookmark %s\n") % b)
4232 repo._bookmarks[b] = repo[rb[b]].node()
4255 repo._bookmarks[b] = repo[rb[b]].node()
4233 bookmarks.write(repo)
4256 bookmarks.write(repo)
4234
4257
4235 return ret
4258 return ret
4236
4259
4237 @command('^push',
4260 @command('^push',
4238 [('f', 'force', None, _('force push')),
4261 [('f', 'force', None, _('force push')),
4239 ('r', 'rev', [],
4262 ('r', 'rev', [],
4240 _('a changeset intended to be included in the destination'),
4263 _('a changeset intended to be included in the destination'),
4241 _('REV')),
4264 _('REV')),
4242 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4265 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4243 ('b', 'branch', [],
4266 ('b', 'branch', [],
4244 _('a specific branch you would like to push'), _('BRANCH')),
4267 _('a specific branch you would like to push'), _('BRANCH')),
4245 ('', 'new-branch', False, _('allow pushing a new branch')),
4268 ('', 'new-branch', False, _('allow pushing a new branch')),
4246 ] + remoteopts,
4269 ] + remoteopts,
4247 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4270 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4248 def push(ui, repo, dest=None, **opts):
4271 def push(ui, repo, dest=None, **opts):
4249 """push changes to the specified destination
4272 """push changes to the specified destination
4250
4273
4251 Push changesets from the local repository to the specified
4274 Push changesets from the local repository to the specified
4252 destination.
4275 destination.
4253
4276
4254 This operation is symmetrical to pull: it is identical to a pull
4277 This operation is symmetrical to pull: it is identical to a pull
4255 in the destination repository from the current one.
4278 in the destination repository from the current one.
4256
4279
4257 By default, push will not allow creation of new heads at the
4280 By default, push will not allow creation of new heads at the
4258 destination, since multiple heads would make it unclear which head
4281 destination, since multiple heads would make it unclear which head
4259 to use. In this situation, it is recommended to pull and merge
4282 to use. In this situation, it is recommended to pull and merge
4260 before pushing.
4283 before pushing.
4261
4284
4262 Use --new-branch if you want to allow push to create a new named
4285 Use --new-branch if you want to allow push to create a new named
4263 branch that is not present at the destination. This allows you to
4286 branch that is not present at the destination. This allows you to
4264 only create a new branch without forcing other changes.
4287 only create a new branch without forcing other changes.
4265
4288
4266 Use -f/--force to override the default behavior and push all
4289 Use -f/--force to override the default behavior and push all
4267 changesets on all branches.
4290 changesets on all branches.
4268
4291
4269 If -r/--rev is used, the specified revision and all its ancestors
4292 If -r/--rev is used, the specified revision and all its ancestors
4270 will be pushed to the remote repository.
4293 will be pushed to the remote repository.
4271
4294
4272 Please see :hg:`help urls` for important details about ``ssh://``
4295 Please see :hg:`help urls` for important details about ``ssh://``
4273 URLs. If DESTINATION is omitted, a default path will be used.
4296 URLs. If DESTINATION is omitted, a default path will be used.
4274
4297
4275 Returns 0 if push was successful, 1 if nothing to push.
4298 Returns 0 if push was successful, 1 if nothing to push.
4276 """
4299 """
4277
4300
4278 if opts.get('bookmark'):
4301 if opts.get('bookmark'):
4279 for b in opts['bookmark']:
4302 for b in opts['bookmark']:
4280 # translate -B options to -r so changesets get pushed
4303 # translate -B options to -r so changesets get pushed
4281 if b in repo._bookmarks:
4304 if b in repo._bookmarks:
4282 opts.setdefault('rev', []).append(b)
4305 opts.setdefault('rev', []).append(b)
4283 else:
4306 else:
4284 # if we try to push a deleted bookmark, translate it to null
4307 # if we try to push a deleted bookmark, translate it to null
4285 # this lets simultaneous -r, -b options continue working
4308 # this lets simultaneous -r, -b options continue working
4286 opts.setdefault('rev', []).append("null")
4309 opts.setdefault('rev', []).append("null")
4287
4310
4288 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4311 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4289 dest, branches = hg.parseurl(dest, opts.get('branch'))
4312 dest, branches = hg.parseurl(dest, opts.get('branch'))
4290 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4313 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4291 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4314 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4292 other = hg.peer(repo, opts, dest)
4315 other = hg.peer(repo, opts, dest)
4293 if revs:
4316 if revs:
4294 revs = [repo.lookup(rev) for rev in revs]
4317 revs = [repo.lookup(rev) for rev in revs]
4295
4318
4296 repo._subtoppath = dest
4319 repo._subtoppath = dest
4297 try:
4320 try:
4298 # push subrepos depth-first for coherent ordering
4321 # push subrepos depth-first for coherent ordering
4299 c = repo['']
4322 c = repo['']
4300 subs = c.substate # only repos that are committed
4323 subs = c.substate # only repos that are committed
4301 for s in sorted(subs):
4324 for s in sorted(subs):
4302 if not c.sub(s).push(opts.get('force')):
4325 if not c.sub(s).push(opts.get('force')):
4303 return False
4326 return False
4304 finally:
4327 finally:
4305 del repo._subtoppath
4328 del repo._subtoppath
4306 result = repo.push(other, opts.get('force'), revs=revs,
4329 result = repo.push(other, opts.get('force'), revs=revs,
4307 newbranch=opts.get('new_branch'))
4330 newbranch=opts.get('new_branch'))
4308
4331
4309 result = (result == 0)
4332 result = (result == 0)
4310
4333
4311 if opts.get('bookmark'):
4334 if opts.get('bookmark'):
4312 rb = other.listkeys('bookmarks')
4335 rb = other.listkeys('bookmarks')
4313 for b in opts['bookmark']:
4336 for b in opts['bookmark']:
4314 # explicit push overrides remote bookmark if any
4337 # explicit push overrides remote bookmark if any
4315 if b in repo._bookmarks:
4338 if b in repo._bookmarks:
4316 ui.status(_("exporting bookmark %s\n") % b)
4339 ui.status(_("exporting bookmark %s\n") % b)
4317 new = repo[b].hex()
4340 new = repo[b].hex()
4318 elif b in rb:
4341 elif b in rb:
4319 ui.status(_("deleting remote bookmark %s\n") % b)
4342 ui.status(_("deleting remote bookmark %s\n") % b)
4320 new = '' # delete
4343 new = '' # delete
4321 else:
4344 else:
4322 ui.warn(_('bookmark %s does not exist on the local '
4345 ui.warn(_('bookmark %s does not exist on the local '
4323 'or remote repository!\n') % b)
4346 'or remote repository!\n') % b)
4324 return 2
4347 return 2
4325 old = rb.get(b, '')
4348 old = rb.get(b, '')
4326 r = other.pushkey('bookmarks', b, old, new)
4349 r = other.pushkey('bookmarks', b, old, new)
4327 if not r:
4350 if not r:
4328 ui.warn(_('updating bookmark %s failed!\n') % b)
4351 ui.warn(_('updating bookmark %s failed!\n') % b)
4329 if not result:
4352 if not result:
4330 result = 2
4353 result = 2
4331
4354
4332 return result
4355 return result
4333
4356
4334 @command('recover', [])
4357 @command('recover', [])
4335 def recover(ui, repo):
4358 def recover(ui, repo):
4336 """roll back an interrupted transaction
4359 """roll back an interrupted transaction
4337
4360
4338 Recover from an interrupted commit or pull.
4361 Recover from an interrupted commit or pull.
4339
4362
4340 This command tries to fix the repository status after an
4363 This command tries to fix the repository status after an
4341 interrupted operation. It should only be necessary when Mercurial
4364 interrupted operation. It should only be necessary when Mercurial
4342 suggests it.
4365 suggests it.
4343
4366
4344 Returns 0 if successful, 1 if nothing to recover or verify fails.
4367 Returns 0 if successful, 1 if nothing to recover or verify fails.
4345 """
4368 """
4346 if repo.recover():
4369 if repo.recover():
4347 return hg.verify(repo)
4370 return hg.verify(repo)
4348 return 1
4371 return 1
4349
4372
4350 @command('^remove|rm',
4373 @command('^remove|rm',
4351 [('A', 'after', None, _('record delete for missing files')),
4374 [('A', 'after', None, _('record delete for missing files')),
4352 ('f', 'force', None,
4375 ('f', 'force', None,
4353 _('remove (and delete) file even if added or modified')),
4376 _('remove (and delete) file even if added or modified')),
4354 ] + walkopts,
4377 ] + walkopts,
4355 _('[OPTION]... FILE...'))
4378 _('[OPTION]... FILE...'))
4356 def remove(ui, repo, *pats, **opts):
4379 def remove(ui, repo, *pats, **opts):
4357 """remove the specified files on the next commit
4380 """remove the specified files on the next commit
4358
4381
4359 Schedule the indicated files for removal from the current branch.
4382 Schedule the indicated files for removal from the current branch.
4360
4383
4361 This command schedules the files to be removed at the next commit.
4384 This command schedules the files to be removed at the next commit.
4362 To undo a remove before that, see :hg:`revert`. To undo added
4385 To undo a remove before that, see :hg:`revert`. To undo added
4363 files, see :hg:`forget`.
4386 files, see :hg:`forget`.
4364
4387
4365 .. container:: verbose
4388 .. container:: verbose
4366
4389
4367 -A/--after can be used to remove only files that have already
4390 -A/--after can be used to remove only files that have already
4368 been deleted, -f/--force can be used to force deletion, and -Af
4391 been deleted, -f/--force can be used to force deletion, and -Af
4369 can be used to remove files from the next revision without
4392 can be used to remove files from the next revision without
4370 deleting them from the working directory.
4393 deleting them from the working directory.
4371
4394
4372 The following table details the behavior of remove for different
4395 The following table details the behavior of remove for different
4373 file states (columns) and option combinations (rows). The file
4396 file states (columns) and option combinations (rows). The file
4374 states are Added [A], Clean [C], Modified [M] and Missing [!]
4397 states are Added [A], Clean [C], Modified [M] and Missing [!]
4375 (as reported by :hg:`status`). The actions are Warn, Remove
4398 (as reported by :hg:`status`). The actions are Warn, Remove
4376 (from branch) and Delete (from disk):
4399 (from branch) and Delete (from disk):
4377
4400
4378 ======= == == == ==
4401 ======= == == == ==
4379 A C M !
4402 A C M !
4380 ======= == == == ==
4403 ======= == == == ==
4381 none W RD W R
4404 none W RD W R
4382 -f R RD RD R
4405 -f R RD RD R
4383 -A W W W R
4406 -A W W W R
4384 -Af R R R R
4407 -Af R R R R
4385 ======= == == == ==
4408 ======= == == == ==
4386
4409
4387 Note that remove never deletes files in Added [A] state from the
4410 Note that remove never deletes files in Added [A] state from the
4388 working directory, not even if option --force is specified.
4411 working directory, not even if option --force is specified.
4389
4412
4390 Returns 0 on success, 1 if any warnings encountered.
4413 Returns 0 on success, 1 if any warnings encountered.
4391 """
4414 """
4392
4415
4393 ret = 0
4416 ret = 0
4394 after, force = opts.get('after'), opts.get('force')
4417 after, force = opts.get('after'), opts.get('force')
4395 if not pats and not after:
4418 if not pats and not after:
4396 raise util.Abort(_('no files specified'))
4419 raise util.Abort(_('no files specified'))
4397
4420
4398 m = scmutil.match(repo[None], pats, opts)
4421 m = scmutil.match(repo[None], pats, opts)
4399 s = repo.status(match=m, clean=True)
4422 s = repo.status(match=m, clean=True)
4400 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4423 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4401
4424
4402 for f in m.files():
4425 for f in m.files():
4403 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
4426 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
4404 if os.path.exists(m.rel(f)):
4427 if os.path.exists(m.rel(f)):
4405 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4428 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4406 ret = 1
4429 ret = 1
4407
4430
4408 if force:
4431 if force:
4409 list = modified + deleted + clean + added
4432 list = modified + deleted + clean + added
4410 elif after:
4433 elif after:
4411 list = deleted
4434 list = deleted
4412 for f in modified + added + clean:
4435 for f in modified + added + clean:
4413 ui.warn(_('not removing %s: file still exists (use -f'
4436 ui.warn(_('not removing %s: file still exists (use -f'
4414 ' to force removal)\n') % m.rel(f))
4437 ' to force removal)\n') % m.rel(f))
4415 ret = 1
4438 ret = 1
4416 else:
4439 else:
4417 list = deleted + clean
4440 list = deleted + clean
4418 for f in modified:
4441 for f in modified:
4419 ui.warn(_('not removing %s: file is modified (use -f'
4442 ui.warn(_('not removing %s: file is modified (use -f'
4420 ' to force removal)\n') % m.rel(f))
4443 ' to force removal)\n') % m.rel(f))
4421 ret = 1
4444 ret = 1
4422 for f in added:
4445 for f in added:
4423 ui.warn(_('not removing %s: file has been marked for add'
4446 ui.warn(_('not removing %s: file has been marked for add'
4424 ' (use forget to undo)\n') % m.rel(f))
4447 ' (use forget to undo)\n') % m.rel(f))
4425 ret = 1
4448 ret = 1
4426
4449
4427 for f in sorted(list):
4450 for f in sorted(list):
4428 if ui.verbose or not m.exact(f):
4451 if ui.verbose or not m.exact(f):
4429 ui.status(_('removing %s\n') % m.rel(f))
4452 ui.status(_('removing %s\n') % m.rel(f))
4430
4453
4431 wlock = repo.wlock()
4454 wlock = repo.wlock()
4432 try:
4455 try:
4433 if not after:
4456 if not after:
4434 for f in list:
4457 for f in list:
4435 if f in added:
4458 if f in added:
4436 continue # we never unlink added files on remove
4459 continue # we never unlink added files on remove
4437 try:
4460 try:
4438 util.unlinkpath(repo.wjoin(f))
4461 util.unlinkpath(repo.wjoin(f))
4439 except OSError, inst:
4462 except OSError, inst:
4440 if inst.errno != errno.ENOENT:
4463 if inst.errno != errno.ENOENT:
4441 raise
4464 raise
4442 repo[None].forget(list)
4465 repo[None].forget(list)
4443 finally:
4466 finally:
4444 wlock.release()
4467 wlock.release()
4445
4468
4446 return ret
4469 return ret
4447
4470
4448 @command('rename|move|mv',
4471 @command('rename|move|mv',
4449 [('A', 'after', None, _('record a rename that has already occurred')),
4472 [('A', 'after', None, _('record a rename that has already occurred')),
4450 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4473 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4451 ] + walkopts + dryrunopts,
4474 ] + walkopts + dryrunopts,
4452 _('[OPTION]... SOURCE... DEST'))
4475 _('[OPTION]... SOURCE... DEST'))
4453 def rename(ui, repo, *pats, **opts):
4476 def rename(ui, repo, *pats, **opts):
4454 """rename files; equivalent of copy + remove
4477 """rename files; equivalent of copy + remove
4455
4478
4456 Mark dest as copies of sources; mark sources for deletion. If dest
4479 Mark dest as copies of sources; mark sources for deletion. If dest
4457 is a directory, copies are put in that directory. If dest is a
4480 is a directory, copies are put in that directory. If dest is a
4458 file, there can only be one source.
4481 file, there can only be one source.
4459
4482
4460 By default, this command copies the contents of files as they
4483 By default, this command copies the contents of files as they
4461 exist in the working directory. If invoked with -A/--after, the
4484 exist in the working directory. If invoked with -A/--after, the
4462 operation is recorded, but no copying is performed.
4485 operation is recorded, but no copying is performed.
4463
4486
4464 This command takes effect at the next commit. To undo a rename
4487 This command takes effect at the next commit. To undo a rename
4465 before that, see :hg:`revert`.
4488 before that, see :hg:`revert`.
4466
4489
4467 Returns 0 on success, 1 if errors are encountered.
4490 Returns 0 on success, 1 if errors are encountered.
4468 """
4491 """
4469 wlock = repo.wlock(False)
4492 wlock = repo.wlock(False)
4470 try:
4493 try:
4471 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4494 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4472 finally:
4495 finally:
4473 wlock.release()
4496 wlock.release()
4474
4497
4475 @command('resolve',
4498 @command('resolve',
4476 [('a', 'all', None, _('select all unresolved files')),
4499 [('a', 'all', None, _('select all unresolved files')),
4477 ('l', 'list', None, _('list state of files needing merge')),
4500 ('l', 'list', None, _('list state of files needing merge')),
4478 ('m', 'mark', None, _('mark files as resolved')),
4501 ('m', 'mark', None, _('mark files as resolved')),
4479 ('u', 'unmark', None, _('mark files as unresolved')),
4502 ('u', 'unmark', None, _('mark files as unresolved')),
4480 ('n', 'no-status', None, _('hide status prefix'))]
4503 ('n', 'no-status', None, _('hide status prefix'))]
4481 + mergetoolopts + walkopts,
4504 + mergetoolopts + walkopts,
4482 _('[OPTION]... [FILE]...'))
4505 _('[OPTION]... [FILE]...'))
4483 def resolve(ui, repo, *pats, **opts):
4506 def resolve(ui, repo, *pats, **opts):
4484 """redo merges or set/view the merge status of files
4507 """redo merges or set/view the merge status of files
4485
4508
4486 Merges with unresolved conflicts are often the result of
4509 Merges with unresolved conflicts are often the result of
4487 non-interactive merging using the ``internal:merge`` configuration
4510 non-interactive merging using the ``internal:merge`` configuration
4488 setting, or a command-line merge tool like ``diff3``. The resolve
4511 setting, or a command-line merge tool like ``diff3``. The resolve
4489 command is used to manage the files involved in a merge, after
4512 command is used to manage the files involved in a merge, after
4490 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4513 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4491 working directory must have two parents).
4514 working directory must have two parents).
4492
4515
4493 The resolve command can be used in the following ways:
4516 The resolve command can be used in the following ways:
4494
4517
4495 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4518 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4496 files, discarding any previous merge attempts. Re-merging is not
4519 files, discarding any previous merge attempts. Re-merging is not
4497 performed for files already marked as resolved. Use ``--all/-a``
4520 performed for files already marked as resolved. Use ``--all/-a``
4498 to select all unresolved files. ``--tool`` can be used to specify
4521 to select all unresolved files. ``--tool`` can be used to specify
4499 the merge tool used for the given files. It overrides the HGMERGE
4522 the merge tool used for the given files. It overrides the HGMERGE
4500 environment variable and your configuration files. Previous file
4523 environment variable and your configuration files. Previous file
4501 contents are saved with a ``.orig`` suffix.
4524 contents are saved with a ``.orig`` suffix.
4502
4525
4503 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4526 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4504 (e.g. after having manually fixed-up the files). The default is
4527 (e.g. after having manually fixed-up the files). The default is
4505 to mark all unresolved files.
4528 to mark all unresolved files.
4506
4529
4507 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4530 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4508 default is to mark all resolved files.
4531 default is to mark all resolved files.
4509
4532
4510 - :hg:`resolve -l`: list files which had or still have conflicts.
4533 - :hg:`resolve -l`: list files which had or still have conflicts.
4511 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4534 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4512
4535
4513 Note that Mercurial will not let you commit files with unresolved
4536 Note that Mercurial will not let you commit files with unresolved
4514 merge conflicts. You must use :hg:`resolve -m ...` before you can
4537 merge conflicts. You must use :hg:`resolve -m ...` before you can
4515 commit after a conflicting merge.
4538 commit after a conflicting merge.
4516
4539
4517 Returns 0 on success, 1 if any files fail a resolve attempt.
4540 Returns 0 on success, 1 if any files fail a resolve attempt.
4518 """
4541 """
4519
4542
4520 all, mark, unmark, show, nostatus = \
4543 all, mark, unmark, show, nostatus = \
4521 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4544 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4522
4545
4523 if (show and (mark or unmark)) or (mark and unmark):
4546 if (show and (mark or unmark)) or (mark and unmark):
4524 raise util.Abort(_("too many options specified"))
4547 raise util.Abort(_("too many options specified"))
4525 if pats and all:
4548 if pats and all:
4526 raise util.Abort(_("can't specify --all and patterns"))
4549 raise util.Abort(_("can't specify --all and patterns"))
4527 if not (all or pats or show or mark or unmark):
4550 if not (all or pats or show or mark or unmark):
4528 raise util.Abort(_('no files or directories specified; '
4551 raise util.Abort(_('no files or directories specified; '
4529 'use --all to remerge all files'))
4552 'use --all to remerge all files'))
4530
4553
4531 ms = mergemod.mergestate(repo)
4554 ms = mergemod.mergestate(repo)
4532 m = scmutil.match(repo[None], pats, opts)
4555 m = scmutil.match(repo[None], pats, opts)
4533 ret = 0
4556 ret = 0
4534
4557
4535 for f in ms:
4558 for f in ms:
4536 if m(f):
4559 if m(f):
4537 if show:
4560 if show:
4538 if nostatus:
4561 if nostatus:
4539 ui.write("%s\n" % f)
4562 ui.write("%s\n" % f)
4540 else:
4563 else:
4541 ui.write("%s %s\n" % (ms[f].upper(), f),
4564 ui.write("%s %s\n" % (ms[f].upper(), f),
4542 label='resolve.' +
4565 label='resolve.' +
4543 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4566 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4544 elif mark:
4567 elif mark:
4545 ms.mark(f, "r")
4568 ms.mark(f, "r")
4546 elif unmark:
4569 elif unmark:
4547 ms.mark(f, "u")
4570 ms.mark(f, "u")
4548 else:
4571 else:
4549 wctx = repo[None]
4572 wctx = repo[None]
4550 mctx = wctx.parents()[-1]
4573 mctx = wctx.parents()[-1]
4551
4574
4552 # backup pre-resolve (merge uses .orig for its own purposes)
4575 # backup pre-resolve (merge uses .orig for its own purposes)
4553 a = repo.wjoin(f)
4576 a = repo.wjoin(f)
4554 util.copyfile(a, a + ".resolve")
4577 util.copyfile(a, a + ".resolve")
4555
4578
4556 try:
4579 try:
4557 # resolve file
4580 # resolve file
4558 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4581 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4559 if ms.resolve(f, wctx, mctx):
4582 if ms.resolve(f, wctx, mctx):
4560 ret = 1
4583 ret = 1
4561 finally:
4584 finally:
4562 ui.setconfig('ui', 'forcemerge', '')
4585 ui.setconfig('ui', 'forcemerge', '')
4563
4586
4564 # replace filemerge's .orig file with our resolve file
4587 # replace filemerge's .orig file with our resolve file
4565 util.rename(a + ".resolve", a + ".orig")
4588 util.rename(a + ".resolve", a + ".orig")
4566
4589
4567 ms.commit()
4590 ms.commit()
4568 return ret
4591 return ret
4569
4592
4570 @command('revert',
4593 @command('revert',
4571 [('a', 'all', None, _('revert all changes when no arguments given')),
4594 [('a', 'all', None, _('revert all changes when no arguments given')),
4572 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4595 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4573 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4596 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4574 ('C', 'no-backup', None, _('do not save backup copies of files')),
4597 ('C', 'no-backup', None, _('do not save backup copies of files')),
4575 ] + walkopts + dryrunopts,
4598 ] + walkopts + dryrunopts,
4576 _('[OPTION]... [-r REV] [NAME]...'))
4599 _('[OPTION]... [-r REV] [NAME]...'))
4577 def revert(ui, repo, *pats, **opts):
4600 def revert(ui, repo, *pats, **opts):
4578 """restore files to their checkout state
4601 """restore files to their checkout state
4579
4602
4580 .. note::
4603 .. note::
4581 To check out earlier revisions, you should use :hg:`update REV`.
4604 To check out earlier revisions, you should use :hg:`update REV`.
4582 To cancel a merge (and lose your changes), use :hg:`update --clean .`.
4605 To cancel a merge (and lose your changes), use :hg:`update --clean .`.
4583
4606
4584 With no revision specified, revert the specified files or directories
4607 With no revision specified, revert the specified files or directories
4585 to the contents they had in the parent of the working directory.
4608 to the contents they had in the parent of the working directory.
4586 This restores the contents of files to an unmodified
4609 This restores the contents of files to an unmodified
4587 state and unschedules adds, removes, copies, and renames. If the
4610 state and unschedules adds, removes, copies, and renames. If the
4588 working directory has two parents, you must explicitly specify a
4611 working directory has two parents, you must explicitly specify a
4589 revision.
4612 revision.
4590
4613
4591 Using the -r/--rev or -d/--date options, revert the given files or
4614 Using the -r/--rev or -d/--date options, revert the given files or
4592 directories to their states as of a specific revision. Because
4615 directories to their states as of a specific revision. Because
4593 revert does not change the working directory parents, this will
4616 revert does not change the working directory parents, this will
4594 cause these files to appear modified. This can be helpful to "back
4617 cause these files to appear modified. This can be helpful to "back
4595 out" some or all of an earlier change. See :hg:`backout` for a
4618 out" some or all of an earlier change. See :hg:`backout` for a
4596 related method.
4619 related method.
4597
4620
4598 Modified files are saved with a .orig suffix before reverting.
4621 Modified files are saved with a .orig suffix before reverting.
4599 To disable these backups, use --no-backup.
4622 To disable these backups, use --no-backup.
4600
4623
4601 See :hg:`help dates` for a list of formats valid for -d/--date.
4624 See :hg:`help dates` for a list of formats valid for -d/--date.
4602
4625
4603 Returns 0 on success.
4626 Returns 0 on success.
4604 """
4627 """
4605
4628
4606 if opts.get("date"):
4629 if opts.get("date"):
4607 if opts.get("rev"):
4630 if opts.get("rev"):
4608 raise util.Abort(_("you can't specify a revision and a date"))
4631 raise util.Abort(_("you can't specify a revision and a date"))
4609 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4632 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4610
4633
4611 parent, p2 = repo.dirstate.parents()
4634 parent, p2 = repo.dirstate.parents()
4612 if not opts.get('rev') and p2 != nullid:
4635 if not opts.get('rev') and p2 != nullid:
4613 # revert after merge is a trap for new users (issue2915)
4636 # revert after merge is a trap for new users (issue2915)
4614 raise util.Abort(_('uncommitted merge with no revision specified'),
4637 raise util.Abort(_('uncommitted merge with no revision specified'),
4615 hint=_('use "hg update" or see "hg help revert"'))
4638 hint=_('use "hg update" or see "hg help revert"'))
4616
4639
4617 ctx = scmutil.revsingle(repo, opts.get('rev'))
4640 ctx = scmutil.revsingle(repo, opts.get('rev'))
4618 node = ctx.node()
4641 node = ctx.node()
4619
4642
4620 if not pats and not opts.get('all'):
4643 if not pats and not opts.get('all'):
4621 msg = _("no files or directories specified")
4644 msg = _("no files or directories specified")
4622 if p2 != nullid:
4645 if p2 != nullid:
4623 hint = _("uncommitted merge, use --all to discard all changes,"
4646 hint = _("uncommitted merge, use --all to discard all changes,"
4624 " or 'hg update -C .' to abort the merge")
4647 " or 'hg update -C .' to abort the merge")
4625 raise util.Abort(msg, hint=hint)
4648 raise util.Abort(msg, hint=hint)
4626 dirty = util.any(repo.status())
4649 dirty = util.any(repo.status())
4627 if node != parent:
4650 if node != parent:
4628 if dirty:
4651 if dirty:
4629 hint = _("uncommitted changes, use --all to discard all"
4652 hint = _("uncommitted changes, use --all to discard all"
4630 " changes, or 'hg update %s' to update") % ctx.rev()
4653 " changes, or 'hg update %s' to update") % ctx.rev()
4631 else:
4654 else:
4632 hint = _("use --all to revert all files,"
4655 hint = _("use --all to revert all files,"
4633 " or 'hg update %s' to update") % ctx.rev()
4656 " or 'hg update %s' to update") % ctx.rev()
4634 elif dirty:
4657 elif dirty:
4635 hint = _("uncommitted changes, use --all to discard all changes")
4658 hint = _("uncommitted changes, use --all to discard all changes")
4636 else:
4659 else:
4637 hint = _("use --all to revert all files")
4660 hint = _("use --all to revert all files")
4638 raise util.Abort(msg, hint=hint)
4661 raise util.Abort(msg, hint=hint)
4639
4662
4640 mf = ctx.manifest()
4663 mf = ctx.manifest()
4641 if node == parent:
4664 if node == parent:
4642 pmf = mf
4665 pmf = mf
4643 else:
4666 else:
4644 pmf = None
4667 pmf = None
4645
4668
4646 # need all matching names in dirstate and manifest of target rev,
4669 # need all matching names in dirstate and manifest of target rev,
4647 # so have to walk both. do not print errors if files exist in one
4670 # so have to walk both. do not print errors if files exist in one
4648 # but not other.
4671 # but not other.
4649
4672
4650 names = {}
4673 names = {}
4651
4674
4652 wlock = repo.wlock()
4675 wlock = repo.wlock()
4653 try:
4676 try:
4654 # walk dirstate.
4677 # walk dirstate.
4655
4678
4656 m = scmutil.match(repo[None], pats, opts)
4679 m = scmutil.match(repo[None], pats, opts)
4657 m.bad = lambda x, y: False
4680 m.bad = lambda x, y: False
4658 for abs in repo.walk(m):
4681 for abs in repo.walk(m):
4659 names[abs] = m.rel(abs), m.exact(abs)
4682 names[abs] = m.rel(abs), m.exact(abs)
4660
4683
4661 # walk target manifest.
4684 # walk target manifest.
4662
4685
4663 def badfn(path, msg):
4686 def badfn(path, msg):
4664 if path in names:
4687 if path in names:
4665 return
4688 return
4666 if path in repo[node].substate:
4689 if path in repo[node].substate:
4667 ui.warn("%s: %s\n" % (m.rel(path),
4690 ui.warn("%s: %s\n" % (m.rel(path),
4668 'reverting subrepos is unsupported'))
4691 'reverting subrepos is unsupported'))
4669 return
4692 return
4670 path_ = path + '/'
4693 path_ = path + '/'
4671 for f in names:
4694 for f in names:
4672 if f.startswith(path_):
4695 if f.startswith(path_):
4673 return
4696 return
4674 ui.warn("%s: %s\n" % (m.rel(path), msg))
4697 ui.warn("%s: %s\n" % (m.rel(path), msg))
4675
4698
4676 m = scmutil.match(repo[node], pats, opts)
4699 m = scmutil.match(repo[node], pats, opts)
4677 m.bad = badfn
4700 m.bad = badfn
4678 for abs in repo[node].walk(m):
4701 for abs in repo[node].walk(m):
4679 if abs not in names:
4702 if abs not in names:
4680 names[abs] = m.rel(abs), m.exact(abs)
4703 names[abs] = m.rel(abs), m.exact(abs)
4681
4704
4682 m = scmutil.matchfiles(repo, names)
4705 m = scmutil.matchfiles(repo, names)
4683 changes = repo.status(match=m)[:4]
4706 changes = repo.status(match=m)[:4]
4684 modified, added, removed, deleted = map(set, changes)
4707 modified, added, removed, deleted = map(set, changes)
4685
4708
4686 # if f is a rename, also revert the source
4709 # if f is a rename, also revert the source
4687 cwd = repo.getcwd()
4710 cwd = repo.getcwd()
4688 for f in added:
4711 for f in added:
4689 src = repo.dirstate.copied(f)
4712 src = repo.dirstate.copied(f)
4690 if src and src not in names and repo.dirstate[src] == 'r':
4713 if src and src not in names and repo.dirstate[src] == 'r':
4691 removed.add(src)
4714 removed.add(src)
4692 names[src] = (repo.pathto(src, cwd), True)
4715 names[src] = (repo.pathto(src, cwd), True)
4693
4716
4694 def removeforget(abs):
4717 def removeforget(abs):
4695 if repo.dirstate[abs] == 'a':
4718 if repo.dirstate[abs] == 'a':
4696 return _('forgetting %s\n')
4719 return _('forgetting %s\n')
4697 return _('removing %s\n')
4720 return _('removing %s\n')
4698
4721
4699 revert = ([], _('reverting %s\n'))
4722 revert = ([], _('reverting %s\n'))
4700 add = ([], _('adding %s\n'))
4723 add = ([], _('adding %s\n'))
4701 remove = ([], removeforget)
4724 remove = ([], removeforget)
4702 undelete = ([], _('undeleting %s\n'))
4725 undelete = ([], _('undeleting %s\n'))
4703
4726
4704 disptable = (
4727 disptable = (
4705 # dispatch table:
4728 # dispatch table:
4706 # file state
4729 # file state
4707 # action if in target manifest
4730 # action if in target manifest
4708 # action if not in target manifest
4731 # action if not in target manifest
4709 # make backup if in target manifest
4732 # make backup if in target manifest
4710 # make backup if not in target manifest
4733 # make backup if not in target manifest
4711 (modified, revert, remove, True, True),
4734 (modified, revert, remove, True, True),
4712 (added, revert, remove, True, False),
4735 (added, revert, remove, True, False),
4713 (removed, undelete, None, False, False),
4736 (removed, undelete, None, False, False),
4714 (deleted, revert, remove, False, False),
4737 (deleted, revert, remove, False, False),
4715 )
4738 )
4716
4739
4717 for abs, (rel, exact) in sorted(names.items()):
4740 for abs, (rel, exact) in sorted(names.items()):
4718 mfentry = mf.get(abs)
4741 mfentry = mf.get(abs)
4719 target = repo.wjoin(abs)
4742 target = repo.wjoin(abs)
4720 def handle(xlist, dobackup):
4743 def handle(xlist, dobackup):
4721 xlist[0].append(abs)
4744 xlist[0].append(abs)
4722 if (dobackup and not opts.get('no_backup') and
4745 if (dobackup and not opts.get('no_backup') and
4723 os.path.lexists(target)):
4746 os.path.lexists(target)):
4724 bakname = "%s.orig" % rel
4747 bakname = "%s.orig" % rel
4725 ui.note(_('saving current version of %s as %s\n') %
4748 ui.note(_('saving current version of %s as %s\n') %
4726 (rel, bakname))
4749 (rel, bakname))
4727 if not opts.get('dry_run'):
4750 if not opts.get('dry_run'):
4728 util.rename(target, bakname)
4751 util.rename(target, bakname)
4729 if ui.verbose or not exact:
4752 if ui.verbose or not exact:
4730 msg = xlist[1]
4753 msg = xlist[1]
4731 if not isinstance(msg, basestring):
4754 if not isinstance(msg, basestring):
4732 msg = msg(abs)
4755 msg = msg(abs)
4733 ui.status(msg % rel)
4756 ui.status(msg % rel)
4734 for table, hitlist, misslist, backuphit, backupmiss in disptable:
4757 for table, hitlist, misslist, backuphit, backupmiss in disptable:
4735 if abs not in table:
4758 if abs not in table:
4736 continue
4759 continue
4737 # file has changed in dirstate
4760 # file has changed in dirstate
4738 if mfentry:
4761 if mfentry:
4739 handle(hitlist, backuphit)
4762 handle(hitlist, backuphit)
4740 elif misslist is not None:
4763 elif misslist is not None:
4741 handle(misslist, backupmiss)
4764 handle(misslist, backupmiss)
4742 break
4765 break
4743 else:
4766 else:
4744 if abs not in repo.dirstate:
4767 if abs not in repo.dirstate:
4745 if mfentry:
4768 if mfentry:
4746 handle(add, True)
4769 handle(add, True)
4747 elif exact:
4770 elif exact:
4748 ui.warn(_('file not managed: %s\n') % rel)
4771 ui.warn(_('file not managed: %s\n') % rel)
4749 continue
4772 continue
4750 # file has not changed in dirstate
4773 # file has not changed in dirstate
4751 if node == parent:
4774 if node == parent:
4752 if exact:
4775 if exact:
4753 ui.warn(_('no changes needed to %s\n') % rel)
4776 ui.warn(_('no changes needed to %s\n') % rel)
4754 continue
4777 continue
4755 if pmf is None:
4778 if pmf is None:
4756 # only need parent manifest in this unlikely case,
4779 # only need parent manifest in this unlikely case,
4757 # so do not read by default
4780 # so do not read by default
4758 pmf = repo[parent].manifest()
4781 pmf = repo[parent].manifest()
4759 if abs in pmf and mfentry:
4782 if abs in pmf and mfentry:
4760 # if version of file is same in parent and target
4783 # if version of file is same in parent and target
4761 # manifests, do nothing
4784 # manifests, do nothing
4762 if (pmf[abs] != mfentry or
4785 if (pmf[abs] != mfentry or
4763 pmf.flags(abs) != mf.flags(abs)):
4786 pmf.flags(abs) != mf.flags(abs)):
4764 handle(revert, False)
4787 handle(revert, False)
4765 else:
4788 else:
4766 handle(remove, False)
4789 handle(remove, False)
4767
4790
4768 if not opts.get('dry_run'):
4791 if not opts.get('dry_run'):
4769 def checkout(f):
4792 def checkout(f):
4770 fc = ctx[f]
4793 fc = ctx[f]
4771 repo.wwrite(f, fc.data(), fc.flags())
4794 repo.wwrite(f, fc.data(), fc.flags())
4772
4795
4773 audit_path = scmutil.pathauditor(repo.root)
4796 audit_path = scmutil.pathauditor(repo.root)
4774 for f in remove[0]:
4797 for f in remove[0]:
4775 if repo.dirstate[f] == 'a':
4798 if repo.dirstate[f] == 'a':
4776 repo.dirstate.drop(f)
4799 repo.dirstate.drop(f)
4777 continue
4800 continue
4778 audit_path(f)
4801 audit_path(f)
4779 try:
4802 try:
4780 util.unlinkpath(repo.wjoin(f))
4803 util.unlinkpath(repo.wjoin(f))
4781 except OSError:
4804 except OSError:
4782 pass
4805 pass
4783 repo.dirstate.remove(f)
4806 repo.dirstate.remove(f)
4784
4807
4785 normal = None
4808 normal = None
4786 if node == parent:
4809 if node == parent:
4787 # We're reverting to our parent. If possible, we'd like status
4810 # We're reverting to our parent. If possible, we'd like status
4788 # to report the file as clean. We have to use normallookup for
4811 # to report the file as clean. We have to use normallookup for
4789 # merges to avoid losing information about merged/dirty files.
4812 # merges to avoid losing information about merged/dirty files.
4790 if p2 != nullid:
4813 if p2 != nullid:
4791 normal = repo.dirstate.normallookup
4814 normal = repo.dirstate.normallookup
4792 else:
4815 else:
4793 normal = repo.dirstate.normal
4816 normal = repo.dirstate.normal
4794 for f in revert[0]:
4817 for f in revert[0]:
4795 checkout(f)
4818 checkout(f)
4796 if normal:
4819 if normal:
4797 normal(f)
4820 normal(f)
4798
4821
4799 for f in add[0]:
4822 for f in add[0]:
4800 checkout(f)
4823 checkout(f)
4801 repo.dirstate.add(f)
4824 repo.dirstate.add(f)
4802
4825
4803 normal = repo.dirstate.normallookup
4826 normal = repo.dirstate.normallookup
4804 if node == parent and p2 == nullid:
4827 if node == parent and p2 == nullid:
4805 normal = repo.dirstate.normal
4828 normal = repo.dirstate.normal
4806 for f in undelete[0]:
4829 for f in undelete[0]:
4807 checkout(f)
4830 checkout(f)
4808 normal(f)
4831 normal(f)
4809
4832
4810 finally:
4833 finally:
4811 wlock.release()
4834 wlock.release()
4812
4835
4813 @command('rollback', dryrunopts +
4836 @command('rollback', dryrunopts +
4814 [('f', 'force', False, _('ignore safety measures'))])
4837 [('f', 'force', False, _('ignore safety measures'))])
4815 def rollback(ui, repo, **opts):
4838 def rollback(ui, repo, **opts):
4816 """roll back the last transaction (dangerous)
4839 """roll back the last transaction (dangerous)
4817
4840
4818 This command should be used with care. There is only one level of
4841 This command should be used with care. There is only one level of
4819 rollback, and there is no way to undo a rollback. It will also
4842 rollback, and there is no way to undo a rollback. It will also
4820 restore the dirstate at the time of the last transaction, losing
4843 restore the dirstate at the time of the last transaction, losing
4821 any dirstate changes since that time. This command does not alter
4844 any dirstate changes since that time. This command does not alter
4822 the working directory.
4845 the working directory.
4823
4846
4824 Transactions are used to encapsulate the effects of all commands
4847 Transactions are used to encapsulate the effects of all commands
4825 that create new changesets or propagate existing changesets into a
4848 that create new changesets or propagate existing changesets into a
4826 repository. For example, the following commands are transactional,
4849 repository. For example, the following commands are transactional,
4827 and their effects can be rolled back:
4850 and their effects can be rolled back:
4828
4851
4829 - commit
4852 - commit
4830 - import
4853 - import
4831 - pull
4854 - pull
4832 - push (with this repository as the destination)
4855 - push (with this repository as the destination)
4833 - unbundle
4856 - unbundle
4834
4857
4835 It's possible to lose data with rollback: commit, update back to
4858 It's possible to lose data with rollback: commit, update back to
4836 an older changeset, and then rollback. The update removes the
4859 an older changeset, and then rollback. The update removes the
4837 changes you committed from the working directory, and rollback
4860 changes you committed from the working directory, and rollback
4838 removes them from history. To avoid data loss, you must pass
4861 removes them from history. To avoid data loss, you must pass
4839 --force in this case.
4862 --force in this case.
4840
4863
4841 This command is not intended for use on public repositories. Once
4864 This command is not intended for use on public repositories. Once
4842 changes are visible for pull by other users, rolling a transaction
4865 changes are visible for pull by other users, rolling a transaction
4843 back locally is ineffective (someone else may already have pulled
4866 back locally is ineffective (someone else may already have pulled
4844 the changes). Furthermore, a race is possible with readers of the
4867 the changes). Furthermore, a race is possible with readers of the
4845 repository; for example an in-progress pull from the repository
4868 repository; for example an in-progress pull from the repository
4846 may fail if a rollback is performed.
4869 may fail if a rollback is performed.
4847
4870
4848 Returns 0 on success, 1 if no rollback data is available.
4871 Returns 0 on success, 1 if no rollback data is available.
4849 """
4872 """
4850 return repo.rollback(dryrun=opts.get('dry_run'),
4873 return repo.rollback(dryrun=opts.get('dry_run'),
4851 force=opts.get('force'))
4874 force=opts.get('force'))
4852
4875
4853 @command('root', [])
4876 @command('root', [])
4854 def root(ui, repo):
4877 def root(ui, repo):
4855 """print the root (top) of the current working directory
4878 """print the root (top) of the current working directory
4856
4879
4857 Print the root directory of the current repository.
4880 Print the root directory of the current repository.
4858
4881
4859 Returns 0 on success.
4882 Returns 0 on success.
4860 """
4883 """
4861 ui.write(repo.root + "\n")
4884 ui.write(repo.root + "\n")
4862
4885
4863 @command('^serve',
4886 @command('^serve',
4864 [('A', 'accesslog', '', _('name of access log file to write to'),
4887 [('A', 'accesslog', '', _('name of access log file to write to'),
4865 _('FILE')),
4888 _('FILE')),
4866 ('d', 'daemon', None, _('run server in background')),
4889 ('d', 'daemon', None, _('run server in background')),
4867 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
4890 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
4868 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4891 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4869 # use string type, then we can check if something was passed
4892 # use string type, then we can check if something was passed
4870 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4893 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4871 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4894 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4872 _('ADDR')),
4895 _('ADDR')),
4873 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4896 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4874 _('PREFIX')),
4897 _('PREFIX')),
4875 ('n', 'name', '',
4898 ('n', 'name', '',
4876 _('name to show in web pages (default: working directory)'), _('NAME')),
4899 _('name to show in web pages (default: working directory)'), _('NAME')),
4877 ('', 'web-conf', '',
4900 ('', 'web-conf', '',
4878 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
4901 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
4879 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4902 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4880 _('FILE')),
4903 _('FILE')),
4881 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4904 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4882 ('', 'stdio', None, _('for remote clients')),
4905 ('', 'stdio', None, _('for remote clients')),
4883 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
4906 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
4884 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4907 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4885 ('', 'style', '', _('template style to use'), _('STYLE')),
4908 ('', 'style', '', _('template style to use'), _('STYLE')),
4886 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4909 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4887 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
4910 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
4888 _('[OPTION]...'))
4911 _('[OPTION]...'))
4889 def serve(ui, repo, **opts):
4912 def serve(ui, repo, **opts):
4890 """start stand-alone webserver
4913 """start stand-alone webserver
4891
4914
4892 Start a local HTTP repository browser and pull server. You can use
4915 Start a local HTTP repository browser and pull server. You can use
4893 this for ad-hoc sharing and browsing of repositories. It is
4916 this for ad-hoc sharing and browsing of repositories. It is
4894 recommended to use a real web server to serve a repository for
4917 recommended to use a real web server to serve a repository for
4895 longer periods of time.
4918 longer periods of time.
4896
4919
4897 Please note that the server does not implement access control.
4920 Please note that the server does not implement access control.
4898 This means that, by default, anybody can read from the server and
4921 This means that, by default, anybody can read from the server and
4899 nobody can write to it by default. Set the ``web.allow_push``
4922 nobody can write to it by default. Set the ``web.allow_push``
4900 option to ``*`` to allow everybody to push to the server. You
4923 option to ``*`` to allow everybody to push to the server. You
4901 should use a real web server if you need to authenticate users.
4924 should use a real web server if you need to authenticate users.
4902
4925
4903 By default, the server logs accesses to stdout and errors to
4926 By default, the server logs accesses to stdout and errors to
4904 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4927 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4905 files.
4928 files.
4906
4929
4907 To have the server choose a free port number to listen on, specify
4930 To have the server choose a free port number to listen on, specify
4908 a port number of 0; in this case, the server will print the port
4931 a port number of 0; in this case, the server will print the port
4909 number it uses.
4932 number it uses.
4910
4933
4911 Returns 0 on success.
4934 Returns 0 on success.
4912 """
4935 """
4913
4936
4914 if opts["stdio"] and opts["cmdserver"]:
4937 if opts["stdio"] and opts["cmdserver"]:
4915 raise util.Abort(_("cannot use --stdio with --cmdserver"))
4938 raise util.Abort(_("cannot use --stdio with --cmdserver"))
4916
4939
4917 def checkrepo():
4940 def checkrepo():
4918 if repo is None:
4941 if repo is None:
4919 raise error.RepoError(_("There is no Mercurial repository here"
4942 raise error.RepoError(_("There is no Mercurial repository here"
4920 " (.hg not found)"))
4943 " (.hg not found)"))
4921
4944
4922 if opts["stdio"]:
4945 if opts["stdio"]:
4923 checkrepo()
4946 checkrepo()
4924 s = sshserver.sshserver(ui, repo)
4947 s = sshserver.sshserver(ui, repo)
4925 s.serve_forever()
4948 s.serve_forever()
4926
4949
4927 if opts["cmdserver"]:
4950 if opts["cmdserver"]:
4928 checkrepo()
4951 checkrepo()
4929 s = commandserver.server(ui, repo, opts["cmdserver"])
4952 s = commandserver.server(ui, repo, opts["cmdserver"])
4930 return s.serve()
4953 return s.serve()
4931
4954
4932 # this way we can check if something was given in the command-line
4955 # this way we can check if something was given in the command-line
4933 if opts.get('port'):
4956 if opts.get('port'):
4934 opts['port'] = util.getport(opts.get('port'))
4957 opts['port'] = util.getport(opts.get('port'))
4935
4958
4936 baseui = repo and repo.baseui or ui
4959 baseui = repo and repo.baseui or ui
4937 optlist = ("name templates style address port prefix ipv6"
4960 optlist = ("name templates style address port prefix ipv6"
4938 " accesslog errorlog certificate encoding")
4961 " accesslog errorlog certificate encoding")
4939 for o in optlist.split():
4962 for o in optlist.split():
4940 val = opts.get(o, '')
4963 val = opts.get(o, '')
4941 if val in (None, ''): # should check against default options instead
4964 if val in (None, ''): # should check against default options instead
4942 continue
4965 continue
4943 baseui.setconfig("web", o, val)
4966 baseui.setconfig("web", o, val)
4944 if repo and repo.ui != baseui:
4967 if repo and repo.ui != baseui:
4945 repo.ui.setconfig("web", o, val)
4968 repo.ui.setconfig("web", o, val)
4946
4969
4947 o = opts.get('web_conf') or opts.get('webdir_conf')
4970 o = opts.get('web_conf') or opts.get('webdir_conf')
4948 if not o:
4971 if not o:
4949 if not repo:
4972 if not repo:
4950 raise error.RepoError(_("There is no Mercurial repository"
4973 raise error.RepoError(_("There is no Mercurial repository"
4951 " here (.hg not found)"))
4974 " here (.hg not found)"))
4952 o = repo.root
4975 o = repo.root
4953
4976
4954 app = hgweb.hgweb(o, baseui=ui)
4977 app = hgweb.hgweb(o, baseui=ui)
4955
4978
4956 class service(object):
4979 class service(object):
4957 def init(self):
4980 def init(self):
4958 util.setsignalhandler()
4981 util.setsignalhandler()
4959 self.httpd = hgweb.server.create_server(ui, app)
4982 self.httpd = hgweb.server.create_server(ui, app)
4960
4983
4961 if opts['port'] and not ui.verbose:
4984 if opts['port'] and not ui.verbose:
4962 return
4985 return
4963
4986
4964 if self.httpd.prefix:
4987 if self.httpd.prefix:
4965 prefix = self.httpd.prefix.strip('/') + '/'
4988 prefix = self.httpd.prefix.strip('/') + '/'
4966 else:
4989 else:
4967 prefix = ''
4990 prefix = ''
4968
4991
4969 port = ':%d' % self.httpd.port
4992 port = ':%d' % self.httpd.port
4970 if port == ':80':
4993 if port == ':80':
4971 port = ''
4994 port = ''
4972
4995
4973 bindaddr = self.httpd.addr
4996 bindaddr = self.httpd.addr
4974 if bindaddr == '0.0.0.0':
4997 if bindaddr == '0.0.0.0':
4975 bindaddr = '*'
4998 bindaddr = '*'
4976 elif ':' in bindaddr: # IPv6
4999 elif ':' in bindaddr: # IPv6
4977 bindaddr = '[%s]' % bindaddr
5000 bindaddr = '[%s]' % bindaddr
4978
5001
4979 fqaddr = self.httpd.fqaddr
5002 fqaddr = self.httpd.fqaddr
4980 if ':' in fqaddr:
5003 if ':' in fqaddr:
4981 fqaddr = '[%s]' % fqaddr
5004 fqaddr = '[%s]' % fqaddr
4982 if opts['port']:
5005 if opts['port']:
4983 write = ui.status
5006 write = ui.status
4984 else:
5007 else:
4985 write = ui.write
5008 write = ui.write
4986 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5009 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
4987 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5010 (fqaddr, port, prefix, bindaddr, self.httpd.port))
4988
5011
4989 def run(self):
5012 def run(self):
4990 self.httpd.serve_forever()
5013 self.httpd.serve_forever()
4991
5014
4992 service = service()
5015 service = service()
4993
5016
4994 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5017 cmdutil.service(opts, initfn=service.init, runfn=service.run)
4995
5018
4996 @command('showconfig|debugconfig',
5019 @command('showconfig|debugconfig',
4997 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5020 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4998 _('[-u] [NAME]...'))
5021 _('[-u] [NAME]...'))
4999 def showconfig(ui, repo, *values, **opts):
5022 def showconfig(ui, repo, *values, **opts):
5000 """show combined config settings from all hgrc files
5023 """show combined config settings from all hgrc files
5001
5024
5002 With no arguments, print names and values of all config items.
5025 With no arguments, print names and values of all config items.
5003
5026
5004 With one argument of the form section.name, print just the value
5027 With one argument of the form section.name, print just the value
5005 of that config item.
5028 of that config item.
5006
5029
5007 With multiple arguments, print names and values of all config
5030 With multiple arguments, print names and values of all config
5008 items with matching section names.
5031 items with matching section names.
5009
5032
5010 With --debug, the source (filename and line number) is printed
5033 With --debug, the source (filename and line number) is printed
5011 for each config item.
5034 for each config item.
5012
5035
5013 Returns 0 on success.
5036 Returns 0 on success.
5014 """
5037 """
5015
5038
5016 for f in scmutil.rcpath():
5039 for f in scmutil.rcpath():
5017 ui.debug('read config from: %s\n' % f)
5040 ui.debug('read config from: %s\n' % f)
5018 untrusted = bool(opts.get('untrusted'))
5041 untrusted = bool(opts.get('untrusted'))
5019 if values:
5042 if values:
5020 sections = [v for v in values if '.' not in v]
5043 sections = [v for v in values if '.' not in v]
5021 items = [v for v in values if '.' in v]
5044 items = [v for v in values if '.' in v]
5022 if len(items) > 1 or items and sections:
5045 if len(items) > 1 or items and sections:
5023 raise util.Abort(_('only one config item permitted'))
5046 raise util.Abort(_('only one config item permitted'))
5024 for section, name, value in ui.walkconfig(untrusted=untrusted):
5047 for section, name, value in ui.walkconfig(untrusted=untrusted):
5025 value = str(value).replace('\n', '\\n')
5048 value = str(value).replace('\n', '\\n')
5026 sectname = section + '.' + name
5049 sectname = section + '.' + name
5027 if values:
5050 if values:
5028 for v in values:
5051 for v in values:
5029 if v == section:
5052 if v == section:
5030 ui.debug('%s: ' %
5053 ui.debug('%s: ' %
5031 ui.configsource(section, name, untrusted))
5054 ui.configsource(section, name, untrusted))
5032 ui.write('%s=%s\n' % (sectname, value))
5055 ui.write('%s=%s\n' % (sectname, value))
5033 elif v == sectname:
5056 elif v == sectname:
5034 ui.debug('%s: ' %
5057 ui.debug('%s: ' %
5035 ui.configsource(section, name, untrusted))
5058 ui.configsource(section, name, untrusted))
5036 ui.write(value, '\n')
5059 ui.write(value, '\n')
5037 else:
5060 else:
5038 ui.debug('%s: ' %
5061 ui.debug('%s: ' %
5039 ui.configsource(section, name, untrusted))
5062 ui.configsource(section, name, untrusted))
5040 ui.write('%s=%s\n' % (sectname, value))
5063 ui.write('%s=%s\n' % (sectname, value))
5041
5064
5042 @command('^status|st',
5065 @command('^status|st',
5043 [('A', 'all', None, _('show status of all files')),
5066 [('A', 'all', None, _('show status of all files')),
5044 ('m', 'modified', None, _('show only modified files')),
5067 ('m', 'modified', None, _('show only modified files')),
5045 ('a', 'added', None, _('show only added files')),
5068 ('a', 'added', None, _('show only added files')),
5046 ('r', 'removed', None, _('show only removed files')),
5069 ('r', 'removed', None, _('show only removed files')),
5047 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5070 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5048 ('c', 'clean', None, _('show only files without changes')),
5071 ('c', 'clean', None, _('show only files without changes')),
5049 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5072 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5050 ('i', 'ignored', None, _('show only ignored files')),
5073 ('i', 'ignored', None, _('show only ignored files')),
5051 ('n', 'no-status', None, _('hide status prefix')),
5074 ('n', 'no-status', None, _('hide status prefix')),
5052 ('C', 'copies', None, _('show source of copied files')),
5075 ('C', 'copies', None, _('show source of copied files')),
5053 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5076 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5054 ('', 'rev', [], _('show difference from revision'), _('REV')),
5077 ('', 'rev', [], _('show difference from revision'), _('REV')),
5055 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5078 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5056 ] + walkopts + subrepoopts,
5079 ] + walkopts + subrepoopts,
5057 _('[OPTION]... [FILE]...'))
5080 _('[OPTION]... [FILE]...'))
5058 def status(ui, repo, *pats, **opts):
5081 def status(ui, repo, *pats, **opts):
5059 """show changed files in the working directory
5082 """show changed files in the working directory
5060
5083
5061 Show status of files in the repository. If names are given, only
5084 Show status of files in the repository. If names are given, only
5062 files that match are shown. Files that are clean or ignored or
5085 files that match are shown. Files that are clean or ignored or
5063 the source of a copy/move operation, are not listed unless
5086 the source of a copy/move operation, are not listed unless
5064 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5087 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5065 Unless options described with "show only ..." are given, the
5088 Unless options described with "show only ..." are given, the
5066 options -mardu are used.
5089 options -mardu are used.
5067
5090
5068 Option -q/--quiet hides untracked (unknown and ignored) files
5091 Option -q/--quiet hides untracked (unknown and ignored) files
5069 unless explicitly requested with -u/--unknown or -i/--ignored.
5092 unless explicitly requested with -u/--unknown or -i/--ignored.
5070
5093
5071 .. note::
5094 .. note::
5072 status may appear to disagree with diff if permissions have
5095 status may appear to disagree with diff if permissions have
5073 changed or a merge has occurred. The standard diff format does
5096 changed or a merge has occurred. The standard diff format does
5074 not report permission changes and diff only reports changes
5097 not report permission changes and diff only reports changes
5075 relative to one merge parent.
5098 relative to one merge parent.
5076
5099
5077 If one revision is given, it is used as the base revision.
5100 If one revision is given, it is used as the base revision.
5078 If two revisions are given, the differences between them are
5101 If two revisions are given, the differences between them are
5079 shown. The --change option can also be used as a shortcut to list
5102 shown. The --change option can also be used as a shortcut to list
5080 the changed files of a revision from its first parent.
5103 the changed files of a revision from its first parent.
5081
5104
5082 The codes used to show the status of files are::
5105 The codes used to show the status of files are::
5083
5106
5084 M = modified
5107 M = modified
5085 A = added
5108 A = added
5086 R = removed
5109 R = removed
5087 C = clean
5110 C = clean
5088 ! = missing (deleted by non-hg command, but still tracked)
5111 ! = missing (deleted by non-hg command, but still tracked)
5089 ? = not tracked
5112 ? = not tracked
5090 I = ignored
5113 I = ignored
5091 = origin of the previous file listed as A (added)
5114 = origin of the previous file listed as A (added)
5092
5115
5093 .. container:: verbose
5116 .. container:: verbose
5094
5117
5095 Examples:
5118 Examples:
5096
5119
5097 - show changes in the working directory relative to a changeset:
5120 - show changes in the working directory relative to a changeset:
5098
5121
5099 hg status --rev 9353
5122 hg status --rev 9353
5100
5123
5101 - show all changes including copies in an existing changeset::
5124 - show all changes including copies in an existing changeset::
5102
5125
5103 hg status --copies --change 9353
5126 hg status --copies --change 9353
5104
5127
5105 - get a NUL separated list of added files, suitable for xargs::
5128 - get a NUL separated list of added files, suitable for xargs::
5106
5129
5107 hg status -an0
5130 hg status -an0
5108
5131
5109 Returns 0 on success.
5132 Returns 0 on success.
5110 """
5133 """
5111
5134
5112 revs = opts.get('rev')
5135 revs = opts.get('rev')
5113 change = opts.get('change')
5136 change = opts.get('change')
5114
5137
5115 if revs and change:
5138 if revs and change:
5116 msg = _('cannot specify --rev and --change at the same time')
5139 msg = _('cannot specify --rev and --change at the same time')
5117 raise util.Abort(msg)
5140 raise util.Abort(msg)
5118 elif change:
5141 elif change:
5119 node2 = repo.lookup(change)
5142 node2 = repo.lookup(change)
5120 node1 = repo[node2].p1().node()
5143 node1 = repo[node2].p1().node()
5121 else:
5144 else:
5122 node1, node2 = scmutil.revpair(repo, revs)
5145 node1, node2 = scmutil.revpair(repo, revs)
5123
5146
5124 cwd = (pats and repo.getcwd()) or ''
5147 cwd = (pats and repo.getcwd()) or ''
5125 end = opts.get('print0') and '\0' or '\n'
5148 end = opts.get('print0') and '\0' or '\n'
5126 copy = {}
5149 copy = {}
5127 states = 'modified added removed deleted unknown ignored clean'.split()
5150 states = 'modified added removed deleted unknown ignored clean'.split()
5128 show = [k for k in states if opts.get(k)]
5151 show = [k for k in states if opts.get(k)]
5129 if opts.get('all'):
5152 if opts.get('all'):
5130 show += ui.quiet and (states[:4] + ['clean']) or states
5153 show += ui.quiet and (states[:4] + ['clean']) or states
5131 if not show:
5154 if not show:
5132 show = ui.quiet and states[:4] or states[:5]
5155 show = ui.quiet and states[:4] or states[:5]
5133
5156
5134 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5157 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5135 'ignored' in show, 'clean' in show, 'unknown' in show,
5158 'ignored' in show, 'clean' in show, 'unknown' in show,
5136 opts.get('subrepos'))
5159 opts.get('subrepos'))
5137 changestates = zip(states, 'MAR!?IC', stat)
5160 changestates = zip(states, 'MAR!?IC', stat)
5138
5161
5139 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5162 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5140 ctxn = repo[nullid]
5163 ctxn = repo[nullid]
5141 ctx1 = repo[node1]
5164 ctx1 = repo[node1]
5142 ctx2 = repo[node2]
5165 ctx2 = repo[node2]
5143 added = stat[1]
5166 added = stat[1]
5144 if node2 is None:
5167 if node2 is None:
5145 added = stat[0] + stat[1] # merged?
5168 added = stat[0] + stat[1] # merged?
5146
5169
5147 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
5170 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
5148 if k in added:
5171 if k in added:
5149 copy[k] = v
5172 copy[k] = v
5150 elif v in added:
5173 elif v in added:
5151 copy[v] = k
5174 copy[v] = k
5152
5175
5153 for state, char, files in changestates:
5176 for state, char, files in changestates:
5154 if state in show:
5177 if state in show:
5155 format = "%s %%s%s" % (char, end)
5178 format = "%s %%s%s" % (char, end)
5156 if opts.get('no_status'):
5179 if opts.get('no_status'):
5157 format = "%%s%s" % end
5180 format = "%%s%s" % end
5158
5181
5159 for f in files:
5182 for f in files:
5160 ui.write(format % repo.pathto(f, cwd),
5183 ui.write(format % repo.pathto(f, cwd),
5161 label='status.' + state)
5184 label='status.' + state)
5162 if f in copy:
5185 if f in copy:
5163 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
5186 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
5164 label='status.copied')
5187 label='status.copied')
5165
5188
5166 @command('^summary|sum',
5189 @command('^summary|sum',
5167 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5190 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5168 def summary(ui, repo, **opts):
5191 def summary(ui, repo, **opts):
5169 """summarize working directory state
5192 """summarize working directory state
5170
5193
5171 This generates a brief summary of the working directory state,
5194 This generates a brief summary of the working directory state,
5172 including parents, branch, commit status, and available updates.
5195 including parents, branch, commit status, and available updates.
5173
5196
5174 With the --remote option, this will check the default paths for
5197 With the --remote option, this will check the default paths for
5175 incoming and outgoing changes. This can be time-consuming.
5198 incoming and outgoing changes. This can be time-consuming.
5176
5199
5177 Returns 0 on success.
5200 Returns 0 on success.
5178 """
5201 """
5179
5202
5180 ctx = repo[None]
5203 ctx = repo[None]
5181 parents = ctx.parents()
5204 parents = ctx.parents()
5182 pnode = parents[0].node()
5205 pnode = parents[0].node()
5183 marks = []
5206 marks = []
5184
5207
5185 for p in parents:
5208 for p in parents:
5186 # label with log.changeset (instead of log.parent) since this
5209 # label with log.changeset (instead of log.parent) since this
5187 # shows a working directory parent *changeset*:
5210 # shows a working directory parent *changeset*:
5188 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5211 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5189 label='log.changeset')
5212 label='log.changeset')
5190 ui.write(' '.join(p.tags()), label='log.tag')
5213 ui.write(' '.join(p.tags()), label='log.tag')
5191 if p.bookmarks():
5214 if p.bookmarks():
5192 marks.extend(p.bookmarks())
5215 marks.extend(p.bookmarks())
5193 if p.rev() == -1:
5216 if p.rev() == -1:
5194 if not len(repo):
5217 if not len(repo):
5195 ui.write(_(' (empty repository)'))
5218 ui.write(_(' (empty repository)'))
5196 else:
5219 else:
5197 ui.write(_(' (no revision checked out)'))
5220 ui.write(_(' (no revision checked out)'))
5198 ui.write('\n')
5221 ui.write('\n')
5199 if p.description():
5222 if p.description():
5200 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5223 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5201 label='log.summary')
5224 label='log.summary')
5202
5225
5203 branch = ctx.branch()
5226 branch = ctx.branch()
5204 bheads = repo.branchheads(branch)
5227 bheads = repo.branchheads(branch)
5205 m = _('branch: %s\n') % branch
5228 m = _('branch: %s\n') % branch
5206 if branch != 'default':
5229 if branch != 'default':
5207 ui.write(m, label='log.branch')
5230 ui.write(m, label='log.branch')
5208 else:
5231 else:
5209 ui.status(m, label='log.branch')
5232 ui.status(m, label='log.branch')
5210
5233
5211 if marks:
5234 if marks:
5212 current = repo._bookmarkcurrent
5235 current = repo._bookmarkcurrent
5213 ui.write(_('bookmarks:'), label='log.bookmark')
5236 ui.write(_('bookmarks:'), label='log.bookmark')
5214 if current is not None:
5237 if current is not None:
5215 try:
5238 try:
5216 marks.remove(current)
5239 marks.remove(current)
5217 ui.write(' *' + current, label='bookmarks.current')
5240 ui.write(' *' + current, label='bookmarks.current')
5218 except ValueError:
5241 except ValueError:
5219 # current bookmark not in parent ctx marks
5242 # current bookmark not in parent ctx marks
5220 pass
5243 pass
5221 for m in marks:
5244 for m in marks:
5222 ui.write(' ' + m, label='log.bookmark')
5245 ui.write(' ' + m, label='log.bookmark')
5223 ui.write('\n', label='log.bookmark')
5246 ui.write('\n', label='log.bookmark')
5224
5247
5225 st = list(repo.status(unknown=True))[:6]
5248 st = list(repo.status(unknown=True))[:6]
5226
5249
5227 c = repo.dirstate.copies()
5250 c = repo.dirstate.copies()
5228 copied, renamed = [], []
5251 copied, renamed = [], []
5229 for d, s in c.iteritems():
5252 for d, s in c.iteritems():
5230 if s in st[2]:
5253 if s in st[2]:
5231 st[2].remove(s)
5254 st[2].remove(s)
5232 renamed.append(d)
5255 renamed.append(d)
5233 else:
5256 else:
5234 copied.append(d)
5257 copied.append(d)
5235 if d in st[1]:
5258 if d in st[1]:
5236 st[1].remove(d)
5259 st[1].remove(d)
5237 st.insert(3, renamed)
5260 st.insert(3, renamed)
5238 st.insert(4, copied)
5261 st.insert(4, copied)
5239
5262
5240 ms = mergemod.mergestate(repo)
5263 ms = mergemod.mergestate(repo)
5241 st.append([f for f in ms if ms[f] == 'u'])
5264 st.append([f for f in ms if ms[f] == 'u'])
5242
5265
5243 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5266 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5244 st.append(subs)
5267 st.append(subs)
5245
5268
5246 labels = [ui.label(_('%d modified'), 'status.modified'),
5269 labels = [ui.label(_('%d modified'), 'status.modified'),
5247 ui.label(_('%d added'), 'status.added'),
5270 ui.label(_('%d added'), 'status.added'),
5248 ui.label(_('%d removed'), 'status.removed'),
5271 ui.label(_('%d removed'), 'status.removed'),
5249 ui.label(_('%d renamed'), 'status.copied'),
5272 ui.label(_('%d renamed'), 'status.copied'),
5250 ui.label(_('%d copied'), 'status.copied'),
5273 ui.label(_('%d copied'), 'status.copied'),
5251 ui.label(_('%d deleted'), 'status.deleted'),
5274 ui.label(_('%d deleted'), 'status.deleted'),
5252 ui.label(_('%d unknown'), 'status.unknown'),
5275 ui.label(_('%d unknown'), 'status.unknown'),
5253 ui.label(_('%d ignored'), 'status.ignored'),
5276 ui.label(_('%d ignored'), 'status.ignored'),
5254 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5277 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5255 ui.label(_('%d subrepos'), 'status.modified')]
5278 ui.label(_('%d subrepos'), 'status.modified')]
5256 t = []
5279 t = []
5257 for s, l in zip(st, labels):
5280 for s, l in zip(st, labels):
5258 if s:
5281 if s:
5259 t.append(l % len(s))
5282 t.append(l % len(s))
5260
5283
5261 t = ', '.join(t)
5284 t = ', '.join(t)
5262 cleanworkdir = False
5285 cleanworkdir = False
5263
5286
5264 if len(parents) > 1:
5287 if len(parents) > 1:
5265 t += _(' (merge)')
5288 t += _(' (merge)')
5266 elif branch != parents[0].branch():
5289 elif branch != parents[0].branch():
5267 t += _(' (new branch)')
5290 t += _(' (new branch)')
5268 elif (parents[0].extra().get('close') and
5291 elif (parents[0].extra().get('close') and
5269 pnode in repo.branchheads(branch, closed=True)):
5292 pnode in repo.branchheads(branch, closed=True)):
5270 t += _(' (head closed)')
5293 t += _(' (head closed)')
5271 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5294 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5272 t += _(' (clean)')
5295 t += _(' (clean)')
5273 cleanworkdir = True
5296 cleanworkdir = True
5274 elif pnode not in bheads:
5297 elif pnode not in bheads:
5275 t += _(' (new branch head)')
5298 t += _(' (new branch head)')
5276
5299
5277 if cleanworkdir:
5300 if cleanworkdir:
5278 ui.status(_('commit: %s\n') % t.strip())
5301 ui.status(_('commit: %s\n') % t.strip())
5279 else:
5302 else:
5280 ui.write(_('commit: %s\n') % t.strip())
5303 ui.write(_('commit: %s\n') % t.strip())
5281
5304
5282 # all ancestors of branch heads - all ancestors of parent = new csets
5305 # all ancestors of branch heads - all ancestors of parent = new csets
5283 new = [0] * len(repo)
5306 new = [0] * len(repo)
5284 cl = repo.changelog
5307 cl = repo.changelog
5285 for a in [cl.rev(n) for n in bheads]:
5308 for a in [cl.rev(n) for n in bheads]:
5286 new[a] = 1
5309 new[a] = 1
5287 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
5310 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
5288 new[a] = 1
5311 new[a] = 1
5289 for a in [p.rev() for p in parents]:
5312 for a in [p.rev() for p in parents]:
5290 if a >= 0:
5313 if a >= 0:
5291 new[a] = 0
5314 new[a] = 0
5292 for a in cl.ancestors(*[p.rev() for p in parents]):
5315 for a in cl.ancestors(*[p.rev() for p in parents]):
5293 new[a] = 0
5316 new[a] = 0
5294 new = sum(new)
5317 new = sum(new)
5295
5318
5296 if new == 0:
5319 if new == 0:
5297 ui.status(_('update: (current)\n'))
5320 ui.status(_('update: (current)\n'))
5298 elif pnode not in bheads:
5321 elif pnode not in bheads:
5299 ui.write(_('update: %d new changesets (update)\n') % new)
5322 ui.write(_('update: %d new changesets (update)\n') % new)
5300 else:
5323 else:
5301 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5324 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5302 (new, len(bheads)))
5325 (new, len(bheads)))
5303
5326
5304 if opts.get('remote'):
5327 if opts.get('remote'):
5305 t = []
5328 t = []
5306 source, branches = hg.parseurl(ui.expandpath('default'))
5329 source, branches = hg.parseurl(ui.expandpath('default'))
5307 other = hg.peer(repo, {}, source)
5330 other = hg.peer(repo, {}, source)
5308 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
5331 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
5309 ui.debug('comparing with %s\n' % util.hidepassword(source))
5332 ui.debug('comparing with %s\n' % util.hidepassword(source))
5310 repo.ui.pushbuffer()
5333 repo.ui.pushbuffer()
5311 commoninc = discovery.findcommonincoming(repo, other)
5334 commoninc = discovery.findcommonincoming(repo, other)
5312 _common, incoming, _rheads = commoninc
5335 _common, incoming, _rheads = commoninc
5313 repo.ui.popbuffer()
5336 repo.ui.popbuffer()
5314 if incoming:
5337 if incoming:
5315 t.append(_('1 or more incoming'))
5338 t.append(_('1 or more incoming'))
5316
5339
5317 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5340 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5318 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5341 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5319 if source != dest:
5342 if source != dest:
5320 other = hg.peer(repo, {}, dest)
5343 other = hg.peer(repo, {}, dest)
5321 commoninc = None
5344 commoninc = None
5322 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5345 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5323 repo.ui.pushbuffer()
5346 repo.ui.pushbuffer()
5324 common, outheads = discovery.findcommonoutgoing(repo, other,
5347 common, outheads = discovery.findcommonoutgoing(repo, other,
5325 commoninc=commoninc)
5348 commoninc=commoninc)
5326 repo.ui.popbuffer()
5349 repo.ui.popbuffer()
5327 o = repo.changelog.findmissing(common=common, heads=outheads)
5350 o = repo.changelog.findmissing(common=common, heads=outheads)
5328 if o:
5351 if o:
5329 t.append(_('%d outgoing') % len(o))
5352 t.append(_('%d outgoing') % len(o))
5330 if 'bookmarks' in other.listkeys('namespaces'):
5353 if 'bookmarks' in other.listkeys('namespaces'):
5331 lmarks = repo.listkeys('bookmarks')
5354 lmarks = repo.listkeys('bookmarks')
5332 rmarks = other.listkeys('bookmarks')
5355 rmarks = other.listkeys('bookmarks')
5333 diff = set(rmarks) - set(lmarks)
5356 diff = set(rmarks) - set(lmarks)
5334 if len(diff) > 0:
5357 if len(diff) > 0:
5335 t.append(_('%d incoming bookmarks') % len(diff))
5358 t.append(_('%d incoming bookmarks') % len(diff))
5336 diff = set(lmarks) - set(rmarks)
5359 diff = set(lmarks) - set(rmarks)
5337 if len(diff) > 0:
5360 if len(diff) > 0:
5338 t.append(_('%d outgoing bookmarks') % len(diff))
5361 t.append(_('%d outgoing bookmarks') % len(diff))
5339
5362
5340 if t:
5363 if t:
5341 ui.write(_('remote: %s\n') % (', '.join(t)))
5364 ui.write(_('remote: %s\n') % (', '.join(t)))
5342 else:
5365 else:
5343 ui.status(_('remote: (synced)\n'))
5366 ui.status(_('remote: (synced)\n'))
5344
5367
5345 @command('tag',
5368 @command('tag',
5346 [('f', 'force', None, _('force tag')),
5369 [('f', 'force', None, _('force tag')),
5347 ('l', 'local', None, _('make the tag local')),
5370 ('l', 'local', None, _('make the tag local')),
5348 ('r', 'rev', '', _('revision to tag'), _('REV')),
5371 ('r', 'rev', '', _('revision to tag'), _('REV')),
5349 ('', 'remove', None, _('remove a tag')),
5372 ('', 'remove', None, _('remove a tag')),
5350 # -l/--local is already there, commitopts cannot be used
5373 # -l/--local is already there, commitopts cannot be used
5351 ('e', 'edit', None, _('edit commit message')),
5374 ('e', 'edit', None, _('edit commit message')),
5352 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5375 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5353 ] + commitopts2,
5376 ] + commitopts2,
5354 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5377 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5355 def tag(ui, repo, name1, *names, **opts):
5378 def tag(ui, repo, name1, *names, **opts):
5356 """add one or more tags for the current or given revision
5379 """add one or more tags for the current or given revision
5357
5380
5358 Name a particular revision using <name>.
5381 Name a particular revision using <name>.
5359
5382
5360 Tags are used to name particular revisions of the repository and are
5383 Tags are used to name particular revisions of the repository and are
5361 very useful to compare different revisions, to go back to significant
5384 very useful to compare different revisions, to go back to significant
5362 earlier versions or to mark branch points as releases, etc. Changing
5385 earlier versions or to mark branch points as releases, etc. Changing
5363 an existing tag is normally disallowed; use -f/--force to override.
5386 an existing tag is normally disallowed; use -f/--force to override.
5364
5387
5365 If no revision is given, the parent of the working directory is
5388 If no revision is given, the parent of the working directory is
5366 used, or tip if no revision is checked out.
5389 used, or tip if no revision is checked out.
5367
5390
5368 To facilitate version control, distribution, and merging of tags,
5391 To facilitate version control, distribution, and merging of tags,
5369 they are stored as a file named ".hgtags" which is managed similarly
5392 they are stored as a file named ".hgtags" which is managed similarly
5370 to other project files and can be hand-edited if necessary. This
5393 to other project files and can be hand-edited if necessary. This
5371 also means that tagging creates a new commit. The file
5394 also means that tagging creates a new commit. The file
5372 ".hg/localtags" is used for local tags (not shared among
5395 ".hg/localtags" is used for local tags (not shared among
5373 repositories).
5396 repositories).
5374
5397
5375 Tag commits are usually made at the head of a branch. If the parent
5398 Tag commits are usually made at the head of a branch. If the parent
5376 of the working directory is not a branch head, :hg:`tag` aborts; use
5399 of the working directory is not a branch head, :hg:`tag` aborts; use
5377 -f/--force to force the tag commit to be based on a non-head
5400 -f/--force to force the tag commit to be based on a non-head
5378 changeset.
5401 changeset.
5379
5402
5380 See :hg:`help dates` for a list of formats valid for -d/--date.
5403 See :hg:`help dates` for a list of formats valid for -d/--date.
5381
5404
5382 Since tag names have priority over branch names during revision
5405 Since tag names have priority over branch names during revision
5383 lookup, using an existing branch name as a tag name is discouraged.
5406 lookup, using an existing branch name as a tag name is discouraged.
5384
5407
5385 Returns 0 on success.
5408 Returns 0 on success.
5386 """
5409 """
5387
5410
5388 rev_ = "."
5411 rev_ = "."
5389 names = [t.strip() for t in (name1,) + names]
5412 names = [t.strip() for t in (name1,) + names]
5390 if len(names) != len(set(names)):
5413 if len(names) != len(set(names)):
5391 raise util.Abort(_('tag names must be unique'))
5414 raise util.Abort(_('tag names must be unique'))
5392 for n in names:
5415 for n in names:
5393 if n in ['tip', '.', 'null']:
5416 if n in ['tip', '.', 'null']:
5394 raise util.Abort(_("the name '%s' is reserved") % n)
5417 raise util.Abort(_("the name '%s' is reserved") % n)
5395 if not n:
5418 if not n:
5396 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
5419 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
5397 if opts.get('rev') and opts.get('remove'):
5420 if opts.get('rev') and opts.get('remove'):
5398 raise util.Abort(_("--rev and --remove are incompatible"))
5421 raise util.Abort(_("--rev and --remove are incompatible"))
5399 if opts.get('rev'):
5422 if opts.get('rev'):
5400 rev_ = opts['rev']
5423 rev_ = opts['rev']
5401 message = opts.get('message')
5424 message = opts.get('message')
5402 if opts.get('remove'):
5425 if opts.get('remove'):
5403 expectedtype = opts.get('local') and 'local' or 'global'
5426 expectedtype = opts.get('local') and 'local' or 'global'
5404 for n in names:
5427 for n in names:
5405 if not repo.tagtype(n):
5428 if not repo.tagtype(n):
5406 raise util.Abort(_("tag '%s' does not exist") % n)
5429 raise util.Abort(_("tag '%s' does not exist") % n)
5407 if repo.tagtype(n) != expectedtype:
5430 if repo.tagtype(n) != expectedtype:
5408 if expectedtype == 'global':
5431 if expectedtype == 'global':
5409 raise util.Abort(_("tag '%s' is not a global tag") % n)
5432 raise util.Abort(_("tag '%s' is not a global tag") % n)
5410 else:
5433 else:
5411 raise util.Abort(_("tag '%s' is not a local tag") % n)
5434 raise util.Abort(_("tag '%s' is not a local tag") % n)
5412 rev_ = nullid
5435 rev_ = nullid
5413 if not message:
5436 if not message:
5414 # we don't translate commit messages
5437 # we don't translate commit messages
5415 message = 'Removed tag %s' % ', '.join(names)
5438 message = 'Removed tag %s' % ', '.join(names)
5416 elif not opts.get('force'):
5439 elif not opts.get('force'):
5417 for n in names:
5440 for n in names:
5418 if n in repo.tags():
5441 if n in repo.tags():
5419 raise util.Abort(_("tag '%s' already exists "
5442 raise util.Abort(_("tag '%s' already exists "
5420 "(use -f to force)") % n)
5443 "(use -f to force)") % n)
5421 if not opts.get('local'):
5444 if not opts.get('local'):
5422 p1, p2 = repo.dirstate.parents()
5445 p1, p2 = repo.dirstate.parents()
5423 if p2 != nullid:
5446 if p2 != nullid:
5424 raise util.Abort(_('uncommitted merge'))
5447 raise util.Abort(_('uncommitted merge'))
5425 bheads = repo.branchheads()
5448 bheads = repo.branchheads()
5426 if not opts.get('force') and bheads and p1 not in bheads:
5449 if not opts.get('force') and bheads and p1 not in bheads:
5427 raise util.Abort(_('not at a branch head (use -f to force)'))
5450 raise util.Abort(_('not at a branch head (use -f to force)'))
5428 r = scmutil.revsingle(repo, rev_).node()
5451 r = scmutil.revsingle(repo, rev_).node()
5429
5452
5430 if not message:
5453 if not message:
5431 # we don't translate commit messages
5454 # we don't translate commit messages
5432 message = ('Added tag %s for changeset %s' %
5455 message = ('Added tag %s for changeset %s' %
5433 (', '.join(names), short(r)))
5456 (', '.join(names), short(r)))
5434
5457
5435 date = opts.get('date')
5458 date = opts.get('date')
5436 if date:
5459 if date:
5437 date = util.parsedate(date)
5460 date = util.parsedate(date)
5438
5461
5439 if opts.get('edit'):
5462 if opts.get('edit'):
5440 message = ui.edit(message, ui.username())
5463 message = ui.edit(message, ui.username())
5441
5464
5442 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5465 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5443
5466
5444 @command('tags', [], '')
5467 @command('tags', [], '')
5445 def tags(ui, repo):
5468 def tags(ui, repo):
5446 """list repository tags
5469 """list repository tags
5447
5470
5448 This lists both regular and local tags. When the -v/--verbose
5471 This lists both regular and local tags. When the -v/--verbose
5449 switch is used, a third column "local" is printed for local tags.
5472 switch is used, a third column "local" is printed for local tags.
5450
5473
5451 Returns 0 on success.
5474 Returns 0 on success.
5452 """
5475 """
5453
5476
5454 hexfunc = ui.debugflag and hex or short
5477 hexfunc = ui.debugflag and hex or short
5455 tagtype = ""
5478 tagtype = ""
5456
5479
5457 for t, n in reversed(repo.tagslist()):
5480 for t, n in reversed(repo.tagslist()):
5458 if ui.quiet:
5481 if ui.quiet:
5459 ui.write("%s\n" % t, label='tags.normal')
5482 ui.write("%s\n" % t, label='tags.normal')
5460 continue
5483 continue
5461
5484
5462 hn = hexfunc(n)
5485 hn = hexfunc(n)
5463 r = "%5d:%s" % (repo.changelog.rev(n), hn)
5486 r = "%5d:%s" % (repo.changelog.rev(n), hn)
5464 rev = ui.label(r, 'log.changeset')
5487 rev = ui.label(r, 'log.changeset')
5465 spaces = " " * (30 - encoding.colwidth(t))
5488 spaces = " " * (30 - encoding.colwidth(t))
5466
5489
5467 tag = ui.label(t, 'tags.normal')
5490 tag = ui.label(t, 'tags.normal')
5468 if ui.verbose:
5491 if ui.verbose:
5469 if repo.tagtype(t) == 'local':
5492 if repo.tagtype(t) == 'local':
5470 tagtype = " local"
5493 tagtype = " local"
5471 tag = ui.label(t, 'tags.local')
5494 tag = ui.label(t, 'tags.local')
5472 else:
5495 else:
5473 tagtype = ""
5496 tagtype = ""
5474 ui.write("%s%s %s%s\n" % (tag, spaces, rev, tagtype))
5497 ui.write("%s%s %s%s\n" % (tag, spaces, rev, tagtype))
5475
5498
5476 @command('tip',
5499 @command('tip',
5477 [('p', 'patch', None, _('show patch')),
5500 [('p', 'patch', None, _('show patch')),
5478 ('g', 'git', None, _('use git extended diff format')),
5501 ('g', 'git', None, _('use git extended diff format')),
5479 ] + templateopts,
5502 ] + templateopts,
5480 _('[-p] [-g]'))
5503 _('[-p] [-g]'))
5481 def tip(ui, repo, **opts):
5504 def tip(ui, repo, **opts):
5482 """show the tip revision
5505 """show the tip revision
5483
5506
5484 The tip revision (usually just called the tip) is the changeset
5507 The tip revision (usually just called the tip) is the changeset
5485 most recently added to the repository (and therefore the most
5508 most recently added to the repository (and therefore the most
5486 recently changed head).
5509 recently changed head).
5487
5510
5488 If you have just made a commit, that commit will be the tip. If
5511 If you have just made a commit, that commit will be the tip. If
5489 you have just pulled changes from another repository, the tip of
5512 you have just pulled changes from another repository, the tip of
5490 that repository becomes the current tip. The "tip" tag is special
5513 that repository becomes the current tip. The "tip" tag is special
5491 and cannot be renamed or assigned to a different changeset.
5514 and cannot be renamed or assigned to a different changeset.
5492
5515
5493 Returns 0 on success.
5516 Returns 0 on success.
5494 """
5517 """
5495 displayer = cmdutil.show_changeset(ui, repo, opts)
5518 displayer = cmdutil.show_changeset(ui, repo, opts)
5496 displayer.show(repo[len(repo) - 1])
5519 displayer.show(repo[len(repo) - 1])
5497 displayer.close()
5520 displayer.close()
5498
5521
5499 @command('unbundle',
5522 @command('unbundle',
5500 [('u', 'update', None,
5523 [('u', 'update', None,
5501 _('update to new branch head if changesets were unbundled'))],
5524 _('update to new branch head if changesets were unbundled'))],
5502 _('[-u] FILE...'))
5525 _('[-u] FILE...'))
5503 def unbundle(ui, repo, fname1, *fnames, **opts):
5526 def unbundle(ui, repo, fname1, *fnames, **opts):
5504 """apply one or more changegroup files
5527 """apply one or more changegroup files
5505
5528
5506 Apply one or more compressed changegroup files generated by the
5529 Apply one or more compressed changegroup files generated by the
5507 bundle command.
5530 bundle command.
5508
5531
5509 Returns 0 on success, 1 if an update has unresolved files.
5532 Returns 0 on success, 1 if an update has unresolved files.
5510 """
5533 """
5511 fnames = (fname1,) + fnames
5534 fnames = (fname1,) + fnames
5512
5535
5513 lock = repo.lock()
5536 lock = repo.lock()
5514 wc = repo['.']
5537 wc = repo['.']
5515 try:
5538 try:
5516 for fname in fnames:
5539 for fname in fnames:
5517 f = url.open(ui, fname)
5540 f = url.open(ui, fname)
5518 gen = changegroup.readbundle(f, fname)
5541 gen = changegroup.readbundle(f, fname)
5519 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
5542 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
5520 lock=lock)
5543 lock=lock)
5521 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5544 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5522 finally:
5545 finally:
5523 lock.release()
5546 lock.release()
5524 return postincoming(ui, repo, modheads, opts.get('update'), None)
5547 return postincoming(ui, repo, modheads, opts.get('update'), None)
5525
5548
5526 @command('^update|up|checkout|co',
5549 @command('^update|up|checkout|co',
5527 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5550 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5528 ('c', 'check', None,
5551 ('c', 'check', None,
5529 _('update across branches if no uncommitted changes')),
5552 _('update across branches if no uncommitted changes')),
5530 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5553 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5531 ('r', 'rev', '', _('revision'), _('REV'))],
5554 ('r', 'rev', '', _('revision'), _('REV'))],
5532 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5555 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5533 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5556 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5534 """update working directory (or switch revisions)
5557 """update working directory (or switch revisions)
5535
5558
5536 Update the repository's working directory to the specified
5559 Update the repository's working directory to the specified
5537 changeset. If no changeset is specified, update to the tip of the
5560 changeset. If no changeset is specified, update to the tip of the
5538 current named branch.
5561 current named branch.
5539
5562
5540 If the changeset is not a descendant of the working directory's
5563 If the changeset is not a descendant of the working directory's
5541 parent, the update is aborted. With the -c/--check option, the
5564 parent, the update is aborted. With the -c/--check option, the
5542 working directory is checked for uncommitted changes; if none are
5565 working directory is checked for uncommitted changes; if none are
5543 found, the working directory is updated to the specified
5566 found, the working directory is updated to the specified
5544 changeset.
5567 changeset.
5545
5568
5546 Update sets the working directory's parent revison to the specified
5569 Update sets the working directory's parent revison to the specified
5547 changeset (see :hg:`help parents`).
5570 changeset (see :hg:`help parents`).
5548
5571
5549 The following rules apply when the working directory contains
5572 The following rules apply when the working directory contains
5550 uncommitted changes:
5573 uncommitted changes:
5551
5574
5552 1. If neither -c/--check nor -C/--clean is specified, and if
5575 1. If neither -c/--check nor -C/--clean is specified, and if
5553 the requested changeset is an ancestor or descendant of
5576 the requested changeset is an ancestor or descendant of
5554 the working directory's parent, the uncommitted changes
5577 the working directory's parent, the uncommitted changes
5555 are merged into the requested changeset and the merged
5578 are merged into the requested changeset and the merged
5556 result is left uncommitted. If the requested changeset is
5579 result is left uncommitted. If the requested changeset is
5557 not an ancestor or descendant (that is, it is on another
5580 not an ancestor or descendant (that is, it is on another
5558 branch), the update is aborted and the uncommitted changes
5581 branch), the update is aborted and the uncommitted changes
5559 are preserved.
5582 are preserved.
5560
5583
5561 2. With the -c/--check option, the update is aborted and the
5584 2. With the -c/--check option, the update is aborted and the
5562 uncommitted changes are preserved.
5585 uncommitted changes are preserved.
5563
5586
5564 3. With the -C/--clean option, uncommitted changes are discarded and
5587 3. With the -C/--clean option, uncommitted changes are discarded and
5565 the working directory is updated to the requested changeset.
5588 the working directory is updated to the requested changeset.
5566
5589
5567 Use null as the changeset to remove the working directory (like
5590 Use null as the changeset to remove the working directory (like
5568 :hg:`clone -U`).
5591 :hg:`clone -U`).
5569
5592
5570 If you want to revert just one file to an older revision, use
5593 If you want to revert just one file to an older revision, use
5571 :hg:`revert [-r REV] NAME`.
5594 :hg:`revert [-r REV] NAME`.
5572
5595
5573 See :hg:`help dates` for a list of formats valid for -d/--date.
5596 See :hg:`help dates` for a list of formats valid for -d/--date.
5574
5597
5575 Returns 0 on success, 1 if there are unresolved files.
5598 Returns 0 on success, 1 if there are unresolved files.
5576 """
5599 """
5577 if rev and node:
5600 if rev and node:
5578 raise util.Abort(_("please specify just one revision"))
5601 raise util.Abort(_("please specify just one revision"))
5579
5602
5580 if rev is None or rev == '':
5603 if rev is None or rev == '':
5581 rev = node
5604 rev = node
5582
5605
5583 # if we defined a bookmark, we have to remember the original bookmark name
5606 # if we defined a bookmark, we have to remember the original bookmark name
5584 brev = rev
5607 brev = rev
5585 rev = scmutil.revsingle(repo, rev, rev).rev()
5608 rev = scmutil.revsingle(repo, rev, rev).rev()
5586
5609
5587 if check and clean:
5610 if check and clean:
5588 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5611 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5589
5612
5590 if check:
5613 if check:
5591 # we could use dirty() but we can ignore merge and branch trivia
5614 # we could use dirty() but we can ignore merge and branch trivia
5592 c = repo[None]
5615 c = repo[None]
5593 if c.modified() or c.added() or c.removed():
5616 if c.modified() or c.added() or c.removed():
5594 raise util.Abort(_("uncommitted local changes"))
5617 raise util.Abort(_("uncommitted local changes"))
5595
5618
5596 if date:
5619 if date:
5597 if rev is not None:
5620 if rev is not None:
5598 raise util.Abort(_("you can't specify a revision and a date"))
5621 raise util.Abort(_("you can't specify a revision and a date"))
5599 rev = cmdutil.finddate(ui, repo, date)
5622 rev = cmdutil.finddate(ui, repo, date)
5600
5623
5601 if clean or check:
5624 if clean or check:
5602 ret = hg.clean(repo, rev)
5625 ret = hg.clean(repo, rev)
5603 else:
5626 else:
5604 ret = hg.update(repo, rev)
5627 ret = hg.update(repo, rev)
5605
5628
5606 if brev in repo._bookmarks:
5629 if brev in repo._bookmarks:
5607 bookmarks.setcurrent(repo, brev)
5630 bookmarks.setcurrent(repo, brev)
5608
5631
5609 return ret
5632 return ret
5610
5633
5611 @command('verify', [])
5634 @command('verify', [])
5612 def verify(ui, repo):
5635 def verify(ui, repo):
5613 """verify the integrity of the repository
5636 """verify the integrity of the repository
5614
5637
5615 Verify the integrity of the current repository.
5638 Verify the integrity of the current repository.
5616
5639
5617 This will perform an extensive check of the repository's
5640 This will perform an extensive check of the repository's
5618 integrity, validating the hashes and checksums of each entry in
5641 integrity, validating the hashes and checksums of each entry in
5619 the changelog, manifest, and tracked files, as well as the
5642 the changelog, manifest, and tracked files, as well as the
5620 integrity of their crosslinks and indices.
5643 integrity of their crosslinks and indices.
5621
5644
5622 Returns 0 on success, 1 if errors are encountered.
5645 Returns 0 on success, 1 if errors are encountered.
5623 """
5646 """
5624 return hg.verify(repo)
5647 return hg.verify(repo)
5625
5648
5626 @command('version', [])
5649 @command('version', [])
5627 def version_(ui):
5650 def version_(ui):
5628 """output version and copyright information"""
5651 """output version and copyright information"""
5629 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5652 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5630 % util.version())
5653 % util.version())
5631 ui.status(_(
5654 ui.status(_(
5632 "(see http://mercurial.selenic.com for more information)\n"
5655 "(see http://mercurial.selenic.com for more information)\n"
5633 "\nCopyright (C) 2005-2011 Matt Mackall and others\n"
5656 "\nCopyright (C) 2005-2011 Matt Mackall and others\n"
5634 "This is free software; see the source for copying conditions. "
5657 "This is free software; see the source for copying conditions. "
5635 "There is NO\nwarranty; "
5658 "There is NO\nwarranty; "
5636 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5659 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5637 ))
5660 ))
5638
5661
5639 norepo = ("clone init version help debugcommands debugcomplete"
5662 norepo = ("clone init version help debugcommands debugcomplete"
5640 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5663 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5641 " debugknown debuggetbundle debugbundle")
5664 " debugknown debuggetbundle debugbundle")
5642 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5665 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5643 " debugdata debugindex debugindexdot debugrevlog")
5666 " debugdata debugindex debugindexdot debugrevlog")
@@ -1,137 +1,140 b''
1 Subrepositories let you nest external repositories or projects into a
1 Subrepositories let you nest external repositories or projects into a
2 parent Mercurial repository, and make commands operate on them as a
2 parent Mercurial repository, and make commands operate on them as a
3 group.
3 group.
4
4
5 Mercurial currently supports Mercurial, Git, and Subversion
5 Mercurial currently supports Mercurial, Git, and Subversion
6 subrepositories.
6 subrepositories.
7
7
8 Subrepositories are made of three components:
8 Subrepositories are made of three components:
9
9
10 1. Nested repository checkouts. They can appear anywhere in the
10 1. Nested repository checkouts. They can appear anywhere in the
11 parent working directory.
11 parent working directory.
12
12
13 2. Nested repository references. They are defined in ``.hgsub`` and
13 2. Nested repository references. They are defined in ``.hgsub`` and
14 tell where the subrepository checkouts come from. Mercurial
14 tell where the subrepository checkouts come from. Mercurial
15 subrepositories are referenced like:
15 subrepositories are referenced like:
16
16
17 path/to/nested = https://example.com/nested/repo/path
17 path/to/nested = https://example.com/nested/repo/path
18
18
19 Git and Subversion subrepos are also supported:
19 Git and Subversion subrepos are also supported:
20
20
21 path/to/nested = [git]git://example.com/nested/repo/path
21 path/to/nested = [git]git://example.com/nested/repo/path
22 path/to/nested = [svn]https://example.com/nested/trunk/path
22 path/to/nested = [svn]https://example.com/nested/trunk/path
23
23
24 where ``path/to/nested`` is the checkout location relatively to the
24 where ``path/to/nested`` is the checkout location relatively to the
25 parent Mercurial root, and ``https://example.com/nested/repo/path``
25 parent Mercurial root, and ``https://example.com/nested/repo/path``
26 is the source repository path. The source can also reference a
26 is the source repository path. The source can also reference a
27 filesystem path.
27 filesystem path.
28
28
29 Note that ``.hgsub`` does not exist by default in Mercurial
29 Note that ``.hgsub`` does not exist by default in Mercurial
30 repositories, you have to create and add it to the parent
30 repositories, you have to create and add it to the parent
31 repository before using subrepositories.
31 repository before using subrepositories.
32
32
33 3. Nested repository states. They are defined in ``.hgsubstate`` and
33 3. Nested repository states. They are defined in ``.hgsubstate`` and
34 capture whatever information is required to restore the
34 capture whatever information is required to restore the
35 subrepositories to the state they were committed in a parent
35 subrepositories to the state they were committed in a parent
36 repository changeset. Mercurial automatically record the nested
36 repository changeset. Mercurial automatically record the nested
37 repositories states when committing in the parent repository.
37 repositories states when committing in the parent repository.
38
38
39 .. note::
39 .. note::
40 The ``.hgsubstate`` file should not be edited manually.
40 The ``.hgsubstate`` file should not be edited manually.
41
41
42
42
43 Adding a Subrepository
43 Adding a Subrepository
44 ----------------------
44 ----------------------
45
45
46 If ``.hgsub`` does not exist, create it and add it to the parent
46 If ``.hgsub`` does not exist, create it and add it to the parent
47 repository. Clone or checkout the external projects where you want it
47 repository. Clone or checkout the external projects where you want it
48 to live in the parent repository. Edit ``.hgsub`` and add the
48 to live in the parent repository. Edit ``.hgsub`` and add the
49 subrepository entry as described above. At this point, the
49 subrepository entry as described above. At this point, the
50 subrepository is tracked and the next commit will record its state in
50 subrepository is tracked and the next commit will record its state in
51 ``.hgsubstate`` and bind it to the committed changeset.
51 ``.hgsubstate`` and bind it to the committed changeset.
52
52
53 Synchronizing a Subrepository
53 Synchronizing a Subrepository
54 -----------------------------
54 -----------------------------
55
55
56 Subrepos do not automatically track the latest changeset of their
56 Subrepos do not automatically track the latest changeset of their
57 sources. Instead, they are updated to the changeset that corresponds
57 sources. Instead, they are updated to the changeset that corresponds
58 with the changeset checked out in the top-level changeset. This is so
58 with the changeset checked out in the top-level changeset. This is so
59 developers always get a consistent set of compatible code and
59 developers always get a consistent set of compatible code and
60 libraries when they update.
60 libraries when they update.
61
61
62 Thus, updating subrepos is a manual process. Simply check out target
62 Thus, updating subrepos is a manual process. Simply check out target
63 subrepo at the desired revision, test in the top-level repo, then
63 subrepo at the desired revision, test in the top-level repo, then
64 commit in the parent repository to record the new combination.
64 commit in the parent repository to record the new combination.
65
65
66 Deleting a Subrepository
66 Deleting a Subrepository
67 ------------------------
67 ------------------------
68
68
69 To remove a subrepository from the parent repository, delete its
69 To remove a subrepository from the parent repository, delete its
70 reference from ``.hgsub``, then remove its files.
70 reference from ``.hgsub``, then remove its files.
71
71
72 Interaction with Mercurial Commands
72 Interaction with Mercurial Commands
73 -----------------------------------
73 -----------------------------------
74
74
75 :add: add does not recurse in subrepos unless -S/--subrepos is
75 :add: add does not recurse in subrepos unless -S/--subrepos is
76 specified. However, if you specify the full path of a file in a
76 specified. However, if you specify the full path of a file in a
77 subrepo, it will be added even without -S/--subrepos specified.
77 subrepo, it will be added even without -S/--subrepos specified.
78 Git and Subversion subrepositories are currently silently
78 Git and Subversion subrepositories are currently silently
79 ignored.
79 ignored.
80
80
81 :archive: archive does not recurse in subrepositories unless
81 :archive: archive does not recurse in subrepositories unless
82 -S/--subrepos is specified.
82 -S/--subrepos is specified.
83
83
84 :commit: commit creates a consistent snapshot of the state of the
84 :commit: commit creates a consistent snapshot of the state of the
85 entire project and its subrepositories. If any subrepositories
85 entire project and its subrepositories. If any subrepositories
86 have been modified, Mercurial will abort. Mercurial can be made
86 have been modified, Mercurial will abort. Mercurial can be made
87 to instead commit all modified subrepositories by specifying
87 to instead commit all modified subrepositories by specifying
88 -S/--subrepos, or setting "ui.commitsubrepos=True" in a
88 -S/--subrepos, or setting "ui.commitsubrepos=True" in a
89 configuration file (see :hg:`help config`). After there are no
89 configuration file (see :hg:`help config`). After there are no
90 longer any modified subrepositories, it records their state and
90 longer any modified subrepositories, it records their state and
91 finally commits it in the parent repository.
91 finally commits it in the parent repository.
92
92
93 :diff: diff does not recurse in subrepos unless -S/--subrepos is
93 :diff: diff does not recurse in subrepos unless -S/--subrepos is
94 specified. Changes are displayed as usual, on the subrepositories
94 specified. Changes are displayed as usual, on the subrepositories
95 elements. Git and Subversion subrepositories are currently
95 elements. Git and Subversion subrepositories are currently
96 silently ignored.
96 silently ignored.
97
97
98 :forget: forget currently only handles exact file matches in subrepos.
99 Git and Subversion subrepositories are currently silently ignored.
100
98 :incoming: incoming does not recurse in subrepos unless -S/--subrepos
101 :incoming: incoming does not recurse in subrepos unless -S/--subrepos
99 is specified. Git and Subversion subrepositories are currently
102 is specified. Git and Subversion subrepositories are currently
100 silently ignored.
103 silently ignored.
101
104
102 :outgoing: outgoing does not recurse in subrepos unless -S/--subrepos
105 :outgoing: outgoing does not recurse in subrepos unless -S/--subrepos
103 is specified. Git and Subversion subrepositories are currently
106 is specified. Git and Subversion subrepositories are currently
104 silently ignored.
107 silently ignored.
105
108
106 :pull: pull is not recursive since it is not clear what to pull prior
109 :pull: pull is not recursive since it is not clear what to pull prior
107 to running :hg:`update`. Listing and retrieving all
110 to running :hg:`update`. Listing and retrieving all
108 subrepositories changes referenced by the parent repository pulled
111 subrepositories changes referenced by the parent repository pulled
109 changesets is expensive at best, impossible in the Subversion
112 changesets is expensive at best, impossible in the Subversion
110 case.
113 case.
111
114
112 :push: Mercurial will automatically push all subrepositories first
115 :push: Mercurial will automatically push all subrepositories first
113 when the parent repository is being pushed. This ensures new
116 when the parent repository is being pushed. This ensures new
114 subrepository changes are available when referenced by top-level
117 subrepository changes are available when referenced by top-level
115 repositories. Push is a no-op for Subversion subrepositories.
118 repositories. Push is a no-op for Subversion subrepositories.
116
119
117 :status: status does not recurse into subrepositories unless
120 :status: status does not recurse into subrepositories unless
118 -S/--subrepos is specified. Subrepository changes are displayed as
121 -S/--subrepos is specified. Subrepository changes are displayed as
119 regular Mercurial changes on the subrepository
122 regular Mercurial changes on the subrepository
120 elements. Subversion subrepositories are currently silently
123 elements. Subversion subrepositories are currently silently
121 ignored.
124 ignored.
122
125
123 :update: update restores the subrepos in the state they were
126 :update: update restores the subrepos in the state they were
124 originally committed in target changeset. If the recorded
127 originally committed in target changeset. If the recorded
125 changeset is not available in the current subrepository, Mercurial
128 changeset is not available in the current subrepository, Mercurial
126 will pull it in first before updating. This means that updating
129 will pull it in first before updating. This means that updating
127 can require network access when using subrepositories.
130 can require network access when using subrepositories.
128
131
129 Remapping Subrepositories Sources
132 Remapping Subrepositories Sources
130 ---------------------------------
133 ---------------------------------
131
134
132 A subrepository source location may change during a project life,
135 A subrepository source location may change during a project life,
133 invalidating references stored in the parent repository history. To
136 invalidating references stored in the parent repository history. To
134 fix this, rewriting rules can be defined in parent repository ``hgrc``
137 fix this, rewriting rules can be defined in parent repository ``hgrc``
135 file or in Mercurial configuration. See the ``[subpaths]`` section in
138 file or in Mercurial configuration. See the ``[subpaths]`` section in
136 hgrc(5) for more details.
139 hgrc(5) for more details.
137
140
@@ -1,1126 +1,1133 b''
1 # subrepo.py - sub-repository handling for Mercurial
1 # subrepo.py - sub-repository handling for Mercurial
2 #
2 #
3 # Copyright 2009-2010 Matt Mackall <mpm@selenic.com>
3 # Copyright 2009-2010 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 errno, os, re, xml.dom.minidom, shutil, posixpath
8 import errno, os, re, xml.dom.minidom, shutil, posixpath
9 import stat, subprocess, tarfile
9 import stat, subprocess, tarfile
10 from i18n import _
10 from i18n import _
11 import config, scmutil, util, node, error, cmdutil, bookmarks
11 import config, scmutil, util, node, error, cmdutil, bookmarks
12 hg = None
12 hg = None
13 propertycache = util.propertycache
13 propertycache = util.propertycache
14
14
15 nullstate = ('', '', 'empty')
15 nullstate = ('', '', 'empty')
16
16
17 def state(ctx, ui):
17 def state(ctx, ui):
18 """return a state dict, mapping subrepo paths configured in .hgsub
18 """return a state dict, mapping subrepo paths configured in .hgsub
19 to tuple: (source from .hgsub, revision from .hgsubstate, kind
19 to tuple: (source from .hgsub, revision from .hgsubstate, kind
20 (key in types dict))
20 (key in types dict))
21 """
21 """
22 p = config.config()
22 p = config.config()
23 def read(f, sections=None, remap=None):
23 def read(f, sections=None, remap=None):
24 if f in ctx:
24 if f in ctx:
25 try:
25 try:
26 data = ctx[f].data()
26 data = ctx[f].data()
27 except IOError, err:
27 except IOError, err:
28 if err.errno != errno.ENOENT:
28 if err.errno != errno.ENOENT:
29 raise
29 raise
30 # handle missing subrepo spec files as removed
30 # handle missing subrepo spec files as removed
31 ui.warn(_("warning: subrepo spec file %s not found\n") % f)
31 ui.warn(_("warning: subrepo spec file %s not found\n") % f)
32 return
32 return
33 p.parse(f, data, sections, remap, read)
33 p.parse(f, data, sections, remap, read)
34 else:
34 else:
35 raise util.Abort(_("subrepo spec file %s not found") % f)
35 raise util.Abort(_("subrepo spec file %s not found") % f)
36
36
37 if '.hgsub' in ctx:
37 if '.hgsub' in ctx:
38 read('.hgsub')
38 read('.hgsub')
39
39
40 for path, src in ui.configitems('subpaths'):
40 for path, src in ui.configitems('subpaths'):
41 p.set('subpaths', path, src, ui.configsource('subpaths', path))
41 p.set('subpaths', path, src, ui.configsource('subpaths', path))
42
42
43 rev = {}
43 rev = {}
44 if '.hgsubstate' in ctx:
44 if '.hgsubstate' in ctx:
45 try:
45 try:
46 for l in ctx['.hgsubstate'].data().splitlines():
46 for l in ctx['.hgsubstate'].data().splitlines():
47 revision, path = l.split(" ", 1)
47 revision, path = l.split(" ", 1)
48 rev[path] = revision
48 rev[path] = revision
49 except IOError, err:
49 except IOError, err:
50 if err.errno != errno.ENOENT:
50 if err.errno != errno.ENOENT:
51 raise
51 raise
52
52
53 def remap(src):
53 def remap(src):
54 for pattern, repl in p.items('subpaths'):
54 for pattern, repl in p.items('subpaths'):
55 # Turn r'C:\foo\bar' into r'C:\\foo\\bar' since re.sub
55 # Turn r'C:\foo\bar' into r'C:\\foo\\bar' since re.sub
56 # does a string decode.
56 # does a string decode.
57 repl = repl.encode('string-escape')
57 repl = repl.encode('string-escape')
58 # However, we still want to allow back references to go
58 # However, we still want to allow back references to go
59 # through unharmed, so we turn r'\\1' into r'\1'. Again,
59 # through unharmed, so we turn r'\\1' into r'\1'. Again,
60 # extra escapes are needed because re.sub string decodes.
60 # extra escapes are needed because re.sub string decodes.
61 repl = re.sub(r'\\\\([0-9]+)', r'\\\1', repl)
61 repl = re.sub(r'\\\\([0-9]+)', r'\\\1', repl)
62 try:
62 try:
63 src = re.sub(pattern, repl, src, 1)
63 src = re.sub(pattern, repl, src, 1)
64 except re.error, e:
64 except re.error, e:
65 raise util.Abort(_("bad subrepository pattern in %s: %s")
65 raise util.Abort(_("bad subrepository pattern in %s: %s")
66 % (p.source('subpaths', pattern), e))
66 % (p.source('subpaths', pattern), e))
67 return src
67 return src
68
68
69 state = {}
69 state = {}
70 for path, src in p[''].items():
70 for path, src in p[''].items():
71 kind = 'hg'
71 kind = 'hg'
72 if src.startswith('['):
72 if src.startswith('['):
73 if ']' not in src:
73 if ']' not in src:
74 raise util.Abort(_('missing ] in subrepo source'))
74 raise util.Abort(_('missing ] in subrepo source'))
75 kind, src = src.split(']', 1)
75 kind, src = src.split(']', 1)
76 kind = kind[1:]
76 kind = kind[1:]
77 src = src.lstrip() # strip any extra whitespace after ']'
77 src = src.lstrip() # strip any extra whitespace after ']'
78
78
79 if not util.url(src).isabs():
79 if not util.url(src).isabs():
80 parent = _abssource(ctx._repo, abort=False)
80 parent = _abssource(ctx._repo, abort=False)
81 if parent:
81 if parent:
82 parent = util.url(parent)
82 parent = util.url(parent)
83 parent.path = posixpath.join(parent.path or '', src)
83 parent.path = posixpath.join(parent.path or '', src)
84 parent.path = posixpath.normpath(parent.path)
84 parent.path = posixpath.normpath(parent.path)
85 joined = str(parent)
85 joined = str(parent)
86 # Remap the full joined path and use it if it changes,
86 # Remap the full joined path and use it if it changes,
87 # else remap the original source.
87 # else remap the original source.
88 remapped = remap(joined)
88 remapped = remap(joined)
89 if remapped == joined:
89 if remapped == joined:
90 src = remap(src)
90 src = remap(src)
91 else:
91 else:
92 src = remapped
92 src = remapped
93
93
94 src = remap(src)
94 src = remap(src)
95 state[path] = (src.strip(), rev.get(path, ''), kind)
95 state[path] = (src.strip(), rev.get(path, ''), kind)
96
96
97 return state
97 return state
98
98
99 def writestate(repo, state):
99 def writestate(repo, state):
100 """rewrite .hgsubstate in (outer) repo with these subrepo states"""
100 """rewrite .hgsubstate in (outer) repo with these subrepo states"""
101 lines = ['%s %s\n' % (state[s][1], s) for s in sorted(state)]
101 lines = ['%s %s\n' % (state[s][1], s) for s in sorted(state)]
102 repo.wwrite('.hgsubstate', ''.join(lines), '')
102 repo.wwrite('.hgsubstate', ''.join(lines), '')
103
103
104 def submerge(repo, wctx, mctx, actx, overwrite):
104 def submerge(repo, wctx, mctx, actx, overwrite):
105 """delegated from merge.applyupdates: merging of .hgsubstate file
105 """delegated from merge.applyupdates: merging of .hgsubstate file
106 in working context, merging context and ancestor context"""
106 in working context, merging context and ancestor context"""
107 if mctx == actx: # backwards?
107 if mctx == actx: # backwards?
108 actx = wctx.p1()
108 actx = wctx.p1()
109 s1 = wctx.substate
109 s1 = wctx.substate
110 s2 = mctx.substate
110 s2 = mctx.substate
111 sa = actx.substate
111 sa = actx.substate
112 sm = {}
112 sm = {}
113
113
114 repo.ui.debug("subrepo merge %s %s %s\n" % (wctx, mctx, actx))
114 repo.ui.debug("subrepo merge %s %s %s\n" % (wctx, mctx, actx))
115
115
116 def debug(s, msg, r=""):
116 def debug(s, msg, r=""):
117 if r:
117 if r:
118 r = "%s:%s:%s" % r
118 r = "%s:%s:%s" % r
119 repo.ui.debug(" subrepo %s: %s %s\n" % (s, msg, r))
119 repo.ui.debug(" subrepo %s: %s %s\n" % (s, msg, r))
120
120
121 for s, l in s1.items():
121 for s, l in s1.items():
122 a = sa.get(s, nullstate)
122 a = sa.get(s, nullstate)
123 ld = l # local state with possible dirty flag for compares
123 ld = l # local state with possible dirty flag for compares
124 if wctx.sub(s).dirty():
124 if wctx.sub(s).dirty():
125 ld = (l[0], l[1] + "+")
125 ld = (l[0], l[1] + "+")
126 if wctx == actx: # overwrite
126 if wctx == actx: # overwrite
127 a = ld
127 a = ld
128
128
129 if s in s2:
129 if s in s2:
130 r = s2[s]
130 r = s2[s]
131 if ld == r or r == a: # no change or local is newer
131 if ld == r or r == a: # no change or local is newer
132 sm[s] = l
132 sm[s] = l
133 continue
133 continue
134 elif ld == a: # other side changed
134 elif ld == a: # other side changed
135 debug(s, "other changed, get", r)
135 debug(s, "other changed, get", r)
136 wctx.sub(s).get(r, overwrite)
136 wctx.sub(s).get(r, overwrite)
137 sm[s] = r
137 sm[s] = r
138 elif ld[0] != r[0]: # sources differ
138 elif ld[0] != r[0]: # sources differ
139 if repo.ui.promptchoice(
139 if repo.ui.promptchoice(
140 _(' subrepository sources for %s differ\n'
140 _(' subrepository sources for %s differ\n'
141 'use (l)ocal source (%s) or (r)emote source (%s)?')
141 'use (l)ocal source (%s) or (r)emote source (%s)?')
142 % (s, l[0], r[0]),
142 % (s, l[0], r[0]),
143 (_('&Local'), _('&Remote')), 0):
143 (_('&Local'), _('&Remote')), 0):
144 debug(s, "prompt changed, get", r)
144 debug(s, "prompt changed, get", r)
145 wctx.sub(s).get(r, overwrite)
145 wctx.sub(s).get(r, overwrite)
146 sm[s] = r
146 sm[s] = r
147 elif ld[1] == a[1]: # local side is unchanged
147 elif ld[1] == a[1]: # local side is unchanged
148 debug(s, "other side changed, get", r)
148 debug(s, "other side changed, get", r)
149 wctx.sub(s).get(r, overwrite)
149 wctx.sub(s).get(r, overwrite)
150 sm[s] = r
150 sm[s] = r
151 else:
151 else:
152 debug(s, "both sides changed, merge with", r)
152 debug(s, "both sides changed, merge with", r)
153 wctx.sub(s).merge(r)
153 wctx.sub(s).merge(r)
154 sm[s] = l
154 sm[s] = l
155 elif ld == a: # remote removed, local unchanged
155 elif ld == a: # remote removed, local unchanged
156 debug(s, "remote removed, remove")
156 debug(s, "remote removed, remove")
157 wctx.sub(s).remove()
157 wctx.sub(s).remove()
158 elif a == nullstate: # not present in remote or ancestor
158 elif a == nullstate: # not present in remote or ancestor
159 debug(s, "local added, keep")
159 debug(s, "local added, keep")
160 sm[s] = l
160 sm[s] = l
161 continue
161 continue
162 else:
162 else:
163 if repo.ui.promptchoice(
163 if repo.ui.promptchoice(
164 _(' local changed subrepository %s which remote removed\n'
164 _(' local changed subrepository %s which remote removed\n'
165 'use (c)hanged version or (d)elete?') % s,
165 'use (c)hanged version or (d)elete?') % s,
166 (_('&Changed'), _('&Delete')), 0):
166 (_('&Changed'), _('&Delete')), 0):
167 debug(s, "prompt remove")
167 debug(s, "prompt remove")
168 wctx.sub(s).remove()
168 wctx.sub(s).remove()
169
169
170 for s, r in sorted(s2.items()):
170 for s, r in sorted(s2.items()):
171 if s in s1:
171 if s in s1:
172 continue
172 continue
173 elif s not in sa:
173 elif s not in sa:
174 debug(s, "remote added, get", r)
174 debug(s, "remote added, get", r)
175 mctx.sub(s).get(r)
175 mctx.sub(s).get(r)
176 sm[s] = r
176 sm[s] = r
177 elif r != sa[s]:
177 elif r != sa[s]:
178 if repo.ui.promptchoice(
178 if repo.ui.promptchoice(
179 _(' remote changed subrepository %s which local removed\n'
179 _(' remote changed subrepository %s which local removed\n'
180 'use (c)hanged version or (d)elete?') % s,
180 'use (c)hanged version or (d)elete?') % s,
181 (_('&Changed'), _('&Delete')), 0) == 0:
181 (_('&Changed'), _('&Delete')), 0) == 0:
182 debug(s, "prompt recreate", r)
182 debug(s, "prompt recreate", r)
183 wctx.sub(s).get(r)
183 wctx.sub(s).get(r)
184 sm[s] = r
184 sm[s] = r
185
185
186 # record merged .hgsubstate
186 # record merged .hgsubstate
187 writestate(repo, sm)
187 writestate(repo, sm)
188
188
189 def _updateprompt(ui, sub, dirty, local, remote):
189 def _updateprompt(ui, sub, dirty, local, remote):
190 if dirty:
190 if dirty:
191 msg = (_(' subrepository sources for %s differ\n'
191 msg = (_(' subrepository sources for %s differ\n'
192 'use (l)ocal source (%s) or (r)emote source (%s)?\n')
192 'use (l)ocal source (%s) or (r)emote source (%s)?\n')
193 % (subrelpath(sub), local, remote))
193 % (subrelpath(sub), local, remote))
194 else:
194 else:
195 msg = (_(' subrepository sources for %s differ (in checked out version)\n'
195 msg = (_(' subrepository sources for %s differ (in checked out version)\n'
196 'use (l)ocal source (%s) or (r)emote source (%s)?\n')
196 'use (l)ocal source (%s) or (r)emote source (%s)?\n')
197 % (subrelpath(sub), local, remote))
197 % (subrelpath(sub), local, remote))
198 return ui.promptchoice(msg, (_('&Local'), _('&Remote')), 0)
198 return ui.promptchoice(msg, (_('&Local'), _('&Remote')), 0)
199
199
200 def reporelpath(repo):
200 def reporelpath(repo):
201 """return path to this (sub)repo as seen from outermost repo"""
201 """return path to this (sub)repo as seen from outermost repo"""
202 parent = repo
202 parent = repo
203 while util.safehasattr(parent, '_subparent'):
203 while util.safehasattr(parent, '_subparent'):
204 parent = parent._subparent
204 parent = parent._subparent
205 p = parent.root.rstrip(os.sep)
205 p = parent.root.rstrip(os.sep)
206 return repo.root[len(p) + 1:]
206 return repo.root[len(p) + 1:]
207
207
208 def subrelpath(sub):
208 def subrelpath(sub):
209 """return path to this subrepo as seen from outermost repo"""
209 """return path to this subrepo as seen from outermost repo"""
210 if util.safehasattr(sub, '_relpath'):
210 if util.safehasattr(sub, '_relpath'):
211 return sub._relpath
211 return sub._relpath
212 if not util.safehasattr(sub, '_repo'):
212 if not util.safehasattr(sub, '_repo'):
213 return sub._path
213 return sub._path
214 return reporelpath(sub._repo)
214 return reporelpath(sub._repo)
215
215
216 def _abssource(repo, push=False, abort=True):
216 def _abssource(repo, push=False, abort=True):
217 """return pull/push path of repo - either based on parent repo .hgsub info
217 """return pull/push path of repo - either based on parent repo .hgsub info
218 or on the top repo config. Abort or return None if no source found."""
218 or on the top repo config. Abort or return None if no source found."""
219 if util.safehasattr(repo, '_subparent'):
219 if util.safehasattr(repo, '_subparent'):
220 source = util.url(repo._subsource)
220 source = util.url(repo._subsource)
221 if source.isabs():
221 if source.isabs():
222 return str(source)
222 return str(source)
223 source.path = posixpath.normpath(source.path)
223 source.path = posixpath.normpath(source.path)
224 parent = _abssource(repo._subparent, push, abort=False)
224 parent = _abssource(repo._subparent, push, abort=False)
225 if parent:
225 if parent:
226 parent = util.url(parent)
226 parent = util.url(parent)
227 parent.path = posixpath.join(parent.path or '', source.path)
227 parent.path = posixpath.join(parent.path or '', source.path)
228 parent.path = posixpath.normpath(parent.path)
228 parent.path = posixpath.normpath(parent.path)
229 return str(parent)
229 return str(parent)
230 else: # recursion reached top repo
230 else: # recursion reached top repo
231 if util.safehasattr(repo, '_subtoppath'):
231 if util.safehasattr(repo, '_subtoppath'):
232 return repo._subtoppath
232 return repo._subtoppath
233 if push and repo.ui.config('paths', 'default-push'):
233 if push and repo.ui.config('paths', 'default-push'):
234 return repo.ui.config('paths', 'default-push')
234 return repo.ui.config('paths', 'default-push')
235 if repo.ui.config('paths', 'default'):
235 if repo.ui.config('paths', 'default'):
236 return repo.ui.config('paths', 'default')
236 return repo.ui.config('paths', 'default')
237 if abort:
237 if abort:
238 raise util.Abort(_("default path for subrepository %s not found") %
238 raise util.Abort(_("default path for subrepository %s not found") %
239 reporelpath(repo))
239 reporelpath(repo))
240
240
241 def itersubrepos(ctx1, ctx2):
241 def itersubrepos(ctx1, ctx2):
242 """find subrepos in ctx1 or ctx2"""
242 """find subrepos in ctx1 or ctx2"""
243 # Create a (subpath, ctx) mapping where we prefer subpaths from
243 # Create a (subpath, ctx) mapping where we prefer subpaths from
244 # ctx1. The subpaths from ctx2 are important when the .hgsub file
244 # ctx1. The subpaths from ctx2 are important when the .hgsub file
245 # has been modified (in ctx2) but not yet committed (in ctx1).
245 # has been modified (in ctx2) but not yet committed (in ctx1).
246 subpaths = dict.fromkeys(ctx2.substate, ctx2)
246 subpaths = dict.fromkeys(ctx2.substate, ctx2)
247 subpaths.update(dict.fromkeys(ctx1.substate, ctx1))
247 subpaths.update(dict.fromkeys(ctx1.substate, ctx1))
248 for subpath, ctx in sorted(subpaths.iteritems()):
248 for subpath, ctx in sorted(subpaths.iteritems()):
249 yield subpath, ctx.sub(subpath)
249 yield subpath, ctx.sub(subpath)
250
250
251 def subrepo(ctx, path):
251 def subrepo(ctx, path):
252 """return instance of the right subrepo class for subrepo in path"""
252 """return instance of the right subrepo class for subrepo in path"""
253 # subrepo inherently violates our import layering rules
253 # subrepo inherently violates our import layering rules
254 # because it wants to make repo objects from deep inside the stack
254 # because it wants to make repo objects from deep inside the stack
255 # so we manually delay the circular imports to not break
255 # so we manually delay the circular imports to not break
256 # scripts that don't use our demand-loading
256 # scripts that don't use our demand-loading
257 global hg
257 global hg
258 import hg as h
258 import hg as h
259 hg = h
259 hg = h
260
260
261 scmutil.pathauditor(ctx._repo.root)(path)
261 scmutil.pathauditor(ctx._repo.root)(path)
262 state = ctx.substate.get(path, nullstate)
262 state = ctx.substate.get(path, nullstate)
263 if state[2] not in types:
263 if state[2] not in types:
264 raise util.Abort(_('unknown subrepo type %s') % state[2])
264 raise util.Abort(_('unknown subrepo type %s') % state[2])
265 return types[state[2]](ctx, path, state[:2])
265 return types[state[2]](ctx, path, state[:2])
266
266
267 # subrepo classes need to implement the following abstract class:
267 # subrepo classes need to implement the following abstract class:
268
268
269 class abstractsubrepo(object):
269 class abstractsubrepo(object):
270
270
271 def dirty(self, ignoreupdate=False):
271 def dirty(self, ignoreupdate=False):
272 """returns true if the dirstate of the subrepo is dirty or does not
272 """returns true if the dirstate of the subrepo is dirty or does not
273 match current stored state. If ignoreupdate is true, only check
273 match current stored state. If ignoreupdate is true, only check
274 whether the subrepo has uncommitted changes in its dirstate.
274 whether the subrepo has uncommitted changes in its dirstate.
275 """
275 """
276 raise NotImplementedError
276 raise NotImplementedError
277
277
278 def checknested(self, path):
278 def checknested(self, path):
279 """check if path is a subrepository within this repository"""
279 """check if path is a subrepository within this repository"""
280 return False
280 return False
281
281
282 def commit(self, text, user, date):
282 def commit(self, text, user, date):
283 """commit the current changes to the subrepo with the given
283 """commit the current changes to the subrepo with the given
284 log message. Use given user and date if possible. Return the
284 log message. Use given user and date if possible. Return the
285 new state of the subrepo.
285 new state of the subrepo.
286 """
286 """
287 raise NotImplementedError
287 raise NotImplementedError
288
288
289 def remove(self):
289 def remove(self):
290 """remove the subrepo
290 """remove the subrepo
291
291
292 (should verify the dirstate is not dirty first)
292 (should verify the dirstate is not dirty first)
293 """
293 """
294 raise NotImplementedError
294 raise NotImplementedError
295
295
296 def get(self, state, overwrite=False):
296 def get(self, state, overwrite=False):
297 """run whatever commands are needed to put the subrepo into
297 """run whatever commands are needed to put the subrepo into
298 this state
298 this state
299 """
299 """
300 raise NotImplementedError
300 raise NotImplementedError
301
301
302 def merge(self, state):
302 def merge(self, state):
303 """merge currently-saved state with the new state."""
303 """merge currently-saved state with the new state."""
304 raise NotImplementedError
304 raise NotImplementedError
305
305
306 def push(self, force):
306 def push(self, force):
307 """perform whatever action is analogous to 'hg push'
307 """perform whatever action is analogous to 'hg push'
308
308
309 This may be a no-op on some systems.
309 This may be a no-op on some systems.
310 """
310 """
311 raise NotImplementedError
311 raise NotImplementedError
312
312
313 def add(self, ui, match, dryrun, prefix):
313 def add(self, ui, match, dryrun, prefix):
314 return []
314 return []
315
315
316 def status(self, rev2, **opts):
316 def status(self, rev2, **opts):
317 return [], [], [], [], [], [], []
317 return [], [], [], [], [], [], []
318
318
319 def diff(self, diffopts, node2, match, prefix, **opts):
319 def diff(self, diffopts, node2, match, prefix, **opts):
320 pass
320 pass
321
321
322 def outgoing(self, ui, dest, opts):
322 def outgoing(self, ui, dest, opts):
323 return 1
323 return 1
324
324
325 def incoming(self, ui, source, opts):
325 def incoming(self, ui, source, opts):
326 return 1
326 return 1
327
327
328 def files(self):
328 def files(self):
329 """return filename iterator"""
329 """return filename iterator"""
330 raise NotImplementedError
330 raise NotImplementedError
331
331
332 def filedata(self, name):
332 def filedata(self, name):
333 """return file data"""
333 """return file data"""
334 raise NotImplementedError
334 raise NotImplementedError
335
335
336 def fileflags(self, name):
336 def fileflags(self, name):
337 """return file flags"""
337 """return file flags"""
338 return ''
338 return ''
339
339
340 def archive(self, ui, archiver, prefix):
340 def archive(self, ui, archiver, prefix):
341 files = self.files()
341 files = self.files()
342 total = len(files)
342 total = len(files)
343 relpath = subrelpath(self)
343 relpath = subrelpath(self)
344 ui.progress(_('archiving (%s)') % relpath, 0,
344 ui.progress(_('archiving (%s)') % relpath, 0,
345 unit=_('files'), total=total)
345 unit=_('files'), total=total)
346 for i, name in enumerate(files):
346 for i, name in enumerate(files):
347 flags = self.fileflags(name)
347 flags = self.fileflags(name)
348 mode = 'x' in flags and 0755 or 0644
348 mode = 'x' in flags and 0755 or 0644
349 symlink = 'l' in flags
349 symlink = 'l' in flags
350 archiver.addfile(os.path.join(prefix, self._path, name),
350 archiver.addfile(os.path.join(prefix, self._path, name),
351 mode, symlink, self.filedata(name))
351 mode, symlink, self.filedata(name))
352 ui.progress(_('archiving (%s)') % relpath, i + 1,
352 ui.progress(_('archiving (%s)') % relpath, i + 1,
353 unit=_('files'), total=total)
353 unit=_('files'), total=total)
354 ui.progress(_('archiving (%s)') % relpath, None)
354 ui.progress(_('archiving (%s)') % relpath, None)
355
355
356 def walk(self, match):
356 def walk(self, match):
357 '''
357 '''
358 walk recursively through the directory tree, finding all files
358 walk recursively through the directory tree, finding all files
359 matched by the match function
359 matched by the match function
360 '''
360 '''
361 pass
361 pass
362
362
363 def forget(self, files):
364 pass
365
363 class hgsubrepo(abstractsubrepo):
366 class hgsubrepo(abstractsubrepo):
364 def __init__(self, ctx, path, state):
367 def __init__(self, ctx, path, state):
365 self._path = path
368 self._path = path
366 self._state = state
369 self._state = state
367 r = ctx._repo
370 r = ctx._repo
368 root = r.wjoin(path)
371 root = r.wjoin(path)
369 create = False
372 create = False
370 if not os.path.exists(os.path.join(root, '.hg')):
373 if not os.path.exists(os.path.join(root, '.hg')):
371 create = True
374 create = True
372 util.makedirs(root)
375 util.makedirs(root)
373 self._repo = hg.repository(r.ui, root, create=create)
376 self._repo = hg.repository(r.ui, root, create=create)
374 self._initrepo(r, state[0], create)
377 self._initrepo(r, state[0], create)
375
378
376 def _initrepo(self, parentrepo, source, create):
379 def _initrepo(self, parentrepo, source, create):
377 self._repo._subparent = parentrepo
380 self._repo._subparent = parentrepo
378 self._repo._subsource = source
381 self._repo._subsource = source
379
382
380 if create:
383 if create:
381 fp = self._repo.opener("hgrc", "w", text=True)
384 fp = self._repo.opener("hgrc", "w", text=True)
382 fp.write('[paths]\n')
385 fp.write('[paths]\n')
383
386
384 def addpathconfig(key, value):
387 def addpathconfig(key, value):
385 if value:
388 if value:
386 fp.write('%s = %s\n' % (key, value))
389 fp.write('%s = %s\n' % (key, value))
387 self._repo.ui.setconfig('paths', key, value)
390 self._repo.ui.setconfig('paths', key, value)
388
391
389 defpath = _abssource(self._repo, abort=False)
392 defpath = _abssource(self._repo, abort=False)
390 defpushpath = _abssource(self._repo, True, abort=False)
393 defpushpath = _abssource(self._repo, True, abort=False)
391 addpathconfig('default', defpath)
394 addpathconfig('default', defpath)
392 if defpath != defpushpath:
395 if defpath != defpushpath:
393 addpathconfig('default-push', defpushpath)
396 addpathconfig('default-push', defpushpath)
394 fp.close()
397 fp.close()
395
398
396 def add(self, ui, match, dryrun, prefix):
399 def add(self, ui, match, dryrun, prefix):
397 return cmdutil.add(ui, self._repo, match, dryrun, True,
400 return cmdutil.add(ui, self._repo, match, dryrun, True,
398 os.path.join(prefix, self._path))
401 os.path.join(prefix, self._path))
399
402
400 def status(self, rev2, **opts):
403 def status(self, rev2, **opts):
401 try:
404 try:
402 rev1 = self._state[1]
405 rev1 = self._state[1]
403 ctx1 = self._repo[rev1]
406 ctx1 = self._repo[rev1]
404 ctx2 = self._repo[rev2]
407 ctx2 = self._repo[rev2]
405 return self._repo.status(ctx1, ctx2, **opts)
408 return self._repo.status(ctx1, ctx2, **opts)
406 except error.RepoLookupError, inst:
409 except error.RepoLookupError, inst:
407 self._repo.ui.warn(_('warning: error "%s" in subrepository "%s"\n')
410 self._repo.ui.warn(_('warning: error "%s" in subrepository "%s"\n')
408 % (inst, subrelpath(self)))
411 % (inst, subrelpath(self)))
409 return [], [], [], [], [], [], []
412 return [], [], [], [], [], [], []
410
413
411 def diff(self, diffopts, node2, match, prefix, **opts):
414 def diff(self, diffopts, node2, match, prefix, **opts):
412 try:
415 try:
413 node1 = node.bin(self._state[1])
416 node1 = node.bin(self._state[1])
414 # We currently expect node2 to come from substate and be
417 # We currently expect node2 to come from substate and be
415 # in hex format
418 # in hex format
416 if node2 is not None:
419 if node2 is not None:
417 node2 = node.bin(node2)
420 node2 = node.bin(node2)
418 cmdutil.diffordiffstat(self._repo.ui, self._repo, diffopts,
421 cmdutil.diffordiffstat(self._repo.ui, self._repo, diffopts,
419 node1, node2, match,
422 node1, node2, match,
420 prefix=os.path.join(prefix, self._path),
423 prefix=os.path.join(prefix, self._path),
421 listsubrepos=True, **opts)
424 listsubrepos=True, **opts)
422 except error.RepoLookupError, inst:
425 except error.RepoLookupError, inst:
423 self._repo.ui.warn(_('warning: error "%s" in subrepository "%s"\n')
426 self._repo.ui.warn(_('warning: error "%s" in subrepository "%s"\n')
424 % (inst, subrelpath(self)))
427 % (inst, subrelpath(self)))
425
428
426 def archive(self, ui, archiver, prefix):
429 def archive(self, ui, archiver, prefix):
427 self._get(self._state + ('hg',))
430 self._get(self._state + ('hg',))
428 abstractsubrepo.archive(self, ui, archiver, prefix)
431 abstractsubrepo.archive(self, ui, archiver, prefix)
429
432
430 rev = self._state[1]
433 rev = self._state[1]
431 ctx = self._repo[rev]
434 ctx = self._repo[rev]
432 for subpath in ctx.substate:
435 for subpath in ctx.substate:
433 s = subrepo(ctx, subpath)
436 s = subrepo(ctx, subpath)
434 s.archive(ui, archiver, os.path.join(prefix, self._path))
437 s.archive(ui, archiver, os.path.join(prefix, self._path))
435
438
436 def dirty(self, ignoreupdate=False):
439 def dirty(self, ignoreupdate=False):
437 r = self._state[1]
440 r = self._state[1]
438 if r == '' and not ignoreupdate: # no state recorded
441 if r == '' and not ignoreupdate: # no state recorded
439 return True
442 return True
440 w = self._repo[None]
443 w = self._repo[None]
441 if r != w.p1().hex() and not ignoreupdate:
444 if r != w.p1().hex() and not ignoreupdate:
442 # different version checked out
445 # different version checked out
443 return True
446 return True
444 return w.dirty() # working directory changed
447 return w.dirty() # working directory changed
445
448
446 def checknested(self, path):
449 def checknested(self, path):
447 return self._repo._checknested(self._repo.wjoin(path))
450 return self._repo._checknested(self._repo.wjoin(path))
448
451
449 def commit(self, text, user, date):
452 def commit(self, text, user, date):
450 # don't bother committing in the subrepo if it's only been
453 # don't bother committing in the subrepo if it's only been
451 # updated
454 # updated
452 if not self.dirty(True):
455 if not self.dirty(True):
453 return self._repo['.'].hex()
456 return self._repo['.'].hex()
454 self._repo.ui.debug("committing subrepo %s\n" % subrelpath(self))
457 self._repo.ui.debug("committing subrepo %s\n" % subrelpath(self))
455 n = self._repo.commit(text, user, date)
458 n = self._repo.commit(text, user, date)
456 if not n:
459 if not n:
457 return self._repo['.'].hex() # different version checked out
460 return self._repo['.'].hex() # different version checked out
458 return node.hex(n)
461 return node.hex(n)
459
462
460 def remove(self):
463 def remove(self):
461 # we can't fully delete the repository as it may contain
464 # we can't fully delete the repository as it may contain
462 # local-only history
465 # local-only history
463 self._repo.ui.note(_('removing subrepo %s\n') % subrelpath(self))
466 self._repo.ui.note(_('removing subrepo %s\n') % subrelpath(self))
464 hg.clean(self._repo, node.nullid, False)
467 hg.clean(self._repo, node.nullid, False)
465
468
466 def _get(self, state):
469 def _get(self, state):
467 source, revision, kind = state
470 source, revision, kind = state
468 if revision not in self._repo:
471 if revision not in self._repo:
469 self._repo._subsource = source
472 self._repo._subsource = source
470 srcurl = _abssource(self._repo)
473 srcurl = _abssource(self._repo)
471 other = hg.peer(self._repo.ui, {}, srcurl)
474 other = hg.peer(self._repo.ui, {}, srcurl)
472 if len(self._repo) == 0:
475 if len(self._repo) == 0:
473 self._repo.ui.status(_('cloning subrepo %s from %s\n')
476 self._repo.ui.status(_('cloning subrepo %s from %s\n')
474 % (subrelpath(self), srcurl))
477 % (subrelpath(self), srcurl))
475 parentrepo = self._repo._subparent
478 parentrepo = self._repo._subparent
476 shutil.rmtree(self._repo.path)
479 shutil.rmtree(self._repo.path)
477 other, self._repo = hg.clone(self._repo._subparent.ui, {}, other,
480 other, self._repo = hg.clone(self._repo._subparent.ui, {}, other,
478 self._repo.root, update=False)
481 self._repo.root, update=False)
479 self._initrepo(parentrepo, source, create=True)
482 self._initrepo(parentrepo, source, create=True)
480 else:
483 else:
481 self._repo.ui.status(_('pulling subrepo %s from %s\n')
484 self._repo.ui.status(_('pulling subrepo %s from %s\n')
482 % (subrelpath(self), srcurl))
485 % (subrelpath(self), srcurl))
483 self._repo.pull(other)
486 self._repo.pull(other)
484 bookmarks.updatefromremote(self._repo.ui, self._repo, other)
487 bookmarks.updatefromremote(self._repo.ui, self._repo, other)
485
488
486 def get(self, state, overwrite=False):
489 def get(self, state, overwrite=False):
487 self._get(state)
490 self._get(state)
488 source, revision, kind = state
491 source, revision, kind = state
489 self._repo.ui.debug("getting subrepo %s\n" % self._path)
492 self._repo.ui.debug("getting subrepo %s\n" % self._path)
490 hg.clean(self._repo, revision, False)
493 hg.clean(self._repo, revision, False)
491
494
492 def merge(self, state):
495 def merge(self, state):
493 self._get(state)
496 self._get(state)
494 cur = self._repo['.']
497 cur = self._repo['.']
495 dst = self._repo[state[1]]
498 dst = self._repo[state[1]]
496 anc = dst.ancestor(cur)
499 anc = dst.ancestor(cur)
497
500
498 def mergefunc():
501 def mergefunc():
499 if anc == cur:
502 if anc == cur:
500 self._repo.ui.debug("updating subrepo %s\n" % subrelpath(self))
503 self._repo.ui.debug("updating subrepo %s\n" % subrelpath(self))
501 hg.update(self._repo, state[1])
504 hg.update(self._repo, state[1])
502 elif anc == dst:
505 elif anc == dst:
503 self._repo.ui.debug("skipping subrepo %s\n" % subrelpath(self))
506 self._repo.ui.debug("skipping subrepo %s\n" % subrelpath(self))
504 else:
507 else:
505 self._repo.ui.debug("merging subrepo %s\n" % subrelpath(self))
508 self._repo.ui.debug("merging subrepo %s\n" % subrelpath(self))
506 hg.merge(self._repo, state[1], remind=False)
509 hg.merge(self._repo, state[1], remind=False)
507
510
508 wctx = self._repo[None]
511 wctx = self._repo[None]
509 if self.dirty():
512 if self.dirty():
510 if anc != dst:
513 if anc != dst:
511 if _updateprompt(self._repo.ui, self, wctx.dirty(), cur, dst):
514 if _updateprompt(self._repo.ui, self, wctx.dirty(), cur, dst):
512 mergefunc()
515 mergefunc()
513 else:
516 else:
514 mergefunc()
517 mergefunc()
515 else:
518 else:
516 mergefunc()
519 mergefunc()
517
520
518 def push(self, force):
521 def push(self, force):
519 # push subrepos depth-first for coherent ordering
522 # push subrepos depth-first for coherent ordering
520 c = self._repo['']
523 c = self._repo['']
521 subs = c.substate # only repos that are committed
524 subs = c.substate # only repos that are committed
522 for s in sorted(subs):
525 for s in sorted(subs):
523 if not c.sub(s).push(force):
526 if not c.sub(s).push(force):
524 return False
527 return False
525
528
526 dsturl = _abssource(self._repo, True)
529 dsturl = _abssource(self._repo, True)
527 self._repo.ui.status(_('pushing subrepo %s to %s\n') %
530 self._repo.ui.status(_('pushing subrepo %s to %s\n') %
528 (subrelpath(self), dsturl))
531 (subrelpath(self), dsturl))
529 other = hg.peer(self._repo.ui, {}, dsturl)
532 other = hg.peer(self._repo.ui, {}, dsturl)
530 return self._repo.push(other, force)
533 return self._repo.push(other, force)
531
534
532 def outgoing(self, ui, dest, opts):
535 def outgoing(self, ui, dest, opts):
533 return hg.outgoing(ui, self._repo, _abssource(self._repo, True), opts)
536 return hg.outgoing(ui, self._repo, _abssource(self._repo, True), opts)
534
537
535 def incoming(self, ui, source, opts):
538 def incoming(self, ui, source, opts):
536 return hg.incoming(ui, self._repo, _abssource(self._repo, False), opts)
539 return hg.incoming(ui, self._repo, _abssource(self._repo, False), opts)
537
540
538 def files(self):
541 def files(self):
539 rev = self._state[1]
542 rev = self._state[1]
540 ctx = self._repo[rev]
543 ctx = self._repo[rev]
541 return ctx.manifest()
544 return ctx.manifest()
542
545
543 def filedata(self, name):
546 def filedata(self, name):
544 rev = self._state[1]
547 rev = self._state[1]
545 return self._repo[rev][name].data()
548 return self._repo[rev][name].data()
546
549
547 def fileflags(self, name):
550 def fileflags(self, name):
548 rev = self._state[1]
551 rev = self._state[1]
549 ctx = self._repo[rev]
552 ctx = self._repo[rev]
550 return ctx.flags(name)
553 return ctx.flags(name)
551
554
552 def walk(self, match):
555 def walk(self, match):
553 ctx = self._repo[None]
556 ctx = self._repo[None]
554 return ctx.walk(match)
557 return ctx.walk(match)
555
558
559 def forget(self, files):
560 ctx = self._repo[None]
561 ctx.forget(files)
562
556 class svnsubrepo(abstractsubrepo):
563 class svnsubrepo(abstractsubrepo):
557 def __init__(self, ctx, path, state):
564 def __init__(self, ctx, path, state):
558 self._path = path
565 self._path = path
559 self._state = state
566 self._state = state
560 self._ctx = ctx
567 self._ctx = ctx
561 self._ui = ctx._repo.ui
568 self._ui = ctx._repo.ui
562 self._exe = util.findexe('svn')
569 self._exe = util.findexe('svn')
563 if not self._exe:
570 if not self._exe:
564 raise util.Abort(_("'svn' executable not found for subrepo '%s'")
571 raise util.Abort(_("'svn' executable not found for subrepo '%s'")
565 % self._path)
572 % self._path)
566
573
567 def _svncommand(self, commands, filename='', failok=False):
574 def _svncommand(self, commands, filename='', failok=False):
568 cmd = [self._exe]
575 cmd = [self._exe]
569 extrakw = {}
576 extrakw = {}
570 if not self._ui.interactive():
577 if not self._ui.interactive():
571 # Making stdin be a pipe should prevent svn from behaving
578 # Making stdin be a pipe should prevent svn from behaving
572 # interactively even if we can't pass --non-interactive.
579 # interactively even if we can't pass --non-interactive.
573 extrakw['stdin'] = subprocess.PIPE
580 extrakw['stdin'] = subprocess.PIPE
574 # Starting in svn 1.5 --non-interactive is a global flag
581 # Starting in svn 1.5 --non-interactive is a global flag
575 # instead of being per-command, but we need to support 1.4 so
582 # instead of being per-command, but we need to support 1.4 so
576 # we have to be intelligent about what commands take
583 # we have to be intelligent about what commands take
577 # --non-interactive.
584 # --non-interactive.
578 if commands[0] in ('update', 'checkout', 'commit'):
585 if commands[0] in ('update', 'checkout', 'commit'):
579 cmd.append('--non-interactive')
586 cmd.append('--non-interactive')
580 cmd.extend(commands)
587 cmd.extend(commands)
581 if filename is not None:
588 if filename is not None:
582 path = os.path.join(self._ctx._repo.origroot, self._path, filename)
589 path = os.path.join(self._ctx._repo.origroot, self._path, filename)
583 cmd.append(path)
590 cmd.append(path)
584 env = dict(os.environ)
591 env = dict(os.environ)
585 # Avoid localized output, preserve current locale for everything else.
592 # Avoid localized output, preserve current locale for everything else.
586 env['LC_MESSAGES'] = 'C'
593 env['LC_MESSAGES'] = 'C'
587 p = subprocess.Popen(cmd, bufsize=-1, close_fds=util.closefds,
594 p = subprocess.Popen(cmd, bufsize=-1, close_fds=util.closefds,
588 stdout=subprocess.PIPE, stderr=subprocess.PIPE,
595 stdout=subprocess.PIPE, stderr=subprocess.PIPE,
589 universal_newlines=True, env=env, **extrakw)
596 universal_newlines=True, env=env, **extrakw)
590 stdout, stderr = p.communicate()
597 stdout, stderr = p.communicate()
591 stderr = stderr.strip()
598 stderr = stderr.strip()
592 if not failok:
599 if not failok:
593 if p.returncode:
600 if p.returncode:
594 raise util.Abort(stderr or 'exited with code %d' % p.returncode)
601 raise util.Abort(stderr or 'exited with code %d' % p.returncode)
595 if stderr:
602 if stderr:
596 self._ui.warn(stderr + '\n')
603 self._ui.warn(stderr + '\n')
597 return stdout, stderr
604 return stdout, stderr
598
605
599 @propertycache
606 @propertycache
600 def _svnversion(self):
607 def _svnversion(self):
601 output, err = self._svncommand(['--version'], filename=None)
608 output, err = self._svncommand(['--version'], filename=None)
602 m = re.search(r'^svn,\s+version\s+(\d+)\.(\d+)', output)
609 m = re.search(r'^svn,\s+version\s+(\d+)\.(\d+)', output)
603 if not m:
610 if not m:
604 raise util.Abort(_('cannot retrieve svn tool version'))
611 raise util.Abort(_('cannot retrieve svn tool version'))
605 return (int(m.group(1)), int(m.group(2)))
612 return (int(m.group(1)), int(m.group(2)))
606
613
607 def _wcrevs(self):
614 def _wcrevs(self):
608 # Get the working directory revision as well as the last
615 # Get the working directory revision as well as the last
609 # commit revision so we can compare the subrepo state with
616 # commit revision so we can compare the subrepo state with
610 # both. We used to store the working directory one.
617 # both. We used to store the working directory one.
611 output, err = self._svncommand(['info', '--xml'])
618 output, err = self._svncommand(['info', '--xml'])
612 doc = xml.dom.minidom.parseString(output)
619 doc = xml.dom.minidom.parseString(output)
613 entries = doc.getElementsByTagName('entry')
620 entries = doc.getElementsByTagName('entry')
614 lastrev, rev = '0', '0'
621 lastrev, rev = '0', '0'
615 if entries:
622 if entries:
616 rev = str(entries[0].getAttribute('revision')) or '0'
623 rev = str(entries[0].getAttribute('revision')) or '0'
617 commits = entries[0].getElementsByTagName('commit')
624 commits = entries[0].getElementsByTagName('commit')
618 if commits:
625 if commits:
619 lastrev = str(commits[0].getAttribute('revision')) or '0'
626 lastrev = str(commits[0].getAttribute('revision')) or '0'
620 return (lastrev, rev)
627 return (lastrev, rev)
621
628
622 def _wcrev(self):
629 def _wcrev(self):
623 return self._wcrevs()[0]
630 return self._wcrevs()[0]
624
631
625 def _wcchanged(self):
632 def _wcchanged(self):
626 """Return (changes, extchanges) where changes is True
633 """Return (changes, extchanges) where changes is True
627 if the working directory was changed, and extchanges is
634 if the working directory was changed, and extchanges is
628 True if any of these changes concern an external entry.
635 True if any of these changes concern an external entry.
629 """
636 """
630 output, err = self._svncommand(['status', '--xml'])
637 output, err = self._svncommand(['status', '--xml'])
631 externals, changes = [], []
638 externals, changes = [], []
632 doc = xml.dom.minidom.parseString(output)
639 doc = xml.dom.minidom.parseString(output)
633 for e in doc.getElementsByTagName('entry'):
640 for e in doc.getElementsByTagName('entry'):
634 s = e.getElementsByTagName('wc-status')
641 s = e.getElementsByTagName('wc-status')
635 if not s:
642 if not s:
636 continue
643 continue
637 item = s[0].getAttribute('item')
644 item = s[0].getAttribute('item')
638 props = s[0].getAttribute('props')
645 props = s[0].getAttribute('props')
639 path = e.getAttribute('path')
646 path = e.getAttribute('path')
640 if item == 'external':
647 if item == 'external':
641 externals.append(path)
648 externals.append(path)
642 if (item not in ('', 'normal', 'unversioned', 'external')
649 if (item not in ('', 'normal', 'unversioned', 'external')
643 or props not in ('', 'none', 'normal')):
650 or props not in ('', 'none', 'normal')):
644 changes.append(path)
651 changes.append(path)
645 for path in changes:
652 for path in changes:
646 for ext in externals:
653 for ext in externals:
647 if path == ext or path.startswith(ext + os.sep):
654 if path == ext or path.startswith(ext + os.sep):
648 return True, True
655 return True, True
649 return bool(changes), False
656 return bool(changes), False
650
657
651 def dirty(self, ignoreupdate=False):
658 def dirty(self, ignoreupdate=False):
652 if not self._wcchanged()[0]:
659 if not self._wcchanged()[0]:
653 if self._state[1] in self._wcrevs() or ignoreupdate:
660 if self._state[1] in self._wcrevs() or ignoreupdate:
654 return False
661 return False
655 return True
662 return True
656
663
657 def commit(self, text, user, date):
664 def commit(self, text, user, date):
658 # user and date are out of our hands since svn is centralized
665 # user and date are out of our hands since svn is centralized
659 changed, extchanged = self._wcchanged()
666 changed, extchanged = self._wcchanged()
660 if not changed:
667 if not changed:
661 return self._wcrev()
668 return self._wcrev()
662 if extchanged:
669 if extchanged:
663 # Do not try to commit externals
670 # Do not try to commit externals
664 raise util.Abort(_('cannot commit svn externals'))
671 raise util.Abort(_('cannot commit svn externals'))
665 commitinfo, err = self._svncommand(['commit', '-m', text])
672 commitinfo, err = self._svncommand(['commit', '-m', text])
666 self._ui.status(commitinfo)
673 self._ui.status(commitinfo)
667 newrev = re.search('Committed revision ([0-9]+).', commitinfo)
674 newrev = re.search('Committed revision ([0-9]+).', commitinfo)
668 if not newrev:
675 if not newrev:
669 raise util.Abort(commitinfo.splitlines()[-1])
676 raise util.Abort(commitinfo.splitlines()[-1])
670 newrev = newrev.groups()[0]
677 newrev = newrev.groups()[0]
671 self._ui.status(self._svncommand(['update', '-r', newrev])[0])
678 self._ui.status(self._svncommand(['update', '-r', newrev])[0])
672 return newrev
679 return newrev
673
680
674 def remove(self):
681 def remove(self):
675 if self.dirty():
682 if self.dirty():
676 self._ui.warn(_('not removing repo %s because '
683 self._ui.warn(_('not removing repo %s because '
677 'it has changes.\n' % self._path))
684 'it has changes.\n' % self._path))
678 return
685 return
679 self._ui.note(_('removing subrepo %s\n') % self._path)
686 self._ui.note(_('removing subrepo %s\n') % self._path)
680
687
681 def onerror(function, path, excinfo):
688 def onerror(function, path, excinfo):
682 if function is not os.remove:
689 if function is not os.remove:
683 raise
690 raise
684 # read-only files cannot be unlinked under Windows
691 # read-only files cannot be unlinked under Windows
685 s = os.stat(path)
692 s = os.stat(path)
686 if (s.st_mode & stat.S_IWRITE) != 0:
693 if (s.st_mode & stat.S_IWRITE) != 0:
687 raise
694 raise
688 os.chmod(path, stat.S_IMODE(s.st_mode) | stat.S_IWRITE)
695 os.chmod(path, stat.S_IMODE(s.st_mode) | stat.S_IWRITE)
689 os.remove(path)
696 os.remove(path)
690
697
691 path = self._ctx._repo.wjoin(self._path)
698 path = self._ctx._repo.wjoin(self._path)
692 shutil.rmtree(path, onerror=onerror)
699 shutil.rmtree(path, onerror=onerror)
693 try:
700 try:
694 os.removedirs(os.path.dirname(path))
701 os.removedirs(os.path.dirname(path))
695 except OSError:
702 except OSError:
696 pass
703 pass
697
704
698 def get(self, state, overwrite=False):
705 def get(self, state, overwrite=False):
699 if overwrite:
706 if overwrite:
700 self._svncommand(['revert', '--recursive'])
707 self._svncommand(['revert', '--recursive'])
701 args = ['checkout']
708 args = ['checkout']
702 if self._svnversion >= (1, 5):
709 if self._svnversion >= (1, 5):
703 args.append('--force')
710 args.append('--force')
704 # The revision must be specified at the end of the URL to properly
711 # The revision must be specified at the end of the URL to properly
705 # update to a directory which has since been deleted and recreated.
712 # update to a directory which has since been deleted and recreated.
706 args.append('%s@%s' % (state[0], state[1]))
713 args.append('%s@%s' % (state[0], state[1]))
707 status, err = self._svncommand(args, failok=True)
714 status, err = self._svncommand(args, failok=True)
708 if not re.search('Checked out revision [0-9]+.', status):
715 if not re.search('Checked out revision [0-9]+.', status):
709 if ('is already a working copy for a different URL' in err
716 if ('is already a working copy for a different URL' in err
710 and (self._wcchanged() == (False, False))):
717 and (self._wcchanged() == (False, False))):
711 # obstructed but clean working copy, so just blow it away.
718 # obstructed but clean working copy, so just blow it away.
712 self.remove()
719 self.remove()
713 self.get(state, overwrite=False)
720 self.get(state, overwrite=False)
714 return
721 return
715 raise util.Abort((status or err).splitlines()[-1])
722 raise util.Abort((status or err).splitlines()[-1])
716 self._ui.status(status)
723 self._ui.status(status)
717
724
718 def merge(self, state):
725 def merge(self, state):
719 old = self._state[1]
726 old = self._state[1]
720 new = state[1]
727 new = state[1]
721 if new != self._wcrev():
728 if new != self._wcrev():
722 dirty = old == self._wcrev() or self._wcchanged()[0]
729 dirty = old == self._wcrev() or self._wcchanged()[0]
723 if _updateprompt(self._ui, self, dirty, self._wcrev(), new):
730 if _updateprompt(self._ui, self, dirty, self._wcrev(), new):
724 self.get(state, False)
731 self.get(state, False)
725
732
726 def push(self, force):
733 def push(self, force):
727 # push is a no-op for SVN
734 # push is a no-op for SVN
728 return True
735 return True
729
736
730 def files(self):
737 def files(self):
731 output = self._svncommand(['list'])
738 output = self._svncommand(['list'])
732 # This works because svn forbids \n in filenames.
739 # This works because svn forbids \n in filenames.
733 return output.splitlines()
740 return output.splitlines()
734
741
735 def filedata(self, name):
742 def filedata(self, name):
736 return self._svncommand(['cat'], name)
743 return self._svncommand(['cat'], name)
737
744
738
745
739 class gitsubrepo(abstractsubrepo):
746 class gitsubrepo(abstractsubrepo):
740 def __init__(self, ctx, path, state):
747 def __init__(self, ctx, path, state):
741 # TODO add git version check.
748 # TODO add git version check.
742 self._state = state
749 self._state = state
743 self._ctx = ctx
750 self._ctx = ctx
744 self._path = path
751 self._path = path
745 self._relpath = os.path.join(reporelpath(ctx._repo), path)
752 self._relpath = os.path.join(reporelpath(ctx._repo), path)
746 self._abspath = ctx._repo.wjoin(path)
753 self._abspath = ctx._repo.wjoin(path)
747 self._subparent = ctx._repo
754 self._subparent = ctx._repo
748 self._ui = ctx._repo.ui
755 self._ui = ctx._repo.ui
749
756
750 def _gitcommand(self, commands, env=None, stream=False):
757 def _gitcommand(self, commands, env=None, stream=False):
751 return self._gitdir(commands, env=env, stream=stream)[0]
758 return self._gitdir(commands, env=env, stream=stream)[0]
752
759
753 def _gitdir(self, commands, env=None, stream=False):
760 def _gitdir(self, commands, env=None, stream=False):
754 return self._gitnodir(commands, env=env, stream=stream,
761 return self._gitnodir(commands, env=env, stream=stream,
755 cwd=self._abspath)
762 cwd=self._abspath)
756
763
757 def _gitnodir(self, commands, env=None, stream=False, cwd=None):
764 def _gitnodir(self, commands, env=None, stream=False, cwd=None):
758 """Calls the git command
765 """Calls the git command
759
766
760 The methods tries to call the git command. versions previor to 1.6.0
767 The methods tries to call the git command. versions previor to 1.6.0
761 are not supported and very probably fail.
768 are not supported and very probably fail.
762 """
769 """
763 self._ui.debug('%s: git %s\n' % (self._relpath, ' '.join(commands)))
770 self._ui.debug('%s: git %s\n' % (self._relpath, ' '.join(commands)))
764 # unless ui.quiet is set, print git's stderr,
771 # unless ui.quiet is set, print git's stderr,
765 # which is mostly progress and useful info
772 # which is mostly progress and useful info
766 errpipe = None
773 errpipe = None
767 if self._ui.quiet:
774 if self._ui.quiet:
768 errpipe = open(os.devnull, 'w')
775 errpipe = open(os.devnull, 'w')
769 p = subprocess.Popen(['git'] + commands, bufsize=-1, cwd=cwd, env=env,
776 p = subprocess.Popen(['git'] + commands, bufsize=-1, cwd=cwd, env=env,
770 close_fds=util.closefds,
777 close_fds=util.closefds,
771 stdout=subprocess.PIPE, stderr=errpipe)
778 stdout=subprocess.PIPE, stderr=errpipe)
772 if stream:
779 if stream:
773 return p.stdout, None
780 return p.stdout, None
774
781
775 retdata = p.stdout.read().strip()
782 retdata = p.stdout.read().strip()
776 # wait for the child to exit to avoid race condition.
783 # wait for the child to exit to avoid race condition.
777 p.wait()
784 p.wait()
778
785
779 if p.returncode != 0 and p.returncode != 1:
786 if p.returncode != 0 and p.returncode != 1:
780 # there are certain error codes that are ok
787 # there are certain error codes that are ok
781 command = commands[0]
788 command = commands[0]
782 if command in ('cat-file', 'symbolic-ref'):
789 if command in ('cat-file', 'symbolic-ref'):
783 return retdata, p.returncode
790 return retdata, p.returncode
784 # for all others, abort
791 # for all others, abort
785 raise util.Abort('git %s error %d in %s' %
792 raise util.Abort('git %s error %d in %s' %
786 (command, p.returncode, self._relpath))
793 (command, p.returncode, self._relpath))
787
794
788 return retdata, p.returncode
795 return retdata, p.returncode
789
796
790 def _gitmissing(self):
797 def _gitmissing(self):
791 return not os.path.exists(os.path.join(self._abspath, '.git'))
798 return not os.path.exists(os.path.join(self._abspath, '.git'))
792
799
793 def _gitstate(self):
800 def _gitstate(self):
794 return self._gitcommand(['rev-parse', 'HEAD'])
801 return self._gitcommand(['rev-parse', 'HEAD'])
795
802
796 def _gitcurrentbranch(self):
803 def _gitcurrentbranch(self):
797 current, err = self._gitdir(['symbolic-ref', 'HEAD', '--quiet'])
804 current, err = self._gitdir(['symbolic-ref', 'HEAD', '--quiet'])
798 if err:
805 if err:
799 current = None
806 current = None
800 return current
807 return current
801
808
802 def _gitremote(self, remote):
809 def _gitremote(self, remote):
803 out = self._gitcommand(['remote', 'show', '-n', remote])
810 out = self._gitcommand(['remote', 'show', '-n', remote])
804 line = out.split('\n')[1]
811 line = out.split('\n')[1]
805 i = line.index('URL: ') + len('URL: ')
812 i = line.index('URL: ') + len('URL: ')
806 return line[i:]
813 return line[i:]
807
814
808 def _githavelocally(self, revision):
815 def _githavelocally(self, revision):
809 out, code = self._gitdir(['cat-file', '-e', revision])
816 out, code = self._gitdir(['cat-file', '-e', revision])
810 return code == 0
817 return code == 0
811
818
812 def _gitisancestor(self, r1, r2):
819 def _gitisancestor(self, r1, r2):
813 base = self._gitcommand(['merge-base', r1, r2])
820 base = self._gitcommand(['merge-base', r1, r2])
814 return base == r1
821 return base == r1
815
822
816 def _gitisbare(self):
823 def _gitisbare(self):
817 return self._gitcommand(['config', '--bool', 'core.bare']) == 'true'
824 return self._gitcommand(['config', '--bool', 'core.bare']) == 'true'
818
825
819 def _gitbranchmap(self):
826 def _gitbranchmap(self):
820 '''returns 2 things:
827 '''returns 2 things:
821 a map from git branch to revision
828 a map from git branch to revision
822 a map from revision to branches'''
829 a map from revision to branches'''
823 branch2rev = {}
830 branch2rev = {}
824 rev2branch = {}
831 rev2branch = {}
825
832
826 out = self._gitcommand(['for-each-ref', '--format',
833 out = self._gitcommand(['for-each-ref', '--format',
827 '%(objectname) %(refname)'])
834 '%(objectname) %(refname)'])
828 for line in out.split('\n'):
835 for line in out.split('\n'):
829 revision, ref = line.split(' ')
836 revision, ref = line.split(' ')
830 if (not ref.startswith('refs/heads/') and
837 if (not ref.startswith('refs/heads/') and
831 not ref.startswith('refs/remotes/')):
838 not ref.startswith('refs/remotes/')):
832 continue
839 continue
833 if ref.startswith('refs/remotes/') and ref.endswith('/HEAD'):
840 if ref.startswith('refs/remotes/') and ref.endswith('/HEAD'):
834 continue # ignore remote/HEAD redirects
841 continue # ignore remote/HEAD redirects
835 branch2rev[ref] = revision
842 branch2rev[ref] = revision
836 rev2branch.setdefault(revision, []).append(ref)
843 rev2branch.setdefault(revision, []).append(ref)
837 return branch2rev, rev2branch
844 return branch2rev, rev2branch
838
845
839 def _gittracking(self, branches):
846 def _gittracking(self, branches):
840 'return map of remote branch to local tracking branch'
847 'return map of remote branch to local tracking branch'
841 # assumes no more than one local tracking branch for each remote
848 # assumes no more than one local tracking branch for each remote
842 tracking = {}
849 tracking = {}
843 for b in branches:
850 for b in branches:
844 if b.startswith('refs/remotes/'):
851 if b.startswith('refs/remotes/'):
845 continue
852 continue
846 bname = b.split('/', 2)[2]
853 bname = b.split('/', 2)[2]
847 remote = self._gitcommand(['config', 'branch.%s.remote' % bname])
854 remote = self._gitcommand(['config', 'branch.%s.remote' % bname])
848 if remote:
855 if remote:
849 ref = self._gitcommand(['config', 'branch.%s.merge' % bname])
856 ref = self._gitcommand(['config', 'branch.%s.merge' % bname])
850 tracking['refs/remotes/%s/%s' %
857 tracking['refs/remotes/%s/%s' %
851 (remote, ref.split('/', 2)[2])] = b
858 (remote, ref.split('/', 2)[2])] = b
852 return tracking
859 return tracking
853
860
854 def _abssource(self, source):
861 def _abssource(self, source):
855 if '://' not in source:
862 if '://' not in source:
856 # recognize the scp syntax as an absolute source
863 # recognize the scp syntax as an absolute source
857 colon = source.find(':')
864 colon = source.find(':')
858 if colon != -1 and '/' not in source[:colon]:
865 if colon != -1 and '/' not in source[:colon]:
859 return source
866 return source
860 self._subsource = source
867 self._subsource = source
861 return _abssource(self)
868 return _abssource(self)
862
869
863 def _fetch(self, source, revision):
870 def _fetch(self, source, revision):
864 if self._gitmissing():
871 if self._gitmissing():
865 source = self._abssource(source)
872 source = self._abssource(source)
866 self._ui.status(_('cloning subrepo %s from %s\n') %
873 self._ui.status(_('cloning subrepo %s from %s\n') %
867 (self._relpath, source))
874 (self._relpath, source))
868 self._gitnodir(['clone', source, self._abspath])
875 self._gitnodir(['clone', source, self._abspath])
869 if self._githavelocally(revision):
876 if self._githavelocally(revision):
870 return
877 return
871 self._ui.status(_('pulling subrepo %s from %s\n') %
878 self._ui.status(_('pulling subrepo %s from %s\n') %
872 (self._relpath, self._gitremote('origin')))
879 (self._relpath, self._gitremote('origin')))
873 # try only origin: the originally cloned repo
880 # try only origin: the originally cloned repo
874 self._gitcommand(['fetch'])
881 self._gitcommand(['fetch'])
875 if not self._githavelocally(revision):
882 if not self._githavelocally(revision):
876 raise util.Abort(_("revision %s does not exist in subrepo %s\n") %
883 raise util.Abort(_("revision %s does not exist in subrepo %s\n") %
877 (revision, self._relpath))
884 (revision, self._relpath))
878
885
879 def dirty(self, ignoreupdate=False):
886 def dirty(self, ignoreupdate=False):
880 if self._gitmissing():
887 if self._gitmissing():
881 return self._state[1] != ''
888 return self._state[1] != ''
882 if self._gitisbare():
889 if self._gitisbare():
883 return True
890 return True
884 if not ignoreupdate and self._state[1] != self._gitstate():
891 if not ignoreupdate and self._state[1] != self._gitstate():
885 # different version checked out
892 # different version checked out
886 return True
893 return True
887 # check for staged changes or modified files; ignore untracked files
894 # check for staged changes or modified files; ignore untracked files
888 out, code = self._gitdir(['diff-index', '--quiet', 'HEAD'])
895 out, code = self._gitdir(['diff-index', '--quiet', 'HEAD'])
889 return code == 1
896 return code == 1
890
897
891 def get(self, state, overwrite=False):
898 def get(self, state, overwrite=False):
892 source, revision, kind = state
899 source, revision, kind = state
893 if not revision:
900 if not revision:
894 self.remove()
901 self.remove()
895 return
902 return
896 self._fetch(source, revision)
903 self._fetch(source, revision)
897 # if the repo was set to be bare, unbare it
904 # if the repo was set to be bare, unbare it
898 if self._gitisbare():
905 if self._gitisbare():
899 self._gitcommand(['config', 'core.bare', 'false'])
906 self._gitcommand(['config', 'core.bare', 'false'])
900 if self._gitstate() == revision:
907 if self._gitstate() == revision:
901 self._gitcommand(['reset', '--hard', 'HEAD'])
908 self._gitcommand(['reset', '--hard', 'HEAD'])
902 return
909 return
903 elif self._gitstate() == revision:
910 elif self._gitstate() == revision:
904 if overwrite:
911 if overwrite:
905 # first reset the index to unmark new files for commit, because
912 # first reset the index to unmark new files for commit, because
906 # reset --hard will otherwise throw away files added for commit,
913 # reset --hard will otherwise throw away files added for commit,
907 # not just unmark them.
914 # not just unmark them.
908 self._gitcommand(['reset', 'HEAD'])
915 self._gitcommand(['reset', 'HEAD'])
909 self._gitcommand(['reset', '--hard', 'HEAD'])
916 self._gitcommand(['reset', '--hard', 'HEAD'])
910 return
917 return
911 branch2rev, rev2branch = self._gitbranchmap()
918 branch2rev, rev2branch = self._gitbranchmap()
912
919
913 def checkout(args):
920 def checkout(args):
914 cmd = ['checkout']
921 cmd = ['checkout']
915 if overwrite:
922 if overwrite:
916 # first reset the index to unmark new files for commit, because
923 # first reset the index to unmark new files for commit, because
917 # the -f option will otherwise throw away files added for
924 # the -f option will otherwise throw away files added for
918 # commit, not just unmark them.
925 # commit, not just unmark them.
919 self._gitcommand(['reset', 'HEAD'])
926 self._gitcommand(['reset', 'HEAD'])
920 cmd.append('-f')
927 cmd.append('-f')
921 self._gitcommand(cmd + args)
928 self._gitcommand(cmd + args)
922
929
923 def rawcheckout():
930 def rawcheckout():
924 # no branch to checkout, check it out with no branch
931 # no branch to checkout, check it out with no branch
925 self._ui.warn(_('checking out detached HEAD in subrepo %s\n') %
932 self._ui.warn(_('checking out detached HEAD in subrepo %s\n') %
926 self._relpath)
933 self._relpath)
927 self._ui.warn(_('check out a git branch if you intend '
934 self._ui.warn(_('check out a git branch if you intend '
928 'to make changes\n'))
935 'to make changes\n'))
929 checkout(['-q', revision])
936 checkout(['-q', revision])
930
937
931 if revision not in rev2branch:
938 if revision not in rev2branch:
932 rawcheckout()
939 rawcheckout()
933 return
940 return
934 branches = rev2branch[revision]
941 branches = rev2branch[revision]
935 firstlocalbranch = None
942 firstlocalbranch = None
936 for b in branches:
943 for b in branches:
937 if b == 'refs/heads/master':
944 if b == 'refs/heads/master':
938 # master trumps all other branches
945 # master trumps all other branches
939 checkout(['refs/heads/master'])
946 checkout(['refs/heads/master'])
940 return
947 return
941 if not firstlocalbranch and not b.startswith('refs/remotes/'):
948 if not firstlocalbranch and not b.startswith('refs/remotes/'):
942 firstlocalbranch = b
949 firstlocalbranch = b
943 if firstlocalbranch:
950 if firstlocalbranch:
944 checkout([firstlocalbranch])
951 checkout([firstlocalbranch])
945 return
952 return
946
953
947 tracking = self._gittracking(branch2rev.keys())
954 tracking = self._gittracking(branch2rev.keys())
948 # choose a remote branch already tracked if possible
955 # choose a remote branch already tracked if possible
949 remote = branches[0]
956 remote = branches[0]
950 if remote not in tracking:
957 if remote not in tracking:
951 for b in branches:
958 for b in branches:
952 if b in tracking:
959 if b in tracking:
953 remote = b
960 remote = b
954 break
961 break
955
962
956 if remote not in tracking:
963 if remote not in tracking:
957 # create a new local tracking branch
964 # create a new local tracking branch
958 local = remote.split('/', 2)[2]
965 local = remote.split('/', 2)[2]
959 checkout(['-b', local, remote])
966 checkout(['-b', local, remote])
960 elif self._gitisancestor(branch2rev[tracking[remote]], remote):
967 elif self._gitisancestor(branch2rev[tracking[remote]], remote):
961 # When updating to a tracked remote branch,
968 # When updating to a tracked remote branch,
962 # if the local tracking branch is downstream of it,
969 # if the local tracking branch is downstream of it,
963 # a normal `git pull` would have performed a "fast-forward merge"
970 # a normal `git pull` would have performed a "fast-forward merge"
964 # which is equivalent to updating the local branch to the remote.
971 # which is equivalent to updating the local branch to the remote.
965 # Since we are only looking at branching at update, we need to
972 # Since we are only looking at branching at update, we need to
966 # detect this situation and perform this action lazily.
973 # detect this situation and perform this action lazily.
967 if tracking[remote] != self._gitcurrentbranch():
974 if tracking[remote] != self._gitcurrentbranch():
968 checkout([tracking[remote]])
975 checkout([tracking[remote]])
969 self._gitcommand(['merge', '--ff', remote])
976 self._gitcommand(['merge', '--ff', remote])
970 else:
977 else:
971 # a real merge would be required, just checkout the revision
978 # a real merge would be required, just checkout the revision
972 rawcheckout()
979 rawcheckout()
973
980
974 def commit(self, text, user, date):
981 def commit(self, text, user, date):
975 if self._gitmissing():
982 if self._gitmissing():
976 raise util.Abort(_("subrepo %s is missing") % self._relpath)
983 raise util.Abort(_("subrepo %s is missing") % self._relpath)
977 cmd = ['commit', '-a', '-m', text]
984 cmd = ['commit', '-a', '-m', text]
978 env = os.environ.copy()
985 env = os.environ.copy()
979 if user:
986 if user:
980 cmd += ['--author', user]
987 cmd += ['--author', user]
981 if date:
988 if date:
982 # git's date parser silently ignores when seconds < 1e9
989 # git's date parser silently ignores when seconds < 1e9
983 # convert to ISO8601
990 # convert to ISO8601
984 env['GIT_AUTHOR_DATE'] = util.datestr(date,
991 env['GIT_AUTHOR_DATE'] = util.datestr(date,
985 '%Y-%m-%dT%H:%M:%S %1%2')
992 '%Y-%m-%dT%H:%M:%S %1%2')
986 self._gitcommand(cmd, env=env)
993 self._gitcommand(cmd, env=env)
987 # make sure commit works otherwise HEAD might not exist under certain
994 # make sure commit works otherwise HEAD might not exist under certain
988 # circumstances
995 # circumstances
989 return self._gitstate()
996 return self._gitstate()
990
997
991 def merge(self, state):
998 def merge(self, state):
992 source, revision, kind = state
999 source, revision, kind = state
993 self._fetch(source, revision)
1000 self._fetch(source, revision)
994 base = self._gitcommand(['merge-base', revision, self._state[1]])
1001 base = self._gitcommand(['merge-base', revision, self._state[1]])
995 out, code = self._gitdir(['diff-index', '--quiet', 'HEAD'])
1002 out, code = self._gitdir(['diff-index', '--quiet', 'HEAD'])
996
1003
997 def mergefunc():
1004 def mergefunc():
998 if base == revision:
1005 if base == revision:
999 self.get(state) # fast forward merge
1006 self.get(state) # fast forward merge
1000 elif base != self._state[1]:
1007 elif base != self._state[1]:
1001 self._gitcommand(['merge', '--no-commit', revision])
1008 self._gitcommand(['merge', '--no-commit', revision])
1002
1009
1003 if self.dirty():
1010 if self.dirty():
1004 if self._gitstate() != revision:
1011 if self._gitstate() != revision:
1005 dirty = self._gitstate() == self._state[1] or code != 0
1012 dirty = self._gitstate() == self._state[1] or code != 0
1006 if _updateprompt(self._ui, self, dirty,
1013 if _updateprompt(self._ui, self, dirty,
1007 self._state[1][:7], revision[:7]):
1014 self._state[1][:7], revision[:7]):
1008 mergefunc()
1015 mergefunc()
1009 else:
1016 else:
1010 mergefunc()
1017 mergefunc()
1011
1018
1012 def push(self, force):
1019 def push(self, force):
1013 if not self._state[1]:
1020 if not self._state[1]:
1014 return True
1021 return True
1015 if self._gitmissing():
1022 if self._gitmissing():
1016 raise util.Abort(_("subrepo %s is missing") % self._relpath)
1023 raise util.Abort(_("subrepo %s is missing") % self._relpath)
1017 # if a branch in origin contains the revision, nothing to do
1024 # if a branch in origin contains the revision, nothing to do
1018 branch2rev, rev2branch = self._gitbranchmap()
1025 branch2rev, rev2branch = self._gitbranchmap()
1019 if self._state[1] in rev2branch:
1026 if self._state[1] in rev2branch:
1020 for b in rev2branch[self._state[1]]:
1027 for b in rev2branch[self._state[1]]:
1021 if b.startswith('refs/remotes/origin/'):
1028 if b.startswith('refs/remotes/origin/'):
1022 return True
1029 return True
1023 for b, revision in branch2rev.iteritems():
1030 for b, revision in branch2rev.iteritems():
1024 if b.startswith('refs/remotes/origin/'):
1031 if b.startswith('refs/remotes/origin/'):
1025 if self._gitisancestor(self._state[1], revision):
1032 if self._gitisancestor(self._state[1], revision):
1026 return True
1033 return True
1027 # otherwise, try to push the currently checked out branch
1034 # otherwise, try to push the currently checked out branch
1028 cmd = ['push']
1035 cmd = ['push']
1029 if force:
1036 if force:
1030 cmd.append('--force')
1037 cmd.append('--force')
1031
1038
1032 current = self._gitcurrentbranch()
1039 current = self._gitcurrentbranch()
1033 if current:
1040 if current:
1034 # determine if the current branch is even useful
1041 # determine if the current branch is even useful
1035 if not self._gitisancestor(self._state[1], current):
1042 if not self._gitisancestor(self._state[1], current):
1036 self._ui.warn(_('unrelated git branch checked out '
1043 self._ui.warn(_('unrelated git branch checked out '
1037 'in subrepo %s\n') % self._relpath)
1044 'in subrepo %s\n') % self._relpath)
1038 return False
1045 return False
1039 self._ui.status(_('pushing branch %s of subrepo %s\n') %
1046 self._ui.status(_('pushing branch %s of subrepo %s\n') %
1040 (current.split('/', 2)[2], self._relpath))
1047 (current.split('/', 2)[2], self._relpath))
1041 self._gitcommand(cmd + ['origin', current])
1048 self._gitcommand(cmd + ['origin', current])
1042 return True
1049 return True
1043 else:
1050 else:
1044 self._ui.warn(_('no branch checked out in subrepo %s\n'
1051 self._ui.warn(_('no branch checked out in subrepo %s\n'
1045 'cannot push revision %s') %
1052 'cannot push revision %s') %
1046 (self._relpath, self._state[1]))
1053 (self._relpath, self._state[1]))
1047 return False
1054 return False
1048
1055
1049 def remove(self):
1056 def remove(self):
1050 if self._gitmissing():
1057 if self._gitmissing():
1051 return
1058 return
1052 if self.dirty():
1059 if self.dirty():
1053 self._ui.warn(_('not removing repo %s because '
1060 self._ui.warn(_('not removing repo %s because '
1054 'it has changes.\n') % self._relpath)
1061 'it has changes.\n') % self._relpath)
1055 return
1062 return
1056 # we can't fully delete the repository as it may contain
1063 # we can't fully delete the repository as it may contain
1057 # local-only history
1064 # local-only history
1058 self._ui.note(_('removing subrepo %s\n') % self._relpath)
1065 self._ui.note(_('removing subrepo %s\n') % self._relpath)
1059 self._gitcommand(['config', 'core.bare', 'true'])
1066 self._gitcommand(['config', 'core.bare', 'true'])
1060 for f in os.listdir(self._abspath):
1067 for f in os.listdir(self._abspath):
1061 if f == '.git':
1068 if f == '.git':
1062 continue
1069 continue
1063 path = os.path.join(self._abspath, f)
1070 path = os.path.join(self._abspath, f)
1064 if os.path.isdir(path) and not os.path.islink(path):
1071 if os.path.isdir(path) and not os.path.islink(path):
1065 shutil.rmtree(path)
1072 shutil.rmtree(path)
1066 else:
1073 else:
1067 os.remove(path)
1074 os.remove(path)
1068
1075
1069 def archive(self, ui, archiver, prefix):
1076 def archive(self, ui, archiver, prefix):
1070 source, revision = self._state
1077 source, revision = self._state
1071 if not revision:
1078 if not revision:
1072 return
1079 return
1073 self._fetch(source, revision)
1080 self._fetch(source, revision)
1074
1081
1075 # Parse git's native archive command.
1082 # Parse git's native archive command.
1076 # This should be much faster than manually traversing the trees
1083 # This should be much faster than manually traversing the trees
1077 # and objects with many subprocess calls.
1084 # and objects with many subprocess calls.
1078 tarstream = self._gitcommand(['archive', revision], stream=True)
1085 tarstream = self._gitcommand(['archive', revision], stream=True)
1079 tar = tarfile.open(fileobj=tarstream, mode='r|')
1086 tar = tarfile.open(fileobj=tarstream, mode='r|')
1080 relpath = subrelpath(self)
1087 relpath = subrelpath(self)
1081 ui.progress(_('archiving (%s)') % relpath, 0, unit=_('files'))
1088 ui.progress(_('archiving (%s)') % relpath, 0, unit=_('files'))
1082 for i, info in enumerate(tar):
1089 for i, info in enumerate(tar):
1083 if info.isdir():
1090 if info.isdir():
1084 continue
1091 continue
1085 if info.issym():
1092 if info.issym():
1086 data = info.linkname
1093 data = info.linkname
1087 else:
1094 else:
1088 data = tar.extractfile(info).read()
1095 data = tar.extractfile(info).read()
1089 archiver.addfile(os.path.join(prefix, self._path, info.name),
1096 archiver.addfile(os.path.join(prefix, self._path, info.name),
1090 info.mode, info.issym(), data)
1097 info.mode, info.issym(), data)
1091 ui.progress(_('archiving (%s)') % relpath, i + 1,
1098 ui.progress(_('archiving (%s)') % relpath, i + 1,
1092 unit=_('files'))
1099 unit=_('files'))
1093 ui.progress(_('archiving (%s)') % relpath, None)
1100 ui.progress(_('archiving (%s)') % relpath, None)
1094
1101
1095
1102
1096 def status(self, rev2, **opts):
1103 def status(self, rev2, **opts):
1097 rev1 = self._state[1]
1104 rev1 = self._state[1]
1098 if self._gitmissing() or not rev1:
1105 if self._gitmissing() or not rev1:
1099 # if the repo is missing, return no results
1106 # if the repo is missing, return no results
1100 return [], [], [], [], [], [], []
1107 return [], [], [], [], [], [], []
1101 modified, added, removed = [], [], []
1108 modified, added, removed = [], [], []
1102 if rev2:
1109 if rev2:
1103 command = ['diff-tree', rev1, rev2]
1110 command = ['diff-tree', rev1, rev2]
1104 else:
1111 else:
1105 command = ['diff-index', rev1]
1112 command = ['diff-index', rev1]
1106 out = self._gitcommand(command)
1113 out = self._gitcommand(command)
1107 for line in out.split('\n'):
1114 for line in out.split('\n'):
1108 tab = line.find('\t')
1115 tab = line.find('\t')
1109 if tab == -1:
1116 if tab == -1:
1110 continue
1117 continue
1111 status, f = line[tab - 1], line[tab + 1:]
1118 status, f = line[tab - 1], line[tab + 1:]
1112 if status == 'M':
1119 if status == 'M':
1113 modified.append(f)
1120 modified.append(f)
1114 elif status == 'A':
1121 elif status == 'A':
1115 added.append(f)
1122 added.append(f)
1116 elif status == 'D':
1123 elif status == 'D':
1117 removed.append(f)
1124 removed.append(f)
1118
1125
1119 deleted = unknown = ignored = clean = []
1126 deleted = unknown = ignored = clean = []
1120 return modified, added, removed, deleted, unknown, ignored, clean
1127 return modified, added, removed, deleted, unknown, ignored, clean
1121
1128
1122 types = {
1129 types = {
1123 'hg': hgsubrepo,
1130 'hg': hgsubrepo,
1124 'svn': svnsubrepo,
1131 'svn': svnsubrepo,
1125 'git': gitsubrepo,
1132 'git': gitsubrepo,
1126 }
1133 }
@@ -1,1017 +1,1017 b''
1 Let commit recurse into subrepos by default to match pre-2.0 behavior:
1 Let commit recurse into subrepos by default to match pre-2.0 behavior:
2
2
3 $ echo "[ui]" >> $HGRCPATH
3 $ echo "[ui]" >> $HGRCPATH
4 $ echo "commitsubrepos = Yes" >> $HGRCPATH
4 $ echo "commitsubrepos = Yes" >> $HGRCPATH
5
5
6 $ rm -rf sub
6 $ rm -rf sub
7 $ mkdir sub
7 $ mkdir sub
8 $ cd sub
8 $ cd sub
9 $ hg init t
9 $ hg init t
10 $ cd t
10 $ cd t
11
11
12 first revision, no sub
12 first revision, no sub
13
13
14 $ echo a > a
14 $ echo a > a
15 $ hg ci -Am0
15 $ hg ci -Am0
16 adding a
16 adding a
17
17
18 add first sub
18 add first sub
19
19
20 $ echo s = s > .hgsub
20 $ echo s = s > .hgsub
21 $ hg add .hgsub
21 $ hg add .hgsub
22 $ hg init s
22 $ hg init s
23 $ echo a > s/a
23 $ echo a > s/a
24
24
25 Issue2232: committing a subrepo without .hgsub
25 Issue2232: committing a subrepo without .hgsub
26
26
27 $ hg ci -mbad s
27 $ hg ci -mbad s
28 abort: can't commit subrepos without .hgsub
28 abort: can't commit subrepos without .hgsub
29 [255]
29 [255]
30
30
31 $ hg -R s ci -Ams0
31 $ hg -R s ci -Ams0
32 adding a
32 adding a
33 $ hg sum
33 $ hg sum
34 parent: 0:f7b1eb17ad24 tip
34 parent: 0:f7b1eb17ad24 tip
35 0
35 0
36 branch: default
36 branch: default
37 commit: 1 added, 1 subrepos
37 commit: 1 added, 1 subrepos
38 update: (current)
38 update: (current)
39 $ hg ci -m1
39 $ hg ci -m1
40 committing subrepository s
40 committing subrepository s
41
41
42 Revert can't (yet) revert subrepos:
42 Revert can't (yet) revert subrepos:
43
43
44 $ echo b > s/a
44 $ echo b > s/a
45 $ hg revert s
45 $ hg revert s
46 s: reverting subrepos is unsupported
46 s: reverting subrepos is unsupported
47
47
48 Revert currently ignores subrepos by default
48 Revert currently ignores subrepos by default
49
49
50 $ hg revert -a
50 $ hg revert -a
51 $ hg revert -R s -a -C
51 $ hg revert -R s -a -C
52 reverting s/a (glob)
52 reverting s/a (glob)
53
53
54 Issue2022: update -C
54 Issue2022: update -C
55
55
56 $ echo b > s/a
56 $ echo b > s/a
57 $ hg sum
57 $ hg sum
58 parent: 1:7cf8cfea66e4 tip
58 parent: 1:7cf8cfea66e4 tip
59 1
59 1
60 branch: default
60 branch: default
61 commit: 1 subrepos
61 commit: 1 subrepos
62 update: (current)
62 update: (current)
63 $ hg co -C 1
63 $ hg co -C 1
64 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
64 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
65 $ hg sum
65 $ hg sum
66 parent: 1:7cf8cfea66e4 tip
66 parent: 1:7cf8cfea66e4 tip
67 1
67 1
68 branch: default
68 branch: default
69 commit: (clean)
69 commit: (clean)
70 update: (current)
70 update: (current)
71
71
72 commands that require a clean repo should respect subrepos
72 commands that require a clean repo should respect subrepos
73
73
74 $ echo b >> s/a
74 $ echo b >> s/a
75 $ hg backout tip
75 $ hg backout tip
76 abort: uncommitted changes in subrepo s
76 abort: uncommitted changes in subrepo s
77 [255]
77 [255]
78 $ hg revert -C -R s s/a
78 $ hg revert -C -R s s/a
79
79
80 add sub sub
80 add sub sub
81
81
82 $ echo ss = ss > s/.hgsub
82 $ echo ss = ss > s/.hgsub
83 $ hg init s/ss
83 $ hg init s/ss
84 $ echo a > s/ss/a
84 $ echo a > s/ss/a
85 $ hg -R s add s/.hgsub
85 $ hg -R s add s/.hgsub
86 $ hg -R s/ss add s/ss/a
86 $ hg -R s/ss add s/ss/a
87 $ hg sum
87 $ hg sum
88 parent: 1:7cf8cfea66e4 tip
88 parent: 1:7cf8cfea66e4 tip
89 1
89 1
90 branch: default
90 branch: default
91 commit: 1 subrepos
91 commit: 1 subrepos
92 update: (current)
92 update: (current)
93 $ hg ci -m2
93 $ hg ci -m2
94 committing subrepository s
94 committing subrepository s
95 committing subrepository s/ss (glob)
95 committing subrepository s/ss (glob)
96 $ hg sum
96 $ hg sum
97 parent: 2:df30734270ae tip
97 parent: 2:df30734270ae tip
98 2
98 2
99 branch: default
99 branch: default
100 commit: (clean)
100 commit: (clean)
101 update: (current)
101 update: (current)
102
102
103 bump sub rev (and check it is ignored by ui.commitsubrepos)
103 bump sub rev (and check it is ignored by ui.commitsubrepos)
104
104
105 $ echo b > s/a
105 $ echo b > s/a
106 $ hg -R s ci -ms1
106 $ hg -R s ci -ms1
107 $ hg --config ui.commitsubrepos=no ci -m3
107 $ hg --config ui.commitsubrepos=no ci -m3
108 committing subrepository s
108 committing subrepository s
109
109
110 leave sub dirty (and check ui.commitsubrepos=no aborts the commit)
110 leave sub dirty (and check ui.commitsubrepos=no aborts the commit)
111
111
112 $ echo c > s/a
112 $ echo c > s/a
113 $ hg --config ui.commitsubrepos=no ci -m4
113 $ hg --config ui.commitsubrepos=no ci -m4
114 abort: uncommitted changes in subrepo s
114 abort: uncommitted changes in subrepo s
115 (use --subrepos for recursive commit)
115 (use --subrepos for recursive commit)
116 [255]
116 [255]
117 $ hg ci -m4
117 $ hg ci -m4
118 committing subrepository s
118 committing subrepository s
119 $ hg tip -R s
119 $ hg tip -R s
120 changeset: 3:1c833a7a9e3a
120 changeset: 3:1c833a7a9e3a
121 tag: tip
121 tag: tip
122 user: test
122 user: test
123 date: Thu Jan 01 00:00:00 1970 +0000
123 date: Thu Jan 01 00:00:00 1970 +0000
124 summary: 4
124 summary: 4
125
125
126
126
127 check caching
127 check caching
128
128
129 $ hg co 0
129 $ hg co 0
130 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
130 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
131 $ hg debugsub
131 $ hg debugsub
132
132
133 restore
133 restore
134
134
135 $ hg co
135 $ hg co
136 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
136 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
137 $ hg debugsub
137 $ hg debugsub
138 path s
138 path s
139 source s
139 source s
140 revision 1c833a7a9e3a4445c711aaf0f012379cd0d4034e
140 revision 1c833a7a9e3a4445c711aaf0f012379cd0d4034e
141
141
142 new branch for merge tests
142 new branch for merge tests
143
143
144 $ hg co 1
144 $ hg co 1
145 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
145 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
146 $ echo t = t >> .hgsub
146 $ echo t = t >> .hgsub
147 $ hg init t
147 $ hg init t
148 $ echo t > t/t
148 $ echo t > t/t
149 $ hg -R t add t
149 $ hg -R t add t
150 adding t/t (glob)
150 adding t/t (glob)
151
151
152 5
152 5
153
153
154 $ hg ci -m5 # add sub
154 $ hg ci -m5 # add sub
155 committing subrepository t
155 committing subrepository t
156 created new head
156 created new head
157 $ echo t2 > t/t
157 $ echo t2 > t/t
158
158
159 6
159 6
160
160
161 $ hg st -R s
161 $ hg st -R s
162 $ hg ci -m6 # change sub
162 $ hg ci -m6 # change sub
163 committing subrepository t
163 committing subrepository t
164 $ hg debugsub
164 $ hg debugsub
165 path s
165 path s
166 source s
166 source s
167 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
167 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
168 path t
168 path t
169 source t
169 source t
170 revision 6747d179aa9a688023c4b0cad32e4c92bb7f34ad
170 revision 6747d179aa9a688023c4b0cad32e4c92bb7f34ad
171 $ echo t3 > t/t
171 $ echo t3 > t/t
172
172
173 7
173 7
174
174
175 $ hg ci -m7 # change sub again for conflict test
175 $ hg ci -m7 # change sub again for conflict test
176 committing subrepository t
176 committing subrepository t
177 $ hg rm .hgsub
177 $ hg rm .hgsub
178
178
179 8
179 8
180
180
181 $ hg ci -m8 # remove sub
181 $ hg ci -m8 # remove sub
182
182
183 merge tests
183 merge tests
184
184
185 $ hg co -C 3
185 $ hg co -C 3
186 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
186 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
187 $ hg merge 5 # test adding
187 $ hg merge 5 # test adding
188 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
188 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
189 (branch merge, don't forget to commit)
189 (branch merge, don't forget to commit)
190 $ hg debugsub
190 $ hg debugsub
191 path s
191 path s
192 source s
192 source s
193 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
193 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
194 path t
194 path t
195 source t
195 source t
196 revision 60ca1237c19474e7a3978b0dc1ca4e6f36d51382
196 revision 60ca1237c19474e7a3978b0dc1ca4e6f36d51382
197 $ hg ci -m9
197 $ hg ci -m9
198 created new head
198 created new head
199 $ hg merge 6 --debug # test change
199 $ hg merge 6 --debug # test change
200 searching for copies back to rev 2
200 searching for copies back to rev 2
201 resolving manifests
201 resolving manifests
202 overwrite None partial False
202 overwrite None partial False
203 ancestor 1f14a2e2d3ec local f0d2028bf86d+ remote 1831e14459c4
203 ancestor 1f14a2e2d3ec local f0d2028bf86d+ remote 1831e14459c4
204 .hgsubstate: versions differ -> m
204 .hgsubstate: versions differ -> m
205 updating: .hgsubstate 1/1 files (100.00%)
205 updating: .hgsubstate 1/1 files (100.00%)
206 subrepo merge f0d2028bf86d+ 1831e14459c4 1f14a2e2d3ec
206 subrepo merge f0d2028bf86d+ 1831e14459c4 1f14a2e2d3ec
207 subrepo t: other changed, get t:6747d179aa9a688023c4b0cad32e4c92bb7f34ad:hg
207 subrepo t: other changed, get t:6747d179aa9a688023c4b0cad32e4c92bb7f34ad:hg
208 getting subrepo t
208 getting subrepo t
209 resolving manifests
209 resolving manifests
210 overwrite True partial False
210 overwrite True partial False
211 ancestor 60ca1237c194+ local 60ca1237c194+ remote 6747d179aa9a
211 ancestor 60ca1237c194+ local 60ca1237c194+ remote 6747d179aa9a
212 t: remote is newer -> g
212 t: remote is newer -> g
213 updating: t 1/1 files (100.00%)
213 updating: t 1/1 files (100.00%)
214 getting t
214 getting t
215 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
215 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
216 (branch merge, don't forget to commit)
216 (branch merge, don't forget to commit)
217 $ hg debugsub
217 $ hg debugsub
218 path s
218 path s
219 source s
219 source s
220 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
220 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
221 path t
221 path t
222 source t
222 source t
223 revision 6747d179aa9a688023c4b0cad32e4c92bb7f34ad
223 revision 6747d179aa9a688023c4b0cad32e4c92bb7f34ad
224 $ echo conflict > t/t
224 $ echo conflict > t/t
225 $ hg ci -m10
225 $ hg ci -m10
226 committing subrepository t
226 committing subrepository t
227 $ HGMERGE=internal:merge hg merge --debug 7 # test conflict
227 $ HGMERGE=internal:merge hg merge --debug 7 # test conflict
228 searching for copies back to rev 2
228 searching for copies back to rev 2
229 resolving manifests
229 resolving manifests
230 overwrite None partial False
230 overwrite None partial False
231 ancestor 1831e14459c4 local e45c8b14af55+ remote f94576341bcf
231 ancestor 1831e14459c4 local e45c8b14af55+ remote f94576341bcf
232 .hgsubstate: versions differ -> m
232 .hgsubstate: versions differ -> m
233 updating: .hgsubstate 1/1 files (100.00%)
233 updating: .hgsubstate 1/1 files (100.00%)
234 subrepo merge e45c8b14af55+ f94576341bcf 1831e14459c4
234 subrepo merge e45c8b14af55+ f94576341bcf 1831e14459c4
235 subrepo t: both sides changed, merge with t:7af322bc1198a32402fe903e0b7ebcfc5c9bf8f4:hg
235 subrepo t: both sides changed, merge with t:7af322bc1198a32402fe903e0b7ebcfc5c9bf8f4:hg
236 merging subrepo t
236 merging subrepo t
237 searching for copies back to rev 2
237 searching for copies back to rev 2
238 resolving manifests
238 resolving manifests
239 overwrite None partial False
239 overwrite None partial False
240 ancestor 6747d179aa9a local 20a0db6fbf6c+ remote 7af322bc1198
240 ancestor 6747d179aa9a local 20a0db6fbf6c+ remote 7af322bc1198
241 t: versions differ -> m
241 t: versions differ -> m
242 preserving t for resolve of t
242 preserving t for resolve of t
243 updating: t 1/1 files (100.00%)
243 updating: t 1/1 files (100.00%)
244 picked tool 'internal:merge' for t (binary False symlink False)
244 picked tool 'internal:merge' for t (binary False symlink False)
245 merging t
245 merging t
246 my t@20a0db6fbf6c+ other t@7af322bc1198 ancestor t@6747d179aa9a
246 my t@20a0db6fbf6c+ other t@7af322bc1198 ancestor t@6747d179aa9a
247 warning: conflicts during merge.
247 warning: conflicts during merge.
248 merging t failed!
248 merging t failed!
249 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
249 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
250 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
250 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
251 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
251 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
252 (branch merge, don't forget to commit)
252 (branch merge, don't forget to commit)
253
253
254 should conflict
254 should conflict
255
255
256 $ cat t/t
256 $ cat t/t
257 <<<<<<< local
257 <<<<<<< local
258 conflict
258 conflict
259 =======
259 =======
260 t3
260 t3
261 >>>>>>> other
261 >>>>>>> other
262
262
263 clone
263 clone
264
264
265 $ cd ..
265 $ cd ..
266 $ hg clone t tc
266 $ hg clone t tc
267 updating to branch default
267 updating to branch default
268 cloning subrepo s from $TESTTMP/sub/t/s (glob)
268 cloning subrepo s from $TESTTMP/sub/t/s (glob)
269 cloning subrepo s/ss from $TESTTMP/sub/t/s/ss (glob)
269 cloning subrepo s/ss from $TESTTMP/sub/t/s/ss (glob)
270 cloning subrepo t from $TESTTMP/sub/t/t (glob)
270 cloning subrepo t from $TESTTMP/sub/t/t (glob)
271 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
271 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
272 $ cd tc
272 $ cd tc
273 $ hg debugsub
273 $ hg debugsub
274 path s
274 path s
275 source s
275 source s
276 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
276 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
277 path t
277 path t
278 source t
278 source t
279 revision 20a0db6fbf6c3d2836e6519a642ae929bfc67c0e
279 revision 20a0db6fbf6c3d2836e6519a642ae929bfc67c0e
280
280
281 push
281 push
282
282
283 $ echo bah > t/t
283 $ echo bah > t/t
284 $ hg ci -m11
284 $ hg ci -m11
285 committing subrepository t
285 committing subrepository t
286 $ hg push
286 $ hg push
287 pushing to $TESTTMP/sub/t (glob)
287 pushing to $TESTTMP/sub/t (glob)
288 pushing subrepo s/ss to $TESTTMP/sub/t/s/ss (glob)
288 pushing subrepo s/ss to $TESTTMP/sub/t/s/ss (glob)
289 searching for changes
289 searching for changes
290 no changes found
290 no changes found
291 pushing subrepo s to $TESTTMP/sub/t/s (glob)
291 pushing subrepo s to $TESTTMP/sub/t/s (glob)
292 searching for changes
292 searching for changes
293 no changes found
293 no changes found
294 pushing subrepo t to $TESTTMP/sub/t/t (glob)
294 pushing subrepo t to $TESTTMP/sub/t/t (glob)
295 searching for changes
295 searching for changes
296 adding changesets
296 adding changesets
297 adding manifests
297 adding manifests
298 adding file changes
298 adding file changes
299 added 1 changesets with 1 changes to 1 files
299 added 1 changesets with 1 changes to 1 files
300 searching for changes
300 searching for changes
301 adding changesets
301 adding changesets
302 adding manifests
302 adding manifests
303 adding file changes
303 adding file changes
304 added 1 changesets with 1 changes to 1 files
304 added 1 changesets with 1 changes to 1 files
305
305
306 push -f
306 push -f
307
307
308 $ echo bah > s/a
308 $ echo bah > s/a
309 $ hg ci -m12
309 $ hg ci -m12
310 committing subrepository s
310 committing subrepository s
311 $ hg push
311 $ hg push
312 pushing to $TESTTMP/sub/t (glob)
312 pushing to $TESTTMP/sub/t (glob)
313 pushing subrepo s/ss to $TESTTMP/sub/t/s/ss (glob)
313 pushing subrepo s/ss to $TESTTMP/sub/t/s/ss (glob)
314 searching for changes
314 searching for changes
315 no changes found
315 no changes found
316 pushing subrepo s to $TESTTMP/sub/t/s (glob)
316 pushing subrepo s to $TESTTMP/sub/t/s (glob)
317 searching for changes
317 searching for changes
318 abort: push creates new remote head 12a213df6fa9!
318 abort: push creates new remote head 12a213df6fa9!
319 (did you forget to merge? use push -f to force)
319 (did you forget to merge? use push -f to force)
320 [255]
320 [255]
321 $ hg push -f
321 $ hg push -f
322 pushing to $TESTTMP/sub/t (glob)
322 pushing to $TESTTMP/sub/t (glob)
323 pushing subrepo s/ss to $TESTTMP/sub/t/s/ss (glob)
323 pushing subrepo s/ss to $TESTTMP/sub/t/s/ss (glob)
324 searching for changes
324 searching for changes
325 no changes found
325 no changes found
326 pushing subrepo s to $TESTTMP/sub/t/s (glob)
326 pushing subrepo s to $TESTTMP/sub/t/s (glob)
327 searching for changes
327 searching for changes
328 adding changesets
328 adding changesets
329 adding manifests
329 adding manifests
330 adding file changes
330 adding file changes
331 added 1 changesets with 1 changes to 1 files (+1 heads)
331 added 1 changesets with 1 changes to 1 files (+1 heads)
332 pushing subrepo t to $TESTTMP/sub/t/t (glob)
332 pushing subrepo t to $TESTTMP/sub/t/t (glob)
333 searching for changes
333 searching for changes
334 no changes found
334 no changes found
335 searching for changes
335 searching for changes
336 adding changesets
336 adding changesets
337 adding manifests
337 adding manifests
338 adding file changes
338 adding file changes
339 added 1 changesets with 1 changes to 1 files
339 added 1 changesets with 1 changes to 1 files
340
340
341 update
341 update
342
342
343 $ cd ../t
343 $ cd ../t
344 $ hg up -C # discard our earlier merge
344 $ hg up -C # discard our earlier merge
345 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
345 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
346 $ echo blah > t/t
346 $ echo blah > t/t
347 $ hg ci -m13
347 $ hg ci -m13
348 committing subrepository t
348 committing subrepository t
349
349
350 pull
350 pull
351
351
352 $ cd ../tc
352 $ cd ../tc
353 $ hg pull
353 $ hg pull
354 pulling from $TESTTMP/sub/t (glob)
354 pulling from $TESTTMP/sub/t (glob)
355 searching for changes
355 searching for changes
356 adding changesets
356 adding changesets
357 adding manifests
357 adding manifests
358 adding file changes
358 adding file changes
359 added 1 changesets with 1 changes to 1 files
359 added 1 changesets with 1 changes to 1 files
360 (run 'hg update' to get a working copy)
360 (run 'hg update' to get a working copy)
361
361
362 should pull t
362 should pull t
363
363
364 $ hg up
364 $ hg up
365 pulling subrepo t from $TESTTMP/sub/t/t (glob)
365 pulling subrepo t from $TESTTMP/sub/t/t (glob)
366 searching for changes
366 searching for changes
367 adding changesets
367 adding changesets
368 adding manifests
368 adding manifests
369 adding file changes
369 adding file changes
370 added 1 changesets with 1 changes to 1 files
370 added 1 changesets with 1 changes to 1 files
371 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
371 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
372 $ cat t/t
372 $ cat t/t
373 blah
373 blah
374
374
375 bogus subrepo path aborts
375 bogus subrepo path aborts
376
376
377 $ echo 'bogus=[boguspath' >> .hgsub
377 $ echo 'bogus=[boguspath' >> .hgsub
378 $ hg ci -m 'bogus subrepo path'
378 $ hg ci -m 'bogus subrepo path'
379 abort: missing ] in subrepo source
379 abort: missing ] in subrepo source
380 [255]
380 [255]
381
381
382 Issue1986: merge aborts when trying to merge a subrepo that
382 Issue1986: merge aborts when trying to merge a subrepo that
383 shouldn't need merging
383 shouldn't need merging
384
384
385 # subrepo layout
385 # subrepo layout
386 #
386 #
387 # o 5 br
387 # o 5 br
388 # /|
388 # /|
389 # o | 4 default
389 # o | 4 default
390 # | |
390 # | |
391 # | o 3 br
391 # | o 3 br
392 # |/|
392 # |/|
393 # o | 2 default
393 # o | 2 default
394 # | |
394 # | |
395 # | o 1 br
395 # | o 1 br
396 # |/
396 # |/
397 # o 0 default
397 # o 0 default
398
398
399 $ cd ..
399 $ cd ..
400 $ rm -rf sub
400 $ rm -rf sub
401 $ hg init main
401 $ hg init main
402 $ cd main
402 $ cd main
403 $ hg init s
403 $ hg init s
404 $ cd s
404 $ cd s
405 $ echo a > a
405 $ echo a > a
406 $ hg ci -Am1
406 $ hg ci -Am1
407 adding a
407 adding a
408 $ hg branch br
408 $ hg branch br
409 marked working directory as branch br
409 marked working directory as branch br
410 $ echo a >> a
410 $ echo a >> a
411 $ hg ci -m1
411 $ hg ci -m1
412 $ hg up default
412 $ hg up default
413 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
413 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
414 $ echo b > b
414 $ echo b > b
415 $ hg ci -Am1
415 $ hg ci -Am1
416 adding b
416 adding b
417 $ hg up br
417 $ hg up br
418 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
418 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
419 $ hg merge tip
419 $ hg merge tip
420 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
420 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
421 (branch merge, don't forget to commit)
421 (branch merge, don't forget to commit)
422 $ hg ci -m1
422 $ hg ci -m1
423 $ hg up 2
423 $ hg up 2
424 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
424 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
425 $ echo c > c
425 $ echo c > c
426 $ hg ci -Am1
426 $ hg ci -Am1
427 adding c
427 adding c
428 $ hg up 3
428 $ hg up 3
429 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
429 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
430 $ hg merge 4
430 $ hg merge 4
431 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
431 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
432 (branch merge, don't forget to commit)
432 (branch merge, don't forget to commit)
433 $ hg ci -m1
433 $ hg ci -m1
434
434
435 # main repo layout:
435 # main repo layout:
436 #
436 #
437 # * <-- try to merge default into br again
437 # * <-- try to merge default into br again
438 # .`|
438 # .`|
439 # . o 5 br --> substate = 5
439 # . o 5 br --> substate = 5
440 # . |
440 # . |
441 # o | 4 default --> substate = 4
441 # o | 4 default --> substate = 4
442 # | |
442 # | |
443 # | o 3 br --> substate = 2
443 # | o 3 br --> substate = 2
444 # |/|
444 # |/|
445 # o | 2 default --> substate = 2
445 # o | 2 default --> substate = 2
446 # | |
446 # | |
447 # | o 1 br --> substate = 3
447 # | o 1 br --> substate = 3
448 # |/
448 # |/
449 # o 0 default --> substate = 2
449 # o 0 default --> substate = 2
450
450
451 $ cd ..
451 $ cd ..
452 $ echo 's = s' > .hgsub
452 $ echo 's = s' > .hgsub
453 $ hg -R s up 2
453 $ hg -R s up 2
454 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
454 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
455 $ hg ci -Am1
455 $ hg ci -Am1
456 adding .hgsub
456 adding .hgsub
457 committing subrepository s
457 committing subrepository s
458 $ hg branch br
458 $ hg branch br
459 marked working directory as branch br
459 marked working directory as branch br
460 $ echo b > b
460 $ echo b > b
461 $ hg -R s up 3
461 $ hg -R s up 3
462 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
462 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
463 $ hg ci -Am1
463 $ hg ci -Am1
464 adding b
464 adding b
465 committing subrepository s
465 committing subrepository s
466 $ hg up default
466 $ hg up default
467 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
467 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
468 $ echo c > c
468 $ echo c > c
469 $ hg ci -Am1
469 $ hg ci -Am1
470 adding c
470 adding c
471 $ hg up 1
471 $ hg up 1
472 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
472 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
473 $ hg merge 2
473 $ hg merge 2
474 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
474 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
475 (branch merge, don't forget to commit)
475 (branch merge, don't forget to commit)
476 $ hg ci -m1
476 $ hg ci -m1
477 $ hg up 2
477 $ hg up 2
478 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
478 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
479 $ hg -R s up 4
479 $ hg -R s up 4
480 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
480 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
481 $ echo d > d
481 $ echo d > d
482 $ hg ci -Am1
482 $ hg ci -Am1
483 adding d
483 adding d
484 committing subrepository s
484 committing subrepository s
485 $ hg up 3
485 $ hg up 3
486 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
486 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
487 $ hg -R s up 5
487 $ hg -R s up 5
488 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
488 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
489 $ echo e > e
489 $ echo e > e
490 $ hg ci -Am1
490 $ hg ci -Am1
491 adding e
491 adding e
492 committing subrepository s
492 committing subrepository s
493
493
494 $ hg up 5
494 $ hg up 5
495 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
495 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
496 $ hg merge 4 # try to merge default into br again
496 $ hg merge 4 # try to merge default into br again
497 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
497 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
498 (branch merge, don't forget to commit)
498 (branch merge, don't forget to commit)
499 $ cd ..
499 $ cd ..
500
500
501 test subrepo delete from .hgsubstate
501 test subrepo delete from .hgsubstate
502
502
503 $ hg init testdelete
503 $ hg init testdelete
504 $ mkdir testdelete/nested testdelete/nested2
504 $ mkdir testdelete/nested testdelete/nested2
505 $ hg init testdelete/nested
505 $ hg init testdelete/nested
506 $ hg init testdelete/nested2
506 $ hg init testdelete/nested2
507 $ echo test > testdelete/nested/foo
507 $ echo test > testdelete/nested/foo
508 $ echo test > testdelete/nested2/foo
508 $ echo test > testdelete/nested2/foo
509 $ hg -R testdelete/nested add
509 $ hg -R testdelete/nested add
510 adding testdelete/nested/foo (glob)
510 adding testdelete/nested/foo (glob)
511 $ hg -R testdelete/nested2 add
511 $ hg -R testdelete/nested2 add
512 adding testdelete/nested2/foo (glob)
512 adding testdelete/nested2/foo (glob)
513 $ hg -R testdelete/nested ci -m test
513 $ hg -R testdelete/nested ci -m test
514 $ hg -R testdelete/nested2 ci -m test
514 $ hg -R testdelete/nested2 ci -m test
515 $ echo nested = nested > testdelete/.hgsub
515 $ echo nested = nested > testdelete/.hgsub
516 $ echo nested2 = nested2 >> testdelete/.hgsub
516 $ echo nested2 = nested2 >> testdelete/.hgsub
517 $ hg -R testdelete add
517 $ hg -R testdelete add
518 adding testdelete/.hgsub (glob)
518 adding testdelete/.hgsub (glob)
519 $ hg -R testdelete ci -m "nested 1 & 2 added"
519 $ hg -R testdelete ci -m "nested 1 & 2 added"
520 committing subrepository nested
520 committing subrepository nested
521 committing subrepository nested2
521 committing subrepository nested2
522 $ echo nested = nested > testdelete/.hgsub
522 $ echo nested = nested > testdelete/.hgsub
523 $ hg -R testdelete ci -m "nested 2 deleted"
523 $ hg -R testdelete ci -m "nested 2 deleted"
524 $ cat testdelete/.hgsubstate
524 $ cat testdelete/.hgsubstate
525 bdf5c9a3103743d900b12ae0db3ffdcfd7b0d878 nested
525 bdf5c9a3103743d900b12ae0db3ffdcfd7b0d878 nested
526 $ hg -R testdelete remove testdelete/.hgsub
526 $ hg -R testdelete remove testdelete/.hgsub
527 $ hg -R testdelete ci -m ".hgsub deleted"
527 $ hg -R testdelete ci -m ".hgsub deleted"
528 $ cat testdelete/.hgsubstate
528 $ cat testdelete/.hgsubstate
529 bdf5c9a3103743d900b12ae0db3ffdcfd7b0d878 nested
529 bdf5c9a3103743d900b12ae0db3ffdcfd7b0d878 nested
530
530
531 test repository cloning
531 test repository cloning
532
532
533 $ mkdir mercurial mercurial2
533 $ mkdir mercurial mercurial2
534 $ hg init nested_absolute
534 $ hg init nested_absolute
535 $ echo test > nested_absolute/foo
535 $ echo test > nested_absolute/foo
536 $ hg -R nested_absolute add
536 $ hg -R nested_absolute add
537 adding nested_absolute/foo (glob)
537 adding nested_absolute/foo (glob)
538 $ hg -R nested_absolute ci -mtest
538 $ hg -R nested_absolute ci -mtest
539 $ cd mercurial
539 $ cd mercurial
540 $ hg init nested_relative
540 $ hg init nested_relative
541 $ echo test2 > nested_relative/foo2
541 $ echo test2 > nested_relative/foo2
542 $ hg -R nested_relative add
542 $ hg -R nested_relative add
543 adding nested_relative/foo2 (glob)
543 adding nested_relative/foo2 (glob)
544 $ hg -R nested_relative ci -mtest2
544 $ hg -R nested_relative ci -mtest2
545 $ hg init main
545 $ hg init main
546 $ echo "nested_relative = ../nested_relative" > main/.hgsub
546 $ echo "nested_relative = ../nested_relative" > main/.hgsub
547 $ echo "nested_absolute = `pwd`/nested_absolute" >> main/.hgsub
547 $ echo "nested_absolute = `pwd`/nested_absolute" >> main/.hgsub
548 $ hg -R main add
548 $ hg -R main add
549 adding main/.hgsub (glob)
549 adding main/.hgsub (glob)
550 $ hg -R main ci -m "add subrepos"
550 $ hg -R main ci -m "add subrepos"
551 committing subrepository nested_absolute
551 committing subrepository nested_absolute
552 committing subrepository nested_relative
552 committing subrepository nested_relative
553 $ cd ..
553 $ cd ..
554 $ hg clone mercurial/main mercurial2/main
554 $ hg clone mercurial/main mercurial2/main
555 updating to branch default
555 updating to branch default
556 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
556 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
557 $ cat mercurial2/main/nested_absolute/.hg/hgrc \
557 $ cat mercurial2/main/nested_absolute/.hg/hgrc \
558 > mercurial2/main/nested_relative/.hg/hgrc
558 > mercurial2/main/nested_relative/.hg/hgrc
559 [paths]
559 [paths]
560 default = $TESTTMP/sub/mercurial/nested_absolute
560 default = $TESTTMP/sub/mercurial/nested_absolute
561 [paths]
561 [paths]
562 default = $TESTTMP/sub/mercurial/nested_relative
562 default = $TESTTMP/sub/mercurial/nested_relative
563 $ rm -rf mercurial mercurial2
563 $ rm -rf mercurial mercurial2
564
564
565 Issue1977: multirepo push should fail if subrepo push fails
565 Issue1977: multirepo push should fail if subrepo push fails
566
566
567 $ hg init repo
567 $ hg init repo
568 $ hg init repo/s
568 $ hg init repo/s
569 $ echo a > repo/s/a
569 $ echo a > repo/s/a
570 $ hg -R repo/s ci -Am0
570 $ hg -R repo/s ci -Am0
571 adding a
571 adding a
572 $ echo s = s > repo/.hgsub
572 $ echo s = s > repo/.hgsub
573 $ hg -R repo ci -Am1
573 $ hg -R repo ci -Am1
574 adding .hgsub
574 adding .hgsub
575 committing subrepository s
575 committing subrepository s
576 $ hg clone repo repo2
576 $ hg clone repo repo2
577 updating to branch default
577 updating to branch default
578 cloning subrepo s from $TESTTMP/sub/repo/s (glob)
578 cloning subrepo s from $TESTTMP/sub/repo/s (glob)
579 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
579 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
580 $ hg -q -R repo2 pull -u
580 $ hg -q -R repo2 pull -u
581 $ echo 1 > repo2/s/a
581 $ echo 1 > repo2/s/a
582 $ hg -R repo2/s ci -m2
582 $ hg -R repo2/s ci -m2
583 $ hg -q -R repo2/s push
583 $ hg -q -R repo2/s push
584 $ hg -R repo2/s up -C 0
584 $ hg -R repo2/s up -C 0
585 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
585 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
586 $ echo 2 > repo2/s/a
586 $ echo 2 > repo2/s/a
587 $ hg -R repo2/s ci -m3
587 $ hg -R repo2/s ci -m3
588 created new head
588 created new head
589 $ hg -R repo2 ci -m3
589 $ hg -R repo2 ci -m3
590 committing subrepository s
590 committing subrepository s
591 $ hg -q -R repo2 push
591 $ hg -q -R repo2 push
592 abort: push creates new remote head 9d66565e64e1!
592 abort: push creates new remote head 9d66565e64e1!
593 (did you forget to merge? use push -f to force)
593 (did you forget to merge? use push -f to force)
594 [255]
594 [255]
595 $ hg -R repo update
595 $ hg -R repo update
596 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
596 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
597 $ rm -rf repo2 repo
597 $ rm -rf repo2 repo
598
598
599
599
600 Issue1852 subrepos with relative paths always push/pull relative to default
600 Issue1852 subrepos with relative paths always push/pull relative to default
601
601
602 Prepare a repo with subrepo
602 Prepare a repo with subrepo
603
603
604 $ hg init issue1852a
604 $ hg init issue1852a
605 $ cd issue1852a
605 $ cd issue1852a
606 $ hg init sub/repo
606 $ hg init sub/repo
607 $ echo test > sub/repo/foo
607 $ echo test > sub/repo/foo
608 $ hg -R sub/repo add sub/repo/foo
608 $ hg -R sub/repo add sub/repo/foo
609 $ echo sub/repo = sub/repo > .hgsub
609 $ echo sub/repo = sub/repo > .hgsub
610 $ hg add .hgsub
610 $ hg add .hgsub
611 $ hg ci -mtest
611 $ hg ci -mtest
612 committing subrepository sub/repo (glob)
612 committing subrepository sub/repo (glob)
613 $ echo test >> sub/repo/foo
613 $ echo test >> sub/repo/foo
614 $ hg ci -mtest
614 $ hg ci -mtest
615 committing subrepository sub/repo (glob)
615 committing subrepository sub/repo (glob)
616 $ cd ..
616 $ cd ..
617
617
618 Create repo without default path, pull top repo, and see what happens on update
618 Create repo without default path, pull top repo, and see what happens on update
619
619
620 $ hg init issue1852b
620 $ hg init issue1852b
621 $ hg -R issue1852b pull issue1852a
621 $ hg -R issue1852b pull issue1852a
622 pulling from issue1852a
622 pulling from issue1852a
623 requesting all changes
623 requesting all changes
624 adding changesets
624 adding changesets
625 adding manifests
625 adding manifests
626 adding file changes
626 adding file changes
627 added 2 changesets with 3 changes to 2 files
627 added 2 changesets with 3 changes to 2 files
628 (run 'hg update' to get a working copy)
628 (run 'hg update' to get a working copy)
629 $ hg -R issue1852b update
629 $ hg -R issue1852b update
630 abort: default path for subrepository sub/repo not found (glob)
630 abort: default path for subrepository sub/repo not found (glob)
631 [255]
631 [255]
632
632
633 Pull -u now doesn't help
633 Pull -u now doesn't help
634
634
635 $ hg -R issue1852b pull -u issue1852a
635 $ hg -R issue1852b pull -u issue1852a
636 pulling from issue1852a
636 pulling from issue1852a
637 searching for changes
637 searching for changes
638 no changes found
638 no changes found
639
639
640 Try the same, but with pull -u
640 Try the same, but with pull -u
641
641
642 $ hg init issue1852c
642 $ hg init issue1852c
643 $ hg -R issue1852c pull -r0 -u issue1852a
643 $ hg -R issue1852c pull -r0 -u issue1852a
644 pulling from issue1852a
644 pulling from issue1852a
645 adding changesets
645 adding changesets
646 adding manifests
646 adding manifests
647 adding file changes
647 adding file changes
648 added 1 changesets with 2 changes to 2 files
648 added 1 changesets with 2 changes to 2 files
649 cloning subrepo sub/repo from issue1852a/sub/repo (glob)
649 cloning subrepo sub/repo from issue1852a/sub/repo (glob)
650 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
650 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
651
651
652 Try to push from the other side
652 Try to push from the other side
653
653
654 $ hg -R issue1852a push `pwd`/issue1852c
654 $ hg -R issue1852a push `pwd`/issue1852c
655 pushing to $TESTTMP/sub/issue1852c
655 pushing to $TESTTMP/sub/issue1852c
656 pushing subrepo sub/repo to $TESTTMP/sub/issue1852c/sub/repo (glob)
656 pushing subrepo sub/repo to $TESTTMP/sub/issue1852c/sub/repo (glob)
657 searching for changes
657 searching for changes
658 no changes found
658 no changes found
659 searching for changes
659 searching for changes
660 adding changesets
660 adding changesets
661 adding manifests
661 adding manifests
662 adding file changes
662 adding file changes
663 added 1 changesets with 1 changes to 1 files
663 added 1 changesets with 1 changes to 1 files
664
664
665 Incoming and outgoing should not use the default path:
665 Incoming and outgoing should not use the default path:
666
666
667 $ hg clone -q issue1852a issue1852d
667 $ hg clone -q issue1852a issue1852d
668 $ hg -R issue1852d outgoing --subrepos issue1852c
668 $ hg -R issue1852d outgoing --subrepos issue1852c
669 comparing with issue1852c
669 comparing with issue1852c
670 searching for changes
670 searching for changes
671 no changes found
671 no changes found
672 comparing with issue1852c/sub/repo
672 comparing with issue1852c/sub/repo
673 searching for changes
673 searching for changes
674 no changes found
674 no changes found
675 [1]
675 [1]
676 $ hg -R issue1852d incoming --subrepos issue1852c
676 $ hg -R issue1852d incoming --subrepos issue1852c
677 comparing with issue1852c
677 comparing with issue1852c
678 searching for changes
678 searching for changes
679 no changes found
679 no changes found
680 comparing with issue1852c/sub/repo
680 comparing with issue1852c/sub/repo
681 searching for changes
681 searching for changes
682 no changes found
682 no changes found
683 [1]
683 [1]
684
684
685 Check status of files when none of them belong to the first
685 Check status of files when none of them belong to the first
686 subrepository:
686 subrepository:
687
687
688 $ hg init subrepo-status
688 $ hg init subrepo-status
689 $ cd subrepo-status
689 $ cd subrepo-status
690 $ hg init subrepo-1
690 $ hg init subrepo-1
691 $ hg init subrepo-2
691 $ hg init subrepo-2
692 $ cd subrepo-2
692 $ cd subrepo-2
693 $ touch file
693 $ touch file
694 $ hg add file
694 $ hg add file
695 $ cd ..
695 $ cd ..
696 $ echo subrepo-1 = subrepo-1 > .hgsub
696 $ echo subrepo-1 = subrepo-1 > .hgsub
697 $ echo subrepo-2 = subrepo-2 >> .hgsub
697 $ echo subrepo-2 = subrepo-2 >> .hgsub
698 $ hg add .hgsub
698 $ hg add .hgsub
699 $ hg ci -m 'Added subrepos'
699 $ hg ci -m 'Added subrepos'
700 committing subrepository subrepo-1
700 committing subrepository subrepo-1
701 committing subrepository subrepo-2
701 committing subrepository subrepo-2
702 $ hg st subrepo-2/file
702 $ hg st subrepo-2/file
703
703
704 Check hg update --clean
704 Check hg update --clean
705 $ cd $TESTTMP/sub/t
705 $ cd $TESTTMP/sub/t
706 $ rm -r t/t.orig
706 $ rm -r t/t.orig
707 $ hg status -S --all
707 $ hg status -S --all
708 C .hgsub
708 C .hgsub
709 C .hgsubstate
709 C .hgsubstate
710 C a
710 C a
711 C s/.hgsub
711 C s/.hgsub
712 C s/.hgsubstate
712 C s/.hgsubstate
713 C s/a
713 C s/a
714 C s/ss/a
714 C s/ss/a
715 C t/t
715 C t/t
716 $ echo c1 > s/a
716 $ echo c1 > s/a
717 $ cd s
717 $ cd s
718 $ echo c1 > b
718 $ echo c1 > b
719 $ echo c1 > c
719 $ echo c1 > c
720 $ hg add b
720 $ hg add b
721 $ cd ..
721 $ cd ..
722 $ hg status -S
722 $ hg status -S
723 M s/a
723 M s/a
724 A s/b
724 A s/b
725 ? s/c
725 ? s/c
726 $ hg update -C
726 $ hg update -C
727 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
727 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
728 $ hg status -S
728 $ hg status -S
729 ? s/b
729 ? s/b
730 ? s/c
730 ? s/c
731
731
732 Sticky subrepositories, no changes
732 Sticky subrepositories, no changes
733 $ cd $TESTTMP/sub/t
733 $ cd $TESTTMP/sub/t
734 $ hg id
734 $ hg id
735 925c17564ef8 tip
735 925c17564ef8 tip
736 $ hg -R s id
736 $ hg -R s id
737 12a213df6fa9 tip
737 12a213df6fa9 tip
738 $ hg -R t id
738 $ hg -R t id
739 52c0adc0515a tip
739 52c0adc0515a tip
740 $ hg update 11
740 $ hg update 11
741 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
741 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
742 $ hg id
742 $ hg id
743 365661e5936a
743 365661e5936a
744 $ hg -R s id
744 $ hg -R s id
745 fc627a69481f
745 fc627a69481f
746 $ hg -R t id
746 $ hg -R t id
747 e95bcfa18a35
747 e95bcfa18a35
748
748
749 Sticky subrepositorys, file changes
749 Sticky subrepositorys, file changes
750 $ touch s/f1
750 $ touch s/f1
751 $ touch t/f1
751 $ touch t/f1
752 $ hg add -S s/f1
752 $ hg add -S s/f1
753 $ hg add -S t/f1
753 $ hg add -S t/f1
754 $ hg id
754 $ hg id
755 365661e5936a
755 365661e5936a
756 $ hg -R s id
756 $ hg -R s id
757 fc627a69481f+
757 fc627a69481f+
758 $ hg -R t id
758 $ hg -R t id
759 e95bcfa18a35+
759 e95bcfa18a35+
760 $ hg update tip
760 $ hg update tip
761 subrepository sources for s differ
761 subrepository sources for s differ
762 use (l)ocal source (fc627a69481f) or (r)emote source (12a213df6fa9)?
762 use (l)ocal source (fc627a69481f) or (r)emote source (12a213df6fa9)?
763 l
763 l
764 subrepository sources for t differ
764 subrepository sources for t differ
765 use (l)ocal source (e95bcfa18a35) or (r)emote source (52c0adc0515a)?
765 use (l)ocal source (e95bcfa18a35) or (r)emote source (52c0adc0515a)?
766 l
766 l
767 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
767 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
768 $ hg id
768 $ hg id
769 925c17564ef8+ tip
769 925c17564ef8+ tip
770 $ hg -R s id
770 $ hg -R s id
771 fc627a69481f+
771 fc627a69481f+
772 $ hg -R t id
772 $ hg -R t id
773 e95bcfa18a35+
773 e95bcfa18a35+
774 $ hg update --clean tip
774 $ hg update --clean tip
775 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
775 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
776
776
777 Sticky subrepository, revision updates
777 Sticky subrepository, revision updates
778 $ hg id
778 $ hg id
779 925c17564ef8 tip
779 925c17564ef8 tip
780 $ hg -R s id
780 $ hg -R s id
781 12a213df6fa9 tip
781 12a213df6fa9 tip
782 $ hg -R t id
782 $ hg -R t id
783 52c0adc0515a tip
783 52c0adc0515a tip
784 $ cd s
784 $ cd s
785 $ hg update -r -2
785 $ hg update -r -2
786 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
786 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
787 $ cd ../t
787 $ cd ../t
788 $ hg update -r 2
788 $ hg update -r 2
789 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
789 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
790 $ cd ..
790 $ cd ..
791 $ hg update 10
791 $ hg update 10
792 subrepository sources for t differ (in checked out version)
792 subrepository sources for t differ (in checked out version)
793 use (l)ocal source (7af322bc1198) or (r)emote source (20a0db6fbf6c)?
793 use (l)ocal source (7af322bc1198) or (r)emote source (20a0db6fbf6c)?
794 l
794 l
795 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
795 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
796 $ hg id
796 $ hg id
797 e45c8b14af55+
797 e45c8b14af55+
798 $ hg -R s id
798 $ hg -R s id
799 1c833a7a9e3a
799 1c833a7a9e3a
800 $ hg -R t id
800 $ hg -R t id
801 7af322bc1198
801 7af322bc1198
802
802
803 Sticky subrepository, file changes and revision updates
803 Sticky subrepository, file changes and revision updates
804 $ touch s/f1
804 $ touch s/f1
805 $ touch t/f1
805 $ touch t/f1
806 $ hg add -S s/f1
806 $ hg add -S s/f1
807 $ hg add -S t/f1
807 $ hg add -S t/f1
808 $ hg id
808 $ hg id
809 e45c8b14af55+
809 e45c8b14af55+
810 $ hg -R s id
810 $ hg -R s id
811 1c833a7a9e3a+
811 1c833a7a9e3a+
812 $ hg -R t id
812 $ hg -R t id
813 7af322bc1198+
813 7af322bc1198+
814 $ hg update tip
814 $ hg update tip
815 subrepository sources for s differ
815 subrepository sources for s differ
816 use (l)ocal source (1c833a7a9e3a) or (r)emote source (12a213df6fa9)?
816 use (l)ocal source (1c833a7a9e3a) or (r)emote source (12a213df6fa9)?
817 l
817 l
818 subrepository sources for t differ
818 subrepository sources for t differ
819 use (l)ocal source (7af322bc1198) or (r)emote source (52c0adc0515a)?
819 use (l)ocal source (7af322bc1198) or (r)emote source (52c0adc0515a)?
820 l
820 l
821 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
821 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
822 $ hg id
822 $ hg id
823 925c17564ef8 tip
823 925c17564ef8 tip
824 $ hg -R s id
824 $ hg -R s id
825 1c833a7a9e3a+
825 1c833a7a9e3a+
826 $ hg -R t id
826 $ hg -R t id
827 7af322bc1198+
827 7af322bc1198+
828
828
829 Sticky repository, update --clean
829 Sticky repository, update --clean
830 $ hg update --clean tip
830 $ hg update --clean tip
831 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
831 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
832 $ hg id
832 $ hg id
833 925c17564ef8 tip
833 925c17564ef8 tip
834 $ hg -R s id
834 $ hg -R s id
835 12a213df6fa9 tip
835 12a213df6fa9 tip
836 $ hg -R t id
836 $ hg -R t id
837 52c0adc0515a tip
837 52c0adc0515a tip
838
838
839 Test subrepo already at intended revision:
839 Test subrepo already at intended revision:
840 $ cd s
840 $ cd s
841 $ hg update fc627a69481f
841 $ hg update fc627a69481f
842 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
842 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
843 $ cd ..
843 $ cd ..
844 $ hg update 11
844 $ hg update 11
845 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
845 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
846 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
846 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
847 $ hg id -n
847 $ hg id -n
848 11+
848 11+
849 $ hg -R s id
849 $ hg -R s id
850 fc627a69481f
850 fc627a69481f
851 $ hg -R t id
851 $ hg -R t id
852 e95bcfa18a35
852 e95bcfa18a35
853
853
854 Test that removing .hgsubstate doesn't break anything:
854 Test that removing .hgsubstate doesn't break anything:
855
855
856 $ hg rm -f .hgsubstate
856 $ hg rm -f .hgsubstate
857 $ hg ci -mrm
857 $ hg ci -mrm
858 committing subrepository s
858 committing subrepository s
859 committing subrepository t
859 committing subrepository t
860 created new head
860 created new head
861 $ hg log -vr tip
861 $ hg log -vr tip
862 changeset: 14:3941e0aa5236
862 changeset: 14:3941e0aa5236
863 tag: tip
863 tag: tip
864 parent: 11:365661e5936a
864 parent: 11:365661e5936a
865 user: test
865 user: test
866 date: Thu Jan 01 00:00:00 1970 +0000
866 date: Thu Jan 01 00:00:00 1970 +0000
867 description:
867 description:
868 rm
868 rm
869
869
870
870
871
871
872 Test that removing .hgsub removes .hgsubstate:
872 Test that removing .hgsub removes .hgsubstate:
873
873
874 $ hg rm .hgsub
874 $ hg rm .hgsub
875 $ hg ci -mrm2
875 $ hg ci -mrm2
876 $ hg log -vr tip
876 $ hg log -vr tip
877 changeset: 15:8b31de9d13d1
877 changeset: 15:8b31de9d13d1
878 tag: tip
878 tag: tip
879 user: test
879 user: test
880 date: Thu Jan 01 00:00:00 1970 +0000
880 date: Thu Jan 01 00:00:00 1970 +0000
881 files: .hgsub .hgsubstate
881 files: .hgsub .hgsubstate
882 description:
882 description:
883 rm2
883 rm2
884
884
885
885
886 Test behavior of add for explicit path in subrepo:
886 Test behavior of add for explicit path in subrepo:
887 $ cd ..
887 $ cd ..
888 $ hg init explicit
888 $ hg init explicit
889 $ cd explicit
889 $ cd explicit
890 $ echo s = s > .hgsub
890 $ echo s = s > .hgsub
891 $ hg add .hgsub
891 $ hg add .hgsub
892 $ hg init s
892 $ hg init s
893 $ hg ci -m0
893 $ hg ci -m0
894 committing subrepository s
894 committing subrepository s
895 Adding with an explicit path in a subrepo adds the file
895 Adding with an explicit path in a subrepo adds the file
896 $ echo c1 > f1
896 $ echo c1 > f1
897 $ echo c2 > s/f2
897 $ echo c2 > s/f2
898 $ hg st -S
898 $ hg st -S
899 ? f1
899 ? f1
900 ? s/f2
900 ? s/f2
901 $ hg add s/f2
901 $ hg add s/f2
902 $ hg st -S
902 $ hg st -S
903 A s/f2
903 A s/f2
904 ? f1
904 ? f1
905 $ hg ci -R s -m0
905 $ hg ci -R s -m0
906 $ hg ci -Am1
906 $ hg ci -Am1
907 adding f1
907 adding f1
908 committing subrepository s
908 committing subrepository s
909 Adding with an explicit path in a subrepo with -S has the same behavior
909 Adding with an explicit path in a subrepo with -S has the same behavior
910 $ echo c3 > f3
910 $ echo c3 > f3
911 $ echo c4 > s/f4
911 $ echo c4 > s/f4
912 $ hg st -S
912 $ hg st -S
913 ? f3
913 ? f3
914 ? s/f4
914 ? s/f4
915 $ hg add -S s/f4
915 $ hg add -S s/f4
916 $ hg st -S
916 $ hg st -S
917 A s/f4
917 A s/f4
918 ? f3
918 ? f3
919 $ hg ci -R s -m1
919 $ hg ci -R s -m1
920 $ hg ci -Ama2
920 $ hg ci -Ama2
921 adding f3
921 adding f3
922 committing subrepository s
922 committing subrepository s
923 Adding without a path or pattern silently ignores subrepos
923 Adding without a path or pattern silently ignores subrepos
924 $ echo c5 > f5
924 $ echo c5 > f5
925 $ echo c6 > s/f6
925 $ echo c6 > s/f6
926 $ echo c7 > s/f7
926 $ echo c7 > s/f7
927 $ hg st -S
927 $ hg st -S
928 ? f5
928 ? f5
929 ? s/f6
929 ? s/f6
930 ? s/f7
930 ? s/f7
931 $ hg add
931 $ hg add
932 adding f5
932 adding f5
933 $ hg st -S
933 $ hg st -S
934 A f5
934 A f5
935 ? s/f6
935 ? s/f6
936 ? s/f7
936 ? s/f7
937 $ hg ci -R s -Am2
937 $ hg ci -R s -Am2
938 adding f6
938 adding f6
939 adding f7
939 adding f7
940 $ hg ci -m3
940 $ hg ci -m3
941 committing subrepository s
941 committing subrepository s
942 Adding without a path or pattern with -S also adds files in subrepos
942 Adding without a path or pattern with -S also adds files in subrepos
943 $ echo c8 > f8
943 $ echo c8 > f8
944 $ echo c9 > s/f9
944 $ echo c9 > s/f9
945 $ echo c10 > s/f10
945 $ echo c10 > s/f10
946 $ hg st -S
946 $ hg st -S
947 ? f8
947 ? f8
948 ? s/f10
948 ? s/f10
949 ? s/f9
949 ? s/f9
950 $ hg add -S
950 $ hg add -S
951 adding f8
951 adding f8
952 adding s/f10
952 adding s/f10
953 adding s/f9
953 adding s/f9
954 $ hg st -S
954 $ hg st -S
955 A f8
955 A f8
956 A s/f10
956 A s/f10
957 A s/f9
957 A s/f9
958 $ hg ci -R s -m3
958 $ hg ci -R s -m3
959 $ hg ci -m4
959 $ hg ci -m4
960 committing subrepository s
960 committing subrepository s
961 Adding with a pattern silently ignores subrepos
961 Adding with a pattern silently ignores subrepos
962 $ echo c11 > fm11
962 $ echo c11 > fm11
963 $ echo c12 > fn12
963 $ echo c12 > fn12
964 $ echo c13 > s/fm13
964 $ echo c13 > s/fm13
965 $ echo c14 > s/fn14
965 $ echo c14 > s/fn14
966 $ hg st -S
966 $ hg st -S
967 ? fm11
967 ? fm11
968 ? fn12
968 ? fn12
969 ? s/fm13
969 ? s/fm13
970 ? s/fn14
970 ? s/fn14
971 $ hg add 'glob:**fm*'
971 $ hg add 'glob:**fm*'
972 adding fm11
972 adding fm11
973 $ hg st -S
973 $ hg st -S
974 A fm11
974 A fm11
975 ? fn12
975 ? fn12
976 ? s/fm13
976 ? s/fm13
977 ? s/fn14
977 ? s/fn14
978 $ hg ci -R s -Am4
978 $ hg ci -R s -Am4
979 adding fm13
979 adding fm13
980 adding fn14
980 adding fn14
981 $ hg ci -Am5
981 $ hg ci -Am5
982 adding fn12
982 adding fn12
983 committing subrepository s
983 committing subrepository s
984 Adding with a pattern with -S also adds matches in subrepos
984 Adding with a pattern with -S also adds matches in subrepos
985 $ echo c15 > fm15
985 $ echo c15 > fm15
986 $ echo c16 > fn16
986 $ echo c16 > fn16
987 $ echo c17 > s/fm17
987 $ echo c17 > s/fm17
988 $ echo c18 > s/fn18
988 $ echo c18 > s/fn18
989 $ hg st -S
989 $ hg st -S
990 ? fm15
990 ? fm15
991 ? fn16
991 ? fn16
992 ? s/fm17
992 ? s/fm17
993 ? s/fn18
993 ? s/fn18
994 $ hg add -S 'glob:**fm*'
994 $ hg add -S 'glob:**fm*'
995 adding fm15
995 adding fm15
996 adding s/fm17
996 adding s/fm17
997 $ hg st -S
997 $ hg st -S
998 A fm15
998 A fm15
999 A s/fm17
999 A s/fm17
1000 ? fn16
1000 ? fn16
1001 ? s/fn18
1001 ? s/fn18
1002 $ hg ci -R s -Am5
1002 $ hg ci -R s -Am5
1003 adding fn18
1003 adding fn18
1004 $ hg ci -Am6
1004 $ hg ci -Am6
1005 adding fn16
1005 adding fn16
1006 committing subrepository s
1006 committing subrepository s
1007
1007
1008 Test behavior of forget for explicit path in subrepo:
1008 Test behavior of forget for explicit path in subrepo:
1009 Forgetting an explicit path in a subrepo currently gives a file untracked warn
1009 Forgetting an explicit path in a subrepo untracks the file
1010 $ echo c19 > s/f19
1010 $ echo c19 > s/f19
1011 $ hg add s/f19
1011 $ hg add s/f19
1012 $ hg st -S
1012 $ hg st -S
1013 A s/f19
1013 A s/f19
1014 $ hg forget s/f19
1014 $ hg forget s/f19
1015 not removing s/f19: file is already untracked
1015 $ hg st -S
1016 [1]
1016 ? s/f19
1017 $ rm s/f19
1017 $ rm s/f19
General Comments 0
You need to be logged in to leave comments. Login now