##// END OF EJS Templates
subrepos: abort commit by default if a subrepo is dirty (BC)...
Martin Geisler -
r15321:e174353e stable
parent child Browse files
Show More
@@ -1,5635 +1,5639 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 merge as mergemod
16 import merge as mergemod
17 import minirst, revset, fileset
17 import minirst, revset, fileset
18 import dagparser, context, simplemerge
18 import dagparser, context, simplemerge
19 import random, setdiscovery, treediscovery, dagutil
19 import random, setdiscovery, treediscovery, dagutil
20
20
21 table = {}
21 table = {}
22
22
23 command = cmdutil.command(table)
23 command = cmdutil.command(table)
24
24
25 # common command options
25 # common command options
26
26
27 globalopts = [
27 globalopts = [
28 ('R', 'repository', '',
28 ('R', 'repository', '',
29 _('repository root directory or name of overlay bundle file'),
29 _('repository root directory or name of overlay bundle file'),
30 _('REPO')),
30 _('REPO')),
31 ('', 'cwd', '',
31 ('', 'cwd', '',
32 _('change working directory'), _('DIR')),
32 _('change working directory'), _('DIR')),
33 ('y', 'noninteractive', None,
33 ('y', 'noninteractive', None,
34 _('do not prompt, automatically pick the first choice for all prompts')),
34 _('do not prompt, automatically pick the first choice for all prompts')),
35 ('q', 'quiet', None, _('suppress output')),
35 ('q', 'quiet', None, _('suppress output')),
36 ('v', 'verbose', None, _('enable additional output')),
36 ('v', 'verbose', None, _('enable additional output')),
37 ('', 'config', [],
37 ('', 'config', [],
38 _('set/override config option (use \'section.name=value\')'),
38 _('set/override config option (use \'section.name=value\')'),
39 _('CONFIG')),
39 _('CONFIG')),
40 ('', 'debug', None, _('enable debugging output')),
40 ('', 'debug', None, _('enable debugging output')),
41 ('', 'debugger', None, _('start debugger')),
41 ('', 'debugger', None, _('start debugger')),
42 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
42 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
43 _('ENCODE')),
43 _('ENCODE')),
44 ('', 'encodingmode', encoding.encodingmode,
44 ('', 'encodingmode', encoding.encodingmode,
45 _('set the charset encoding mode'), _('MODE')),
45 _('set the charset encoding mode'), _('MODE')),
46 ('', 'traceback', None, _('always print a traceback on exception')),
46 ('', 'traceback', None, _('always print a traceback on exception')),
47 ('', 'time', None, _('time how long the command takes')),
47 ('', 'time', None, _('time how long the command takes')),
48 ('', 'profile', None, _('print command execution profile')),
48 ('', 'profile', None, _('print command execution profile')),
49 ('', 'version', None, _('output version information and exit')),
49 ('', 'version', None, _('output version information and exit')),
50 ('h', 'help', None, _('display help and exit')),
50 ('h', 'help', None, _('display help and exit')),
51 ]
51 ]
52
52
53 dryrunopts = [('n', 'dry-run', None,
53 dryrunopts = [('n', 'dry-run', None,
54 _('do not perform actions, just print output'))]
54 _('do not perform actions, just print output'))]
55
55
56 remoteopts = [
56 remoteopts = [
57 ('e', 'ssh', '',
57 ('e', 'ssh', '',
58 _('specify ssh command to use'), _('CMD')),
58 _('specify ssh command to use'), _('CMD')),
59 ('', 'remotecmd', '',
59 ('', 'remotecmd', '',
60 _('specify hg command to run on the remote side'), _('CMD')),
60 _('specify hg command to run on the remote side'), _('CMD')),
61 ('', 'insecure', None,
61 ('', 'insecure', None,
62 _('do not verify server certificate (ignoring web.cacerts config)')),
62 _('do not verify server certificate (ignoring web.cacerts config)')),
63 ]
63 ]
64
64
65 walkopts = [
65 walkopts = [
66 ('I', 'include', [],
66 ('I', 'include', [],
67 _('include names matching the given patterns'), _('PATTERN')),
67 _('include names matching the given patterns'), _('PATTERN')),
68 ('X', 'exclude', [],
68 ('X', 'exclude', [],
69 _('exclude names matching the given patterns'), _('PATTERN')),
69 _('exclude names matching the given patterns'), _('PATTERN')),
70 ]
70 ]
71
71
72 commitopts = [
72 commitopts = [
73 ('m', 'message', '',
73 ('m', 'message', '',
74 _('use text as commit message'), _('TEXT')),
74 _('use text as commit message'), _('TEXT')),
75 ('l', 'logfile', '',
75 ('l', 'logfile', '',
76 _('read commit message from file'), _('FILE')),
76 _('read commit message from file'), _('FILE')),
77 ]
77 ]
78
78
79 commitopts2 = [
79 commitopts2 = [
80 ('d', 'date', '',
80 ('d', 'date', '',
81 _('record the specified date as commit date'), _('DATE')),
81 _('record the specified date as commit date'), _('DATE')),
82 ('u', 'user', '',
82 ('u', 'user', '',
83 _('record the specified user as committer'), _('USER')),
83 _('record the specified user as committer'), _('USER')),
84 ]
84 ]
85
85
86 templateopts = [
86 templateopts = [
87 ('', 'style', '',
87 ('', 'style', '',
88 _('display using template map file'), _('STYLE')),
88 _('display using template map file'), _('STYLE')),
89 ('', 'template', '',
89 ('', 'template', '',
90 _('display with template'), _('TEMPLATE')),
90 _('display with template'), _('TEMPLATE')),
91 ]
91 ]
92
92
93 logopts = [
93 logopts = [
94 ('p', 'patch', None, _('show patch')),
94 ('p', 'patch', None, _('show patch')),
95 ('g', 'git', None, _('use git extended diff format')),
95 ('g', 'git', None, _('use git extended diff format')),
96 ('l', 'limit', '',
96 ('l', 'limit', '',
97 _('limit number of changes displayed'), _('NUM')),
97 _('limit number of changes displayed'), _('NUM')),
98 ('M', 'no-merges', None, _('do not show merges')),
98 ('M', 'no-merges', None, _('do not show merges')),
99 ('', 'stat', None, _('output diffstat-style summary of changes')),
99 ('', 'stat', None, _('output diffstat-style summary of changes')),
100 ] + templateopts
100 ] + templateopts
101
101
102 diffopts = [
102 diffopts = [
103 ('a', 'text', None, _('treat all files as text')),
103 ('a', 'text', None, _('treat all files as text')),
104 ('g', 'git', None, _('use git extended diff format')),
104 ('g', 'git', None, _('use git extended diff format')),
105 ('', 'nodates', None, _('omit dates from diff headers'))
105 ('', 'nodates', None, _('omit dates from diff headers'))
106 ]
106 ]
107
107
108 diffopts2 = [
108 diffopts2 = [
109 ('p', 'show-function', None, _('show which function each change is in')),
109 ('p', 'show-function', None, _('show which function each change is in')),
110 ('', 'reverse', None, _('produce a diff that undoes the changes')),
110 ('', 'reverse', None, _('produce a diff that undoes the changes')),
111 ('w', 'ignore-all-space', None,
111 ('w', 'ignore-all-space', None,
112 _('ignore white space when comparing lines')),
112 _('ignore white space when comparing lines')),
113 ('b', 'ignore-space-change', None,
113 ('b', 'ignore-space-change', None,
114 _('ignore changes in the amount of white space')),
114 _('ignore changes in the amount of white space')),
115 ('B', 'ignore-blank-lines', None,
115 ('B', 'ignore-blank-lines', None,
116 _('ignore changes whose lines are all blank')),
116 _('ignore changes whose lines are all blank')),
117 ('U', 'unified', '',
117 ('U', 'unified', '',
118 _('number of lines of context to show'), _('NUM')),
118 _('number of lines of context to show'), _('NUM')),
119 ('', 'stat', None, _('output diffstat-style summary of changes')),
119 ('', 'stat', None, _('output diffstat-style summary of changes')),
120 ]
120 ]
121
121
122 mergetoolopts = [
122 mergetoolopts = [
123 ('t', 'tool', '', _('specify merge tool')),
123 ('t', 'tool', '', _('specify merge tool')),
124 ]
124 ]
125
125
126 similarityopts = [
126 similarityopts = [
127 ('s', 'similarity', '',
127 ('s', 'similarity', '',
128 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
128 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
129 ]
129 ]
130
130
131 subrepoopts = [
131 subrepoopts = [
132 ('S', 'subrepos', None,
132 ('S', 'subrepos', None,
133 _('recurse into subrepositories'))
133 _('recurse into subrepositories'))
134 ]
134 ]
135
135
136 # Commands start here, listed alphabetically
136 # Commands start here, listed alphabetically
137
137
138 @command('^add',
138 @command('^add',
139 walkopts + subrepoopts + dryrunopts,
139 walkopts + subrepoopts + dryrunopts,
140 _('[OPTION]... [FILE]...'))
140 _('[OPTION]... [FILE]...'))
141 def add(ui, repo, *pats, **opts):
141 def add(ui, repo, *pats, **opts):
142 """add the specified files on the next commit
142 """add the specified files on the next commit
143
143
144 Schedule files to be version controlled and added to the
144 Schedule files to be version controlled and added to the
145 repository.
145 repository.
146
146
147 The files will be added to the repository at the next commit. To
147 The files will be added to the repository at the next commit. To
148 undo an add before that, see :hg:`forget`.
148 undo an add before that, see :hg:`forget`.
149
149
150 If no names are given, add all files to the repository.
150 If no names are given, add all files to the repository.
151
151
152 .. container:: verbose
152 .. container:: verbose
153
153
154 An example showing how new (unknown) files are added
154 An example showing how new (unknown) files are added
155 automatically by :hg:`add`::
155 automatically by :hg:`add`::
156
156
157 $ ls
157 $ ls
158 foo.c
158 foo.c
159 $ hg status
159 $ hg status
160 ? foo.c
160 ? foo.c
161 $ hg add
161 $ hg add
162 adding foo.c
162 adding foo.c
163 $ hg status
163 $ hg status
164 A foo.c
164 A foo.c
165
165
166 Returns 0 if all files are successfully added.
166 Returns 0 if all files are successfully added.
167 """
167 """
168
168
169 m = scmutil.match(repo[None], pats, opts)
169 m = scmutil.match(repo[None], pats, opts)
170 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
170 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
171 opts.get('subrepos'), prefix="")
171 opts.get('subrepos'), prefix="")
172 return rejected and 1 or 0
172 return rejected and 1 or 0
173
173
174 @command('addremove',
174 @command('addremove',
175 similarityopts + walkopts + dryrunopts,
175 similarityopts + walkopts + dryrunopts,
176 _('[OPTION]... [FILE]...'))
176 _('[OPTION]... [FILE]...'))
177 def addremove(ui, repo, *pats, **opts):
177 def addremove(ui, repo, *pats, **opts):
178 """add all new files, delete all missing files
178 """add all new files, delete all missing files
179
179
180 Add all new files and remove all missing files from the
180 Add all new files and remove all missing files from the
181 repository.
181 repository.
182
182
183 New files are ignored if they match any of the patterns in
183 New files are ignored if they match any of the patterns in
184 ``.hgignore``. As with add, these changes take effect at the next
184 ``.hgignore``. As with add, these changes take effect at the next
185 commit.
185 commit.
186
186
187 Use the -s/--similarity option to detect renamed files. With a
187 Use the -s/--similarity option to detect renamed files. With a
188 parameter greater than 0, this compares every removed file with
188 parameter greater than 0, this compares every removed file with
189 every added file and records those similar enough as renames. This
189 every added file and records those similar enough as renames. This
190 option takes a percentage between 0 (disabled) and 100 (files must
190 option takes a percentage between 0 (disabled) and 100 (files must
191 be identical) as its parameter. Detecting renamed files this way
191 be identical) as its parameter. Detecting renamed files this way
192 can be expensive. After using this option, :hg:`status -C` can be
192 can be expensive. After using this option, :hg:`status -C` can be
193 used to check which files were identified as moved or renamed.
193 used to check which files were identified as moved or renamed.
194
194
195 Returns 0 if all files are successfully added.
195 Returns 0 if all files are successfully added.
196 """
196 """
197 try:
197 try:
198 sim = float(opts.get('similarity') or 100)
198 sim = float(opts.get('similarity') or 100)
199 except ValueError:
199 except ValueError:
200 raise util.Abort(_('similarity must be a number'))
200 raise util.Abort(_('similarity must be a number'))
201 if sim < 0 or sim > 100:
201 if sim < 0 or sim > 100:
202 raise util.Abort(_('similarity must be between 0 and 100'))
202 raise util.Abort(_('similarity must be between 0 and 100'))
203 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
203 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
204
204
205 @command('^annotate|blame',
205 @command('^annotate|blame',
206 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
206 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
207 ('', 'follow', None,
207 ('', 'follow', None,
208 _('follow copies/renames and list the filename (DEPRECATED)')),
208 _('follow copies/renames and list the filename (DEPRECATED)')),
209 ('', 'no-follow', None, _("don't follow copies and renames")),
209 ('', 'no-follow', None, _("don't follow copies and renames")),
210 ('a', 'text', None, _('treat all files as text')),
210 ('a', 'text', None, _('treat all files as text')),
211 ('u', 'user', None, _('list the author (long with -v)')),
211 ('u', 'user', None, _('list the author (long with -v)')),
212 ('f', 'file', None, _('list the filename')),
212 ('f', 'file', None, _('list the filename')),
213 ('d', 'date', None, _('list the date (short with -q)')),
213 ('d', 'date', None, _('list the date (short with -q)')),
214 ('n', 'number', None, _('list the revision number (default)')),
214 ('n', 'number', None, _('list the revision number (default)')),
215 ('c', 'changeset', None, _('list the changeset')),
215 ('c', 'changeset', None, _('list the changeset')),
216 ('l', 'line-number', None, _('show line number at the first appearance'))
216 ('l', 'line-number', None, _('show line number at the first appearance'))
217 ] + walkopts,
217 ] + walkopts,
218 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
218 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
219 def annotate(ui, repo, *pats, **opts):
219 def annotate(ui, repo, *pats, **opts):
220 """show changeset information by line for each file
220 """show changeset information by line for each file
221
221
222 List changes in files, showing the revision id responsible for
222 List changes in files, showing the revision id responsible for
223 each line
223 each line
224
224
225 This command is useful for discovering when a change was made and
225 This command is useful for discovering when a change was made and
226 by whom.
226 by whom.
227
227
228 Without the -a/--text option, annotate will avoid processing files
228 Without the -a/--text option, annotate will avoid processing files
229 it detects as binary. With -a, annotate will annotate the file
229 it detects as binary. With -a, annotate will annotate the file
230 anyway, although the results will probably be neither useful
230 anyway, although the results will probably be neither useful
231 nor desirable.
231 nor desirable.
232
232
233 Returns 0 on success.
233 Returns 0 on success.
234 """
234 """
235 if opts.get('follow'):
235 if opts.get('follow'):
236 # --follow is deprecated and now just an alias for -f/--file
236 # --follow is deprecated and now just an alias for -f/--file
237 # to mimic the behavior of Mercurial before version 1.5
237 # to mimic the behavior of Mercurial before version 1.5
238 opts['file'] = True
238 opts['file'] = True
239
239
240 datefunc = ui.quiet and util.shortdate or util.datestr
240 datefunc = ui.quiet and util.shortdate or util.datestr
241 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
241 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
242
242
243 if not pats:
243 if not pats:
244 raise util.Abort(_('at least one filename or pattern is required'))
244 raise util.Abort(_('at least one filename or pattern is required'))
245
245
246 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
246 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
247 ('number', ' ', lambda x: str(x[0].rev())),
247 ('number', ' ', lambda x: str(x[0].rev())),
248 ('changeset', ' ', lambda x: short(x[0].node())),
248 ('changeset', ' ', lambda x: short(x[0].node())),
249 ('date', ' ', getdate),
249 ('date', ' ', getdate),
250 ('file', ' ', lambda x: x[0].path()),
250 ('file', ' ', lambda x: x[0].path()),
251 ('line_number', ':', lambda x: str(x[1])),
251 ('line_number', ':', lambda x: str(x[1])),
252 ]
252 ]
253
253
254 if (not opts.get('user') and not opts.get('changeset')
254 if (not opts.get('user') and not opts.get('changeset')
255 and not opts.get('date') and not opts.get('file')):
255 and not opts.get('date') and not opts.get('file')):
256 opts['number'] = True
256 opts['number'] = True
257
257
258 linenumber = opts.get('line_number') is not None
258 linenumber = opts.get('line_number') is not None
259 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
259 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'))
260 raise util.Abort(_('at least one of -n/-c is required for -l'))
261
261
262 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
262 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
263 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
264
264
265 def bad(x, y):
265 def bad(x, y):
266 raise util.Abort("%s: %s" % (x, y))
266 raise util.Abort("%s: %s" % (x, y))
267
267
268 ctx = scmutil.revsingle(repo, opts.get('rev'))
268 ctx = scmutil.revsingle(repo, opts.get('rev'))
269 m = scmutil.match(ctx, pats, opts)
269 m = scmutil.match(ctx, pats, opts)
270 m.bad = bad
270 m.bad = bad
271 follow = not opts.get('no_follow')
271 follow = not opts.get('no_follow')
272 for abs in ctx.walk(m):
272 for abs in ctx.walk(m):
273 fctx = ctx[abs]
273 fctx = ctx[abs]
274 if not opts.get('text') and util.binary(fctx.data()):
274 if not opts.get('text') and util.binary(fctx.data()):
275 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
275 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
276 continue
276 continue
277
277
278 lines = fctx.annotate(follow=follow, linenumber=linenumber)
278 lines = fctx.annotate(follow=follow, linenumber=linenumber)
279 pieces = []
279 pieces = []
280
280
281 for f, sep in funcmap:
281 for f, sep in funcmap:
282 l = [f(n) for n, dummy in lines]
282 l = [f(n) for n, dummy in lines]
283 if l:
283 if l:
284 sized = [(x, encoding.colwidth(x)) for x in l]
284 sized = [(x, encoding.colwidth(x)) for x in l]
285 ml = max([w for x, w in sized])
285 ml = max([w for x, w in sized])
286 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
286 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
287 for x, w in sized])
287 for x, w in sized])
288
288
289 if pieces:
289 if pieces:
290 for p, l in zip(zip(*pieces), lines):
290 for p, l in zip(zip(*pieces), lines):
291 ui.write("%s: %s" % ("".join(p), l[1]))
291 ui.write("%s: %s" % ("".join(p), l[1]))
292
292
293 @command('archive',
293 @command('archive',
294 [('', 'no-decode', None, _('do not pass files through decoders')),
294 [('', 'no-decode', None, _('do not pass files through decoders')),
295 ('p', 'prefix', '', _('directory prefix for files in archive'),
295 ('p', 'prefix', '', _('directory prefix for files in archive'),
296 _('PREFIX')),
296 _('PREFIX')),
297 ('r', 'rev', '', _('revision to distribute'), _('REV')),
297 ('r', 'rev', '', _('revision to distribute'), _('REV')),
298 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
298 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
299 ] + subrepoopts + walkopts,
299 ] + subrepoopts + walkopts,
300 _('[OPTION]... DEST'))
300 _('[OPTION]... DEST'))
301 def archive(ui, repo, dest, **opts):
301 def archive(ui, repo, dest, **opts):
302 '''create an unversioned archive of a repository revision
302 '''create an unversioned archive of a repository revision
303
303
304 By default, the revision used is the parent of the working
304 By default, the revision used is the parent of the working
305 directory; use -r/--rev to specify a different revision.
305 directory; use -r/--rev to specify a different revision.
306
306
307 The archive type is automatically detected based on file
307 The archive type is automatically detected based on file
308 extension (or override using -t/--type).
308 extension (or override using -t/--type).
309
309
310 .. container:: verbose
310 .. container:: verbose
311
311
312 Examples:
312 Examples:
313
313
314 - create a zip file containing the 1.0 release::
314 - create a zip file containing the 1.0 release::
315
315
316 hg archive -r 1.0 project-1.0.zip
316 hg archive -r 1.0 project-1.0.zip
317
317
318 - create a tarball excluding .hg files::
318 - create a tarball excluding .hg files::
319
319
320 hg archive project.tar.gz -X ".hg*"
320 hg archive project.tar.gz -X ".hg*"
321
321
322 Valid types are:
322 Valid types are:
323
323
324 :``files``: a directory full of files (default)
324 :``files``: a directory full of files (default)
325 :``tar``: tar archive, uncompressed
325 :``tar``: tar archive, uncompressed
326 :``tbz2``: tar archive, compressed using bzip2
326 :``tbz2``: tar archive, compressed using bzip2
327 :``tgz``: tar archive, compressed using gzip
327 :``tgz``: tar archive, compressed using gzip
328 :``uzip``: zip archive, uncompressed
328 :``uzip``: zip archive, uncompressed
329 :``zip``: zip archive, compressed using deflate
329 :``zip``: zip archive, compressed using deflate
330
330
331 The exact name of the destination archive or directory is given
331 The exact name of the destination archive or directory is given
332 using a format string; see :hg:`help export` for details.
332 using a format string; see :hg:`help export` for details.
333
333
334 Each member added to an archive file has a directory prefix
334 Each member added to an archive file has a directory prefix
335 prepended. Use -p/--prefix to specify a format string for the
335 prepended. Use -p/--prefix to specify a format string for the
336 prefix. The default is the basename of the archive, with suffixes
336 prefix. The default is the basename of the archive, with suffixes
337 removed.
337 removed.
338
338
339 Returns 0 on success.
339 Returns 0 on success.
340 '''
340 '''
341
341
342 ctx = scmutil.revsingle(repo, opts.get('rev'))
342 ctx = scmutil.revsingle(repo, opts.get('rev'))
343 if not ctx:
343 if not ctx:
344 raise util.Abort(_('no working directory: please specify a revision'))
344 raise util.Abort(_('no working directory: please specify a revision'))
345 node = ctx.node()
345 node = ctx.node()
346 dest = cmdutil.makefilename(repo, dest, node)
346 dest = cmdutil.makefilename(repo, dest, node)
347 if os.path.realpath(dest) == repo.root:
347 if os.path.realpath(dest) == repo.root:
348 raise util.Abort(_('repository root cannot be destination'))
348 raise util.Abort(_('repository root cannot be destination'))
349
349
350 kind = opts.get('type') or archival.guesskind(dest) or 'files'
350 kind = opts.get('type') or archival.guesskind(dest) or 'files'
351 prefix = opts.get('prefix')
351 prefix = opts.get('prefix')
352
352
353 if dest == '-':
353 if dest == '-':
354 if kind == 'files':
354 if kind == 'files':
355 raise util.Abort(_('cannot archive plain files to stdout'))
355 raise util.Abort(_('cannot archive plain files to stdout'))
356 dest = cmdutil.makefileobj(repo, dest)
356 dest = cmdutil.makefileobj(repo, dest)
357 if not prefix:
357 if not prefix:
358 prefix = os.path.basename(repo.root) + '-%h'
358 prefix = os.path.basename(repo.root) + '-%h'
359
359
360 prefix = cmdutil.makefilename(repo, prefix, node)
360 prefix = cmdutil.makefilename(repo, prefix, node)
361 matchfn = scmutil.match(ctx, [], opts)
361 matchfn = scmutil.match(ctx, [], opts)
362 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
362 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
363 matchfn, prefix, subrepos=opts.get('subrepos'))
363 matchfn, prefix, subrepos=opts.get('subrepos'))
364
364
365 @command('backout',
365 @command('backout',
366 [('', 'merge', None, _('merge with old dirstate parent after backout')),
366 [('', 'merge', None, _('merge with old dirstate parent after backout')),
367 ('', 'parent', '',
367 ('', 'parent', '',
368 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
368 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
369 ('r', 'rev', '', _('revision to backout'), _('REV')),
369 ('r', 'rev', '', _('revision to backout'), _('REV')),
370 ] + mergetoolopts + walkopts + commitopts + commitopts2,
370 ] + mergetoolopts + walkopts + commitopts + commitopts2,
371 _('[OPTION]... [-r] REV'))
371 _('[OPTION]... [-r] REV'))
372 def backout(ui, repo, node=None, rev=None, **opts):
372 def backout(ui, repo, node=None, rev=None, **opts):
373 '''reverse effect of earlier changeset
373 '''reverse effect of earlier changeset
374
374
375 Prepare a new changeset with the effect of REV undone in the
375 Prepare a new changeset with the effect of REV undone in the
376 current working directory.
376 current working directory.
377
377
378 If REV is the parent of the working directory, then this new changeset
378 If REV is the parent of the working directory, then this new changeset
379 is committed automatically. Otherwise, hg needs to merge the
379 is committed automatically. Otherwise, hg needs to merge the
380 changes and the merged result is left uncommitted.
380 changes and the merged result is left uncommitted.
381
381
382 .. note::
382 .. note::
383 backout cannot be used to fix either an unwanted or
383 backout cannot be used to fix either an unwanted or
384 incorrect merge.
384 incorrect merge.
385
385
386 .. container:: verbose
386 .. container:: verbose
387
387
388 By default, the pending changeset will have one parent,
388 By default, the pending changeset will have one parent,
389 maintaining a linear history. With --merge, the pending
389 maintaining a linear history. With --merge, the pending
390 changeset will instead have two parents: the old parent of the
390 changeset will instead have two parents: the old parent of the
391 working directory and a new child of REV that simply undoes REV.
391 working directory and a new child of REV that simply undoes REV.
392
392
393 Before version 1.7, the behavior without --merge was equivalent
393 Before version 1.7, the behavior without --merge was equivalent
394 to specifying --merge followed by :hg:`update --clean .` to
394 to specifying --merge followed by :hg:`update --clean .` to
395 cancel the merge and leave the child of REV as a head to be
395 cancel the merge and leave the child of REV as a head to be
396 merged separately.
396 merged separately.
397
397
398 See :hg:`help dates` for a list of formats valid for -d/--date.
398 See :hg:`help dates` for a list of formats valid for -d/--date.
399
399
400 Returns 0 on success.
400 Returns 0 on success.
401 '''
401 '''
402 if rev and node:
402 if rev and node:
403 raise util.Abort(_("please specify just one revision"))
403 raise util.Abort(_("please specify just one revision"))
404
404
405 if not rev:
405 if not rev:
406 rev = node
406 rev = node
407
407
408 if not rev:
408 if not rev:
409 raise util.Abort(_("please specify a revision to backout"))
409 raise util.Abort(_("please specify a revision to backout"))
410
410
411 date = opts.get('date')
411 date = opts.get('date')
412 if date:
412 if date:
413 opts['date'] = util.parsedate(date)
413 opts['date'] = util.parsedate(date)
414
414
415 cmdutil.bailifchanged(repo)
415 cmdutil.bailifchanged(repo)
416 node = scmutil.revsingle(repo, rev).node()
416 node = scmutil.revsingle(repo, rev).node()
417
417
418 op1, op2 = repo.dirstate.parents()
418 op1, op2 = repo.dirstate.parents()
419 a = repo.changelog.ancestor(op1, node)
419 a = repo.changelog.ancestor(op1, node)
420 if a != node:
420 if a != node:
421 raise util.Abort(_('cannot backout change on a different branch'))
421 raise util.Abort(_('cannot backout change on a different branch'))
422
422
423 p1, p2 = repo.changelog.parents(node)
423 p1, p2 = repo.changelog.parents(node)
424 if p1 == nullid:
424 if p1 == nullid:
425 raise util.Abort(_('cannot backout a change with no parents'))
425 raise util.Abort(_('cannot backout a change with no parents'))
426 if p2 != nullid:
426 if p2 != nullid:
427 if not opts.get('parent'):
427 if not opts.get('parent'):
428 raise util.Abort(_('cannot backout a merge changeset'))
428 raise util.Abort(_('cannot backout a merge changeset'))
429 p = repo.lookup(opts['parent'])
429 p = repo.lookup(opts['parent'])
430 if p not in (p1, p2):
430 if p not in (p1, p2):
431 raise util.Abort(_('%s is not a parent of %s') %
431 raise util.Abort(_('%s is not a parent of %s') %
432 (short(p), short(node)))
432 (short(p), short(node)))
433 parent = p
433 parent = p
434 else:
434 else:
435 if opts.get('parent'):
435 if opts.get('parent'):
436 raise util.Abort(_('cannot use --parent on non-merge changeset'))
436 raise util.Abort(_('cannot use --parent on non-merge changeset'))
437 parent = p1
437 parent = p1
438
438
439 # the backout should appear on the same branch
439 # the backout should appear on the same branch
440 branch = repo.dirstate.branch()
440 branch = repo.dirstate.branch()
441 hg.clean(repo, node, show_stats=False)
441 hg.clean(repo, node, show_stats=False)
442 repo.dirstate.setbranch(branch)
442 repo.dirstate.setbranch(branch)
443 revert_opts = opts.copy()
443 revert_opts = opts.copy()
444 revert_opts['date'] = None
444 revert_opts['date'] = None
445 revert_opts['all'] = True
445 revert_opts['all'] = True
446 revert_opts['rev'] = hex(parent)
446 revert_opts['rev'] = hex(parent)
447 revert_opts['no_backup'] = None
447 revert_opts['no_backup'] = None
448 revert(ui, repo, **revert_opts)
448 revert(ui, repo, **revert_opts)
449 if not opts.get('merge') and op1 != node:
449 if not opts.get('merge') and op1 != node:
450 try:
450 try:
451 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
451 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
452 return hg.update(repo, op1)
452 return hg.update(repo, op1)
453 finally:
453 finally:
454 ui.setconfig('ui', 'forcemerge', '')
454 ui.setconfig('ui', 'forcemerge', '')
455
455
456 commit_opts = opts.copy()
456 commit_opts = opts.copy()
457 commit_opts['addremove'] = False
457 commit_opts['addremove'] = False
458 if not commit_opts['message'] and not commit_opts['logfile']:
458 if not commit_opts['message'] and not commit_opts['logfile']:
459 # we don't translate commit messages
459 # we don't translate commit messages
460 commit_opts['message'] = "Backed out changeset %s" % short(node)
460 commit_opts['message'] = "Backed out changeset %s" % short(node)
461 commit_opts['force_editor'] = True
461 commit_opts['force_editor'] = True
462 commit(ui, repo, **commit_opts)
462 commit(ui, repo, **commit_opts)
463 def nice(node):
463 def nice(node):
464 return '%d:%s' % (repo.changelog.rev(node), short(node))
464 return '%d:%s' % (repo.changelog.rev(node), short(node))
465 ui.status(_('changeset %s backs out changeset %s\n') %
465 ui.status(_('changeset %s backs out changeset %s\n') %
466 (nice(repo.changelog.tip()), nice(node)))
466 (nice(repo.changelog.tip()), nice(node)))
467 if opts.get('merge') and op1 != node:
467 if opts.get('merge') and op1 != node:
468 hg.clean(repo, op1, show_stats=False)
468 hg.clean(repo, op1, show_stats=False)
469 ui.status(_('merging with changeset %s\n')
469 ui.status(_('merging with changeset %s\n')
470 % nice(repo.changelog.tip()))
470 % nice(repo.changelog.tip()))
471 try:
471 try:
472 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
472 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
473 return hg.merge(repo, hex(repo.changelog.tip()))
473 return hg.merge(repo, hex(repo.changelog.tip()))
474 finally:
474 finally:
475 ui.setconfig('ui', 'forcemerge', '')
475 ui.setconfig('ui', 'forcemerge', '')
476 return 0
476 return 0
477
477
478 @command('bisect',
478 @command('bisect',
479 [('r', 'reset', False, _('reset bisect state')),
479 [('r', 'reset', False, _('reset bisect state')),
480 ('g', 'good', False, _('mark changeset good')),
480 ('g', 'good', False, _('mark changeset good')),
481 ('b', 'bad', False, _('mark changeset bad')),
481 ('b', 'bad', False, _('mark changeset bad')),
482 ('s', 'skip', False, _('skip testing changeset')),
482 ('s', 'skip', False, _('skip testing changeset')),
483 ('e', 'extend', False, _('extend the bisect range')),
483 ('e', 'extend', False, _('extend the bisect range')),
484 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
484 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
485 ('U', 'noupdate', False, _('do not update to target'))],
485 ('U', 'noupdate', False, _('do not update to target'))],
486 _("[-gbsr] [-U] [-c CMD] [REV]"))
486 _("[-gbsr] [-U] [-c CMD] [REV]"))
487 def bisect(ui, repo, rev=None, extra=None, command=None,
487 def bisect(ui, repo, rev=None, extra=None, command=None,
488 reset=None, good=None, bad=None, skip=None, extend=None,
488 reset=None, good=None, bad=None, skip=None, extend=None,
489 noupdate=None):
489 noupdate=None):
490 """subdivision search of changesets
490 """subdivision search of changesets
491
491
492 This command helps to find changesets which introduce problems. To
492 This command helps to find changesets which introduce problems. To
493 use, mark the earliest changeset you know exhibits the problem as
493 use, mark the earliest changeset you know exhibits the problem as
494 bad, then mark the latest changeset which is free from the problem
494 bad, then mark the latest changeset which is free from the problem
495 as good. Bisect will update your working directory to a revision
495 as good. Bisect will update your working directory to a revision
496 for testing (unless the -U/--noupdate option is specified). Once
496 for testing (unless the -U/--noupdate option is specified). Once
497 you have performed tests, mark the working directory as good or
497 you have performed tests, mark the working directory as good or
498 bad, and bisect will either update to another candidate changeset
498 bad, and bisect will either update to another candidate changeset
499 or announce that it has found the bad revision.
499 or announce that it has found the bad revision.
500
500
501 As a shortcut, you can also use the revision argument to mark a
501 As a shortcut, you can also use the revision argument to mark a
502 revision as good or bad without checking it out first.
502 revision as good or bad without checking it out first.
503
503
504 If you supply a command, it will be used for automatic bisection.
504 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:
505 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
506 status 0 means good, 125 means to skip the revision, 127
507 (command not found) will abort the bisection, and any other
507 (command not found) will abort the bisection, and any other
508 non-zero exit status means the revision is bad.
508 non-zero exit status means the revision is bad.
509
509
510 .. container:: verbose
510 .. container:: verbose
511
511
512 Some examples:
512 Some examples:
513
513
514 - start a bisection with known bad revision 12, and good revision 34::
514 - start a bisection with known bad revision 12, and good revision 34::
515
515
516 hg bisect --bad 34
516 hg bisect --bad 34
517 hg bisect --good 12
517 hg bisect --good 12
518
518
519 - advance the current bisection by marking current revision as good or
519 - advance the current bisection by marking current revision as good or
520 bad::
520 bad::
521
521
522 hg bisect --good
522 hg bisect --good
523 hg bisect --bad
523 hg bisect --bad
524
524
525 - mark the current revision, or a known revision, to be skipped (eg. if
525 - mark the current revision, or a known revision, to be skipped (eg. if
526 that revision is not usable because of another issue)::
526 that revision is not usable because of another issue)::
527
527
528 hg bisect --skip
528 hg bisect --skip
529 hg bisect --skip 23
529 hg bisect --skip 23
530
530
531 - forget the current bisection::
531 - forget the current bisection::
532
532
533 hg bisect --reset
533 hg bisect --reset
534
534
535 - use 'make && make tests' to automatically find the first broken
535 - use 'make && make tests' to automatically find the first broken
536 revision::
536 revision::
537
537
538 hg bisect --reset
538 hg bisect --reset
539 hg bisect --bad 34
539 hg bisect --bad 34
540 hg bisect --good 12
540 hg bisect --good 12
541 hg bisect --command 'make && make tests'
541 hg bisect --command 'make && make tests'
542
542
543 - see all changesets whose states are already known in the current
543 - see all changesets whose states are already known in the current
544 bisection::
544 bisection::
545
545
546 hg log -r "bisect(pruned)"
546 hg log -r "bisect(pruned)"
547
547
548 - see all changesets that took part in the current bisection::
548 - see all changesets that took part in the current bisection::
549
549
550 hg log -r "bisect(range)"
550 hg log -r "bisect(range)"
551
551
552 - with the graphlog extension, you can even get a nice graph::
552 - with the graphlog extension, you can even get a nice graph::
553
553
554 hg log --graph -r "bisect(range)"
554 hg log --graph -r "bisect(range)"
555
555
556 See :hg:`help revsets` for more about the `bisect()` keyword.
556 See :hg:`help revsets` for more about the `bisect()` keyword.
557
557
558 Returns 0 on success.
558 Returns 0 on success.
559 """
559 """
560 def extendbisectrange(nodes, good):
560 def extendbisectrange(nodes, good):
561 # bisect is incomplete when it ends on a merge node and
561 # bisect is incomplete when it ends on a merge node and
562 # one of the parent was not checked.
562 # one of the parent was not checked.
563 parents = repo[nodes[0]].parents()
563 parents = repo[nodes[0]].parents()
564 if len(parents) > 1:
564 if len(parents) > 1:
565 side = good and state['bad'] or state['good']
565 side = good and state['bad'] or state['good']
566 num = len(set(i.node() for i in parents) & set(side))
566 num = len(set(i.node() for i in parents) & set(side))
567 if num == 1:
567 if num == 1:
568 return parents[0].ancestor(parents[1])
568 return parents[0].ancestor(parents[1])
569 return None
569 return None
570
570
571 def print_result(nodes, good):
571 def print_result(nodes, good):
572 displayer = cmdutil.show_changeset(ui, repo, {})
572 displayer = cmdutil.show_changeset(ui, repo, {})
573 if len(nodes) == 1:
573 if len(nodes) == 1:
574 # narrowed it down to a single revision
574 # narrowed it down to a single revision
575 if good:
575 if good:
576 ui.write(_("The first good revision is:\n"))
576 ui.write(_("The first good revision is:\n"))
577 else:
577 else:
578 ui.write(_("The first bad revision is:\n"))
578 ui.write(_("The first bad revision is:\n"))
579 displayer.show(repo[nodes[0]])
579 displayer.show(repo[nodes[0]])
580 extendnode = extendbisectrange(nodes, good)
580 extendnode = extendbisectrange(nodes, good)
581 if extendnode is not None:
581 if extendnode is not None:
582 ui.write(_('Not all ancestors of this changeset have been'
582 ui.write(_('Not all ancestors of this changeset have been'
583 ' checked.\nUse bisect --extend to continue the '
583 ' checked.\nUse bisect --extend to continue the '
584 'bisection from\nthe common ancestor, %s.\n')
584 'bisection from\nthe common ancestor, %s.\n')
585 % extendnode)
585 % extendnode)
586 else:
586 else:
587 # multiple possible revisions
587 # multiple possible revisions
588 if good:
588 if good:
589 ui.write(_("Due to skipped revisions, the first "
589 ui.write(_("Due to skipped revisions, the first "
590 "good revision could be any of:\n"))
590 "good revision could be any of:\n"))
591 else:
591 else:
592 ui.write(_("Due to skipped revisions, the first "
592 ui.write(_("Due to skipped revisions, the first "
593 "bad revision could be any of:\n"))
593 "bad revision could be any of:\n"))
594 for n in nodes:
594 for n in nodes:
595 displayer.show(repo[n])
595 displayer.show(repo[n])
596 displayer.close()
596 displayer.close()
597
597
598 def check_state(state, interactive=True):
598 def check_state(state, interactive=True):
599 if not state['good'] or not state['bad']:
599 if not state['good'] or not state['bad']:
600 if (good or bad or skip or reset) and interactive:
600 if (good or bad or skip or reset) and interactive:
601 return
601 return
602 if not state['good']:
602 if not state['good']:
603 raise util.Abort(_('cannot bisect (no known good revisions)'))
603 raise util.Abort(_('cannot bisect (no known good revisions)'))
604 else:
604 else:
605 raise util.Abort(_('cannot bisect (no known bad revisions)'))
605 raise util.Abort(_('cannot bisect (no known bad revisions)'))
606 return True
606 return True
607
607
608 # backward compatibility
608 # backward compatibility
609 if rev in "good bad reset init".split():
609 if rev in "good bad reset init".split():
610 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
610 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
611 cmd, rev, extra = rev, extra, None
611 cmd, rev, extra = rev, extra, None
612 if cmd == "good":
612 if cmd == "good":
613 good = True
613 good = True
614 elif cmd == "bad":
614 elif cmd == "bad":
615 bad = True
615 bad = True
616 else:
616 else:
617 reset = True
617 reset = True
618 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
618 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
619 raise util.Abort(_('incompatible arguments'))
619 raise util.Abort(_('incompatible arguments'))
620
620
621 if reset:
621 if reset:
622 p = repo.join("bisect.state")
622 p = repo.join("bisect.state")
623 if os.path.exists(p):
623 if os.path.exists(p):
624 os.unlink(p)
624 os.unlink(p)
625 return
625 return
626
626
627 state = hbisect.load_state(repo)
627 state = hbisect.load_state(repo)
628
628
629 if command:
629 if command:
630 changesets = 1
630 changesets = 1
631 try:
631 try:
632 while changesets:
632 while changesets:
633 # update state
633 # update state
634 status = util.system(command, out=ui.fout)
634 status = util.system(command, out=ui.fout)
635 if status == 125:
635 if status == 125:
636 transition = "skip"
636 transition = "skip"
637 elif status == 0:
637 elif status == 0:
638 transition = "good"
638 transition = "good"
639 # status < 0 means process was killed
639 # status < 0 means process was killed
640 elif status == 127:
640 elif status == 127:
641 raise util.Abort(_("failed to execute %s") % command)
641 raise util.Abort(_("failed to execute %s") % command)
642 elif status < 0:
642 elif status < 0:
643 raise util.Abort(_("%s killed") % command)
643 raise util.Abort(_("%s killed") % command)
644 else:
644 else:
645 transition = "bad"
645 transition = "bad"
646 ctx = scmutil.revsingle(repo, rev)
646 ctx = scmutil.revsingle(repo, rev)
647 rev = None # clear for future iterations
647 rev = None # clear for future iterations
648 state[transition].append(ctx.node())
648 state[transition].append(ctx.node())
649 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
649 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
650 check_state(state, interactive=False)
650 check_state(state, interactive=False)
651 # bisect
651 # bisect
652 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
652 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
653 # update to next check
653 # update to next check
654 cmdutil.bailifchanged(repo)
654 cmdutil.bailifchanged(repo)
655 hg.clean(repo, nodes[0], show_stats=False)
655 hg.clean(repo, nodes[0], show_stats=False)
656 finally:
656 finally:
657 hbisect.save_state(repo, state)
657 hbisect.save_state(repo, state)
658 print_result(nodes, good)
658 print_result(nodes, good)
659 return
659 return
660
660
661 # update state
661 # update state
662
662
663 if rev:
663 if rev:
664 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
664 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
665 else:
665 else:
666 nodes = [repo.lookup('.')]
666 nodes = [repo.lookup('.')]
667
667
668 if good or bad or skip:
668 if good or bad or skip:
669 if good:
669 if good:
670 state['good'] += nodes
670 state['good'] += nodes
671 elif bad:
671 elif bad:
672 state['bad'] += nodes
672 state['bad'] += nodes
673 elif skip:
673 elif skip:
674 state['skip'] += nodes
674 state['skip'] += nodes
675 hbisect.save_state(repo, state)
675 hbisect.save_state(repo, state)
676
676
677 if not check_state(state):
677 if not check_state(state):
678 return
678 return
679
679
680 # actually bisect
680 # actually bisect
681 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
681 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
682 if extend:
682 if extend:
683 if not changesets:
683 if not changesets:
684 extendnode = extendbisectrange(nodes, good)
684 extendnode = extendbisectrange(nodes, good)
685 if extendnode is not None:
685 if extendnode is not None:
686 ui.write(_("Extending search to changeset %d:%s\n"
686 ui.write(_("Extending search to changeset %d:%s\n"
687 % (extendnode.rev(), extendnode)))
687 % (extendnode.rev(), extendnode)))
688 if noupdate:
688 if noupdate:
689 return
689 return
690 cmdutil.bailifchanged(repo)
690 cmdutil.bailifchanged(repo)
691 return hg.clean(repo, extendnode.node())
691 return hg.clean(repo, extendnode.node())
692 raise util.Abort(_("nothing to extend"))
692 raise util.Abort(_("nothing to extend"))
693
693
694 if changesets == 0:
694 if changesets == 0:
695 print_result(nodes, good)
695 print_result(nodes, good)
696 else:
696 else:
697 assert len(nodes) == 1 # only a single node can be tested next
697 assert len(nodes) == 1 # only a single node can be tested next
698 node = nodes[0]
698 node = nodes[0]
699 # compute the approximate number of remaining tests
699 # compute the approximate number of remaining tests
700 tests, size = 0, 2
700 tests, size = 0, 2
701 while size <= changesets:
701 while size <= changesets:
702 tests, size = tests + 1, size * 2
702 tests, size = tests + 1, size * 2
703 rev = repo.changelog.rev(node)
703 rev = repo.changelog.rev(node)
704 ui.write(_("Testing changeset %d:%s "
704 ui.write(_("Testing changeset %d:%s "
705 "(%d changesets remaining, ~%d tests)\n")
705 "(%d changesets remaining, ~%d tests)\n")
706 % (rev, short(node), changesets, tests))
706 % (rev, short(node), changesets, tests))
707 if not noupdate:
707 if not noupdate:
708 cmdutil.bailifchanged(repo)
708 cmdutil.bailifchanged(repo)
709 return hg.clean(repo, node)
709 return hg.clean(repo, node)
710
710
711 @command('bookmarks',
711 @command('bookmarks',
712 [('f', 'force', False, _('force')),
712 [('f', 'force', False, _('force')),
713 ('r', 'rev', '', _('revision'), _('REV')),
713 ('r', 'rev', '', _('revision'), _('REV')),
714 ('d', 'delete', False, _('delete a given bookmark')),
714 ('d', 'delete', False, _('delete a given bookmark')),
715 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
715 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
716 ('i', 'inactive', False, _('do not mark a new bookmark active'))],
716 ('i', 'inactive', False, _('do not mark a new bookmark active'))],
717 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
717 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
718 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
718 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
719 rename=None, inactive=False):
719 rename=None, inactive=False):
720 '''track a line of development with movable markers
720 '''track a line of development with movable markers
721
721
722 Bookmarks are pointers to certain commits that move when
722 Bookmarks are pointers to certain commits that move when
723 committing. Bookmarks are local. They can be renamed, copied and
723 committing. Bookmarks are local. They can be renamed, copied and
724 deleted. It is possible to use bookmark names in :hg:`merge` and
724 deleted. It is possible to use bookmark names in :hg:`merge` and
725 :hg:`update` to merge and update respectively to a given bookmark.
725 :hg:`update` to merge and update respectively to a given bookmark.
726
726
727 You can use :hg:`bookmark NAME` to set a bookmark on the working
727 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
728 directory's parent revision with the given name. If you specify
729 a revision using -r REV (where REV may be an existing bookmark),
729 a revision using -r REV (where REV may be an existing bookmark),
730 the bookmark is assigned to that revision.
730 the bookmark is assigned to that revision.
731
731
732 Bookmarks can be pushed and pulled between repositories (see :hg:`help
732 Bookmarks can be pushed and pulled between repositories (see :hg:`help
733 push` and :hg:`help pull`). This requires both the local and remote
733 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
734 repositories to support bookmarks. For versions prior to 1.8, this means
735 the bookmarks extension must be enabled.
735 the bookmarks extension must be enabled.
736 '''
736 '''
737 hexfn = ui.debugflag and hex or short
737 hexfn = ui.debugflag and hex or short
738 marks = repo._bookmarks
738 marks = repo._bookmarks
739 cur = repo.changectx('.').node()
739 cur = repo.changectx('.').node()
740
740
741 if rename:
741 if rename:
742 if rename not in marks:
742 if rename not in marks:
743 raise util.Abort(_("bookmark '%s' does not exist") % rename)
743 raise util.Abort(_("bookmark '%s' does not exist") % rename)
744 if mark in marks and not force:
744 if mark in marks and not force:
745 raise util.Abort(_("bookmark '%s' already exists "
745 raise util.Abort(_("bookmark '%s' already exists "
746 "(use -f to force)") % mark)
746 "(use -f to force)") % mark)
747 if mark is None:
747 if mark is None:
748 raise util.Abort(_("new bookmark name required"))
748 raise util.Abort(_("new bookmark name required"))
749 marks[mark] = marks[rename]
749 marks[mark] = marks[rename]
750 if repo._bookmarkcurrent == rename and not inactive:
750 if repo._bookmarkcurrent == rename and not inactive:
751 bookmarks.setcurrent(repo, mark)
751 bookmarks.setcurrent(repo, mark)
752 del marks[rename]
752 del marks[rename]
753 bookmarks.write(repo)
753 bookmarks.write(repo)
754 return
754 return
755
755
756 if delete:
756 if delete:
757 if mark is None:
757 if mark is None:
758 raise util.Abort(_("bookmark name required"))
758 raise util.Abort(_("bookmark name required"))
759 if mark not in marks:
759 if mark not in marks:
760 raise util.Abort(_("bookmark '%s' does not exist") % mark)
760 raise util.Abort(_("bookmark '%s' does not exist") % mark)
761 if mark == repo._bookmarkcurrent:
761 if mark == repo._bookmarkcurrent:
762 bookmarks.setcurrent(repo, None)
762 bookmarks.setcurrent(repo, None)
763 del marks[mark]
763 del marks[mark]
764 bookmarks.write(repo)
764 bookmarks.write(repo)
765 return
765 return
766
766
767 if mark is not None:
767 if mark is not None:
768 if "\n" in mark:
768 if "\n" in mark:
769 raise util.Abort(_("bookmark name cannot contain newlines"))
769 raise util.Abort(_("bookmark name cannot contain newlines"))
770 mark = mark.strip()
770 mark = mark.strip()
771 if not mark:
771 if not mark:
772 raise util.Abort(_("bookmark names cannot consist entirely of "
772 raise util.Abort(_("bookmark names cannot consist entirely of "
773 "whitespace"))
773 "whitespace"))
774 if inactive and mark == repo._bookmarkcurrent:
774 if inactive and mark == repo._bookmarkcurrent:
775 bookmarks.setcurrent(repo, None)
775 bookmarks.setcurrent(repo, None)
776 return
776 return
777 if mark in marks and not force:
777 if mark in marks and not force:
778 raise util.Abort(_("bookmark '%s' already exists "
778 raise util.Abort(_("bookmark '%s' already exists "
779 "(use -f to force)") % mark)
779 "(use -f to force)") % mark)
780 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
780 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
781 and not force):
781 and not force):
782 raise util.Abort(
782 raise util.Abort(
783 _("a bookmark cannot have the name of an existing branch"))
783 _("a bookmark cannot have the name of an existing branch"))
784 if rev:
784 if rev:
785 marks[mark] = repo.lookup(rev)
785 marks[mark] = repo.lookup(rev)
786 else:
786 else:
787 marks[mark] = repo.changectx('.').node()
787 marks[mark] = repo.changectx('.').node()
788 if not inactive and repo.changectx('.').node() == marks[mark]:
788 if not inactive and repo.changectx('.').node() == marks[mark]:
789 bookmarks.setcurrent(repo, mark)
789 bookmarks.setcurrent(repo, mark)
790 bookmarks.write(repo)
790 bookmarks.write(repo)
791 return
791 return
792
792
793 if mark is None:
793 if mark is None:
794 if rev:
794 if rev:
795 raise util.Abort(_("bookmark name required"))
795 raise util.Abort(_("bookmark name required"))
796 if len(marks) == 0:
796 if len(marks) == 0:
797 ui.status(_("no bookmarks set\n"))
797 ui.status(_("no bookmarks set\n"))
798 else:
798 else:
799 for bmark, n in sorted(marks.iteritems()):
799 for bmark, n in sorted(marks.iteritems()):
800 current = repo._bookmarkcurrent
800 current = repo._bookmarkcurrent
801 if bmark == current and n == cur:
801 if bmark == current and n == cur:
802 prefix, label = '*', 'bookmarks.current'
802 prefix, label = '*', 'bookmarks.current'
803 else:
803 else:
804 prefix, label = ' ', ''
804 prefix, label = ' ', ''
805
805
806 if ui.quiet:
806 if ui.quiet:
807 ui.write("%s\n" % bmark, label=label)
807 ui.write("%s\n" % bmark, label=label)
808 else:
808 else:
809 ui.write(" %s %-25s %d:%s\n" % (
809 ui.write(" %s %-25s %d:%s\n" % (
810 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
810 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
811 label=label)
811 label=label)
812 return
812 return
813
813
814 @command('branch',
814 @command('branch',
815 [('f', 'force', None,
815 [('f', 'force', None,
816 _('set branch name even if it shadows an existing branch')),
816 _('set branch name even if it shadows an existing branch')),
817 ('C', 'clean', None, _('reset branch name to parent branch name'))],
817 ('C', 'clean', None, _('reset branch name to parent branch name'))],
818 _('[-fC] [NAME]'))
818 _('[-fC] [NAME]'))
819 def branch(ui, repo, label=None, **opts):
819 def branch(ui, repo, label=None, **opts):
820 """set or show the current branch name
820 """set or show the current branch name
821
821
822 With no argument, show the current branch name. With one argument,
822 With no argument, show the current branch name. With one argument,
823 set the working directory branch name (the branch will not exist
823 set the working directory branch name (the branch will not exist
824 in the repository until the next commit). Standard practice
824 in the repository until the next commit). Standard practice
825 recommends that primary development take place on the 'default'
825 recommends that primary development take place on the 'default'
826 branch.
826 branch.
827
827
828 Unless -f/--force is specified, branch will not let you set a
828 Unless -f/--force is specified, branch will not let you set a
829 branch name that already exists, even if it's inactive.
829 branch name that already exists, even if it's inactive.
830
830
831 Use -C/--clean to reset the working directory branch to that of
831 Use -C/--clean to reset the working directory branch to that of
832 the parent of the working directory, negating a previous branch
832 the parent of the working directory, negating a previous branch
833 change.
833 change.
834
834
835 Use the command :hg:`update` to switch to an existing branch. Use
835 Use the command :hg:`update` to switch to an existing branch. Use
836 :hg:`commit --close-branch` to mark this branch as closed.
836 :hg:`commit --close-branch` to mark this branch as closed.
837
837
838 .. note::
838 .. note::
839 Branch names are permanent. Use :hg:`bookmark` to create a
839 Branch names are permanent. Use :hg:`bookmark` to create a
840 light-weight bookmark instead. See :hg:`help glossary` for more
840 light-weight bookmark instead. See :hg:`help glossary` for more
841 information about named branches and bookmarks.
841 information about named branches and bookmarks.
842
842
843 Returns 0 on success.
843 Returns 0 on success.
844 """
844 """
845
845
846 if opts.get('clean'):
846 if opts.get('clean'):
847 label = repo[None].p1().branch()
847 label = repo[None].p1().branch()
848 repo.dirstate.setbranch(label)
848 repo.dirstate.setbranch(label)
849 ui.status(_('reset working directory to branch %s\n') % label)
849 ui.status(_('reset working directory to branch %s\n') % label)
850 elif label:
850 elif label:
851 if not opts.get('force') and label in repo.branchtags():
851 if not opts.get('force') and label in repo.branchtags():
852 if label not in [p.branch() for p in repo.parents()]:
852 if label not in [p.branch() for p in repo.parents()]:
853 raise util.Abort(_('a branch of the same name already exists'),
853 raise util.Abort(_('a branch of the same name already exists'),
854 # i18n: "it" refers to an existing branch
854 # i18n: "it" refers to an existing branch
855 hint=_("use 'hg update' to switch to it"))
855 hint=_("use 'hg update' to switch to it"))
856 repo.dirstate.setbranch(label)
856 repo.dirstate.setbranch(label)
857 ui.status(_('marked working directory as branch %s\n') % label)
857 ui.status(_('marked working directory as branch %s\n') % label)
858 else:
858 else:
859 ui.write("%s\n" % repo.dirstate.branch())
859 ui.write("%s\n" % repo.dirstate.branch())
860
860
861 @command('branches',
861 @command('branches',
862 [('a', 'active', False, _('show only branches that have unmerged heads')),
862 [('a', 'active', False, _('show only branches that have unmerged heads')),
863 ('c', 'closed', False, _('show normal and closed branches'))],
863 ('c', 'closed', False, _('show normal and closed branches'))],
864 _('[-ac]'))
864 _('[-ac]'))
865 def branches(ui, repo, active=False, closed=False):
865 def branches(ui, repo, active=False, closed=False):
866 """list repository named branches
866 """list repository named branches
867
867
868 List the repository's named branches, indicating which ones are
868 List the repository's named branches, indicating which ones are
869 inactive. If -c/--closed is specified, also list branches which have
869 inactive. If -c/--closed is specified, also list branches which have
870 been marked closed (see :hg:`commit --close-branch`).
870 been marked closed (see :hg:`commit --close-branch`).
871
871
872 If -a/--active is specified, only show active branches. A branch
872 If -a/--active is specified, only show active branches. A branch
873 is considered active if it contains repository heads.
873 is considered active if it contains repository heads.
874
874
875 Use the command :hg:`update` to switch to an existing branch.
875 Use the command :hg:`update` to switch to an existing branch.
876
876
877 Returns 0.
877 Returns 0.
878 """
878 """
879
879
880 hexfunc = ui.debugflag and hex or short
880 hexfunc = ui.debugflag and hex or short
881 activebranches = [repo[n].branch() for n in repo.heads()]
881 activebranches = [repo[n].branch() for n in repo.heads()]
882 def testactive(tag, node):
882 def testactive(tag, node):
883 realhead = tag in activebranches
883 realhead = tag in activebranches
884 open = node in repo.branchheads(tag, closed=False)
884 open = node in repo.branchheads(tag, closed=False)
885 return realhead and open
885 return realhead and open
886 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
886 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
887 for tag, node in repo.branchtags().items()],
887 for tag, node in repo.branchtags().items()],
888 reverse=True)
888 reverse=True)
889
889
890 for isactive, node, tag in branches:
890 for isactive, node, tag in branches:
891 if (not active) or isactive:
891 if (not active) or isactive:
892 if ui.quiet:
892 if ui.quiet:
893 ui.write("%s\n" % tag)
893 ui.write("%s\n" % tag)
894 else:
894 else:
895 hn = repo.lookup(node)
895 hn = repo.lookup(node)
896 if isactive:
896 if isactive:
897 label = 'branches.active'
897 label = 'branches.active'
898 notice = ''
898 notice = ''
899 elif hn not in repo.branchheads(tag, closed=False):
899 elif hn not in repo.branchheads(tag, closed=False):
900 if not closed:
900 if not closed:
901 continue
901 continue
902 label = 'branches.closed'
902 label = 'branches.closed'
903 notice = _(' (closed)')
903 notice = _(' (closed)')
904 else:
904 else:
905 label = 'branches.inactive'
905 label = 'branches.inactive'
906 notice = _(' (inactive)')
906 notice = _(' (inactive)')
907 if tag == repo.dirstate.branch():
907 if tag == repo.dirstate.branch():
908 label = 'branches.current'
908 label = 'branches.current'
909 rev = str(node).rjust(31 - encoding.colwidth(tag))
909 rev = str(node).rjust(31 - encoding.colwidth(tag))
910 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
910 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
911 tag = ui.label(tag, label)
911 tag = ui.label(tag, label)
912 ui.write("%s %s%s\n" % (tag, rev, notice))
912 ui.write("%s %s%s\n" % (tag, rev, notice))
913
913
914 @command('bundle',
914 @command('bundle',
915 [('f', 'force', None, _('run even when the destination is unrelated')),
915 [('f', 'force', None, _('run even when the destination is unrelated')),
916 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
916 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
917 _('REV')),
917 _('REV')),
918 ('b', 'branch', [], _('a specific branch you would like to bundle'),
918 ('b', 'branch', [], _('a specific branch you would like to bundle'),
919 _('BRANCH')),
919 _('BRANCH')),
920 ('', 'base', [],
920 ('', 'base', [],
921 _('a base changeset assumed to be available at the destination'),
921 _('a base changeset assumed to be available at the destination'),
922 _('REV')),
922 _('REV')),
923 ('a', 'all', None, _('bundle all changesets in the repository')),
923 ('a', 'all', None, _('bundle all changesets in the repository')),
924 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
924 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
925 ] + remoteopts,
925 ] + remoteopts,
926 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
926 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
927 def bundle(ui, repo, fname, dest=None, **opts):
927 def bundle(ui, repo, fname, dest=None, **opts):
928 """create a changegroup file
928 """create a changegroup file
929
929
930 Generate a compressed changegroup file collecting changesets not
930 Generate a compressed changegroup file collecting changesets not
931 known to be in another repository.
931 known to be in another repository.
932
932
933 If you omit the destination repository, then hg assumes the
933 If you omit the destination repository, then hg assumes the
934 destination will have all the nodes you specify with --base
934 destination will have all the nodes you specify with --base
935 parameters. To create a bundle containing all changesets, use
935 parameters. To create a bundle containing all changesets, use
936 -a/--all (or --base null).
936 -a/--all (or --base null).
937
937
938 You can change compression method with the -t/--type option.
938 You can change compression method with the -t/--type option.
939 The available compression methods are: none, bzip2, and
939 The available compression methods are: none, bzip2, and
940 gzip (by default, bundles are compressed using bzip2).
940 gzip (by default, bundles are compressed using bzip2).
941
941
942 The bundle file can then be transferred using conventional means
942 The bundle file can then be transferred using conventional means
943 and applied to another repository with the unbundle or pull
943 and applied to another repository with the unbundle or pull
944 command. This is useful when direct push and pull are not
944 command. This is useful when direct push and pull are not
945 available or when exporting an entire repository is undesirable.
945 available or when exporting an entire repository is undesirable.
946
946
947 Applying bundles preserves all changeset contents including
947 Applying bundles preserves all changeset contents including
948 permissions, copy/rename information, and revision history.
948 permissions, copy/rename information, and revision history.
949
949
950 Returns 0 on success, 1 if no changes found.
950 Returns 0 on success, 1 if no changes found.
951 """
951 """
952 revs = None
952 revs = None
953 if 'rev' in opts:
953 if 'rev' in opts:
954 revs = scmutil.revrange(repo, opts['rev'])
954 revs = scmutil.revrange(repo, opts['rev'])
955
955
956 if opts.get('all'):
956 if opts.get('all'):
957 base = ['null']
957 base = ['null']
958 else:
958 else:
959 base = scmutil.revrange(repo, opts.get('base'))
959 base = scmutil.revrange(repo, opts.get('base'))
960 if base:
960 if base:
961 if dest:
961 if dest:
962 raise util.Abort(_("--base is incompatible with specifying "
962 raise util.Abort(_("--base is incompatible with specifying "
963 "a destination"))
963 "a destination"))
964 common = [repo.lookup(rev) for rev in base]
964 common = [repo.lookup(rev) for rev in base]
965 heads = revs and map(repo.lookup, revs) or revs
965 heads = revs and map(repo.lookup, revs) or revs
966 else:
966 else:
967 dest = ui.expandpath(dest or 'default-push', dest or 'default')
967 dest = ui.expandpath(dest or 'default-push', dest or 'default')
968 dest, branches = hg.parseurl(dest, opts.get('branch'))
968 dest, branches = hg.parseurl(dest, opts.get('branch'))
969 other = hg.peer(repo, opts, dest)
969 other = hg.peer(repo, opts, dest)
970 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
970 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
971 heads = revs and map(repo.lookup, revs) or revs
971 heads = revs and map(repo.lookup, revs) or revs
972 common, outheads = discovery.findcommonoutgoing(repo, other,
972 common, outheads = discovery.findcommonoutgoing(repo, other,
973 onlyheads=heads,
973 onlyheads=heads,
974 force=opts.get('force'))
974 force=opts.get('force'))
975
975
976 cg = repo.getbundle('bundle', common=common, heads=heads)
976 cg = repo.getbundle('bundle', common=common, heads=heads)
977 if not cg:
977 if not cg:
978 ui.status(_("no changes found\n"))
978 ui.status(_("no changes found\n"))
979 return 1
979 return 1
980
980
981 bundletype = opts.get('type', 'bzip2').lower()
981 bundletype = opts.get('type', 'bzip2').lower()
982 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
982 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
983 bundletype = btypes.get(bundletype)
983 bundletype = btypes.get(bundletype)
984 if bundletype not in changegroup.bundletypes:
984 if bundletype not in changegroup.bundletypes:
985 raise util.Abort(_('unknown bundle type specified with --type'))
985 raise util.Abort(_('unknown bundle type specified with --type'))
986
986
987 changegroup.writebundle(cg, fname, bundletype)
987 changegroup.writebundle(cg, fname, bundletype)
988
988
989 @command('cat',
989 @command('cat',
990 [('o', 'output', '',
990 [('o', 'output', '',
991 _('print output to file with formatted name'), _('FORMAT')),
991 _('print output to file with formatted name'), _('FORMAT')),
992 ('r', 'rev', '', _('print the given revision'), _('REV')),
992 ('r', 'rev', '', _('print the given revision'), _('REV')),
993 ('', 'decode', None, _('apply any matching decode filter')),
993 ('', 'decode', None, _('apply any matching decode filter')),
994 ] + walkopts,
994 ] + walkopts,
995 _('[OPTION]... FILE...'))
995 _('[OPTION]... FILE...'))
996 def cat(ui, repo, file1, *pats, **opts):
996 def cat(ui, repo, file1, *pats, **opts):
997 """output the current or given revision of files
997 """output the current or given revision of files
998
998
999 Print the specified files as they were at the given revision. If
999 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,
1000 no revision is given, the parent of the working directory is used,
1001 or tip if no revision is checked out.
1001 or tip if no revision is checked out.
1002
1002
1003 Output may be to a file, in which case the name of the file is
1003 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
1004 given using a format string. The formatting rules are the same as
1005 for the export command, with the following additions:
1005 for the export command, with the following additions:
1006
1006
1007 :``%s``: basename of file being printed
1007 :``%s``: basename of file being printed
1008 :``%d``: dirname of file being printed, or '.' if in repository root
1008 :``%d``: dirname of file being printed, or '.' if in repository root
1009 :``%p``: root-relative path name of file being printed
1009 :``%p``: root-relative path name of file being printed
1010
1010
1011 Returns 0 on success.
1011 Returns 0 on success.
1012 """
1012 """
1013 ctx = scmutil.revsingle(repo, opts.get('rev'))
1013 ctx = scmutil.revsingle(repo, opts.get('rev'))
1014 err = 1
1014 err = 1
1015 m = scmutil.match(ctx, (file1,) + pats, opts)
1015 m = scmutil.match(ctx, (file1,) + pats, opts)
1016 for abs in ctx.walk(m):
1016 for abs in ctx.walk(m):
1017 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1017 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1018 pathname=abs)
1018 pathname=abs)
1019 data = ctx[abs].data()
1019 data = ctx[abs].data()
1020 if opts.get('decode'):
1020 if opts.get('decode'):
1021 data = repo.wwritedata(abs, data)
1021 data = repo.wwritedata(abs, data)
1022 fp.write(data)
1022 fp.write(data)
1023 fp.close()
1023 fp.close()
1024 err = 0
1024 err = 0
1025 return err
1025 return err
1026
1026
1027 @command('^clone',
1027 @command('^clone',
1028 [('U', 'noupdate', None,
1028 [('U', 'noupdate', None,
1029 _('the clone will include an empty working copy (only a repository)')),
1029 _('the clone will include an empty working copy (only a repository)')),
1030 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1030 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1031 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1031 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1032 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1032 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1033 ('', 'pull', None, _('use pull protocol to copy metadata')),
1033 ('', 'pull', None, _('use pull protocol to copy metadata')),
1034 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1034 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1035 ] + remoteopts,
1035 ] + remoteopts,
1036 _('[OPTION]... SOURCE [DEST]'))
1036 _('[OPTION]... SOURCE [DEST]'))
1037 def clone(ui, source, dest=None, **opts):
1037 def clone(ui, source, dest=None, **opts):
1038 """make a copy of an existing repository
1038 """make a copy of an existing repository
1039
1039
1040 Create a copy of an existing repository in a new directory.
1040 Create a copy of an existing repository in a new directory.
1041
1041
1042 If no destination directory name is specified, it defaults to the
1042 If no destination directory name is specified, it defaults to the
1043 basename of the source.
1043 basename of the source.
1044
1044
1045 The location of the source is added to the new repository's
1045 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.
1046 ``.hg/hgrc`` file, as the default to be used for future pulls.
1047
1047
1048 Only local paths and ``ssh://`` URLs are supported as
1048 Only local paths and ``ssh://`` URLs are supported as
1049 destinations. For ``ssh://`` destinations, no working directory or
1049 destinations. For ``ssh://`` destinations, no working directory or
1050 ``.hg/hgrc`` will be created on the remote side.
1050 ``.hg/hgrc`` will be created on the remote side.
1051
1051
1052 To pull only a subset of changesets, specify one or more revisions
1052 To pull only a subset of changesets, specify one or more revisions
1053 identifiers with -r/--rev or branches with -b/--branch. The
1053 identifiers with -r/--rev or branches with -b/--branch. The
1054 resulting clone will contain only the specified changesets and
1054 resulting clone will contain only the specified changesets and
1055 their ancestors. These options (or 'clone src#rev dest') imply
1055 their ancestors. These options (or 'clone src#rev dest') imply
1056 --pull, even for local source repositories. Note that specifying a
1056 --pull, even for local source repositories. Note that specifying a
1057 tag will include the tagged changeset but not the changeset
1057 tag will include the tagged changeset but not the changeset
1058 containing the tag.
1058 containing the tag.
1059
1059
1060 To check out a particular version, use -u/--update, or
1060 To check out a particular version, use -u/--update, or
1061 -U/--noupdate to create a clone with no working directory.
1061 -U/--noupdate to create a clone with no working directory.
1062
1062
1063 .. container:: verbose
1063 .. container:: verbose
1064
1064
1065 For efficiency, hardlinks are used for cloning whenever the
1065 For efficiency, hardlinks are used for cloning whenever the
1066 source and destination are on the same filesystem (note this
1066 source and destination are on the same filesystem (note this
1067 applies only to the repository data, not to the working
1067 applies only to the repository data, not to the working
1068 directory). Some filesystems, such as AFS, implement hardlinking
1068 directory). Some filesystems, such as AFS, implement hardlinking
1069 incorrectly, but do not report errors. In these cases, use the
1069 incorrectly, but do not report errors. In these cases, use the
1070 --pull option to avoid hardlinking.
1070 --pull option to avoid hardlinking.
1071
1071
1072 In some cases, you can clone repositories and the working
1072 In some cases, you can clone repositories and the working
1073 directory using full hardlinks with ::
1073 directory using full hardlinks with ::
1074
1074
1075 $ cp -al REPO REPOCLONE
1075 $ cp -al REPO REPOCLONE
1076
1076
1077 This is the fastest way to clone, but it is not always safe. The
1077 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
1078 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
1079 the operation is up to you) and you have to make sure your
1080 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1080 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1081 so). Also, this is not compatible with certain extensions that
1081 so). Also, this is not compatible with certain extensions that
1082 place their metadata under the .hg directory, such as mq.
1082 place their metadata under the .hg directory, such as mq.
1083
1083
1084 Mercurial will update the working directory to the first applicable
1084 Mercurial will update the working directory to the first applicable
1085 revision from this list:
1085 revision from this list:
1086
1086
1087 a) null if -U or the source repository has no changesets
1087 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
1088 b) if -u . and the source repository is local, the first parent of
1089 the source repository's working directory
1089 the source repository's working directory
1090 c) the changeset specified with -u (if a branch name, this means the
1090 c) the changeset specified with -u (if a branch name, this means the
1091 latest head of that branch)
1091 latest head of that branch)
1092 d) the changeset specified with -r
1092 d) the changeset specified with -r
1093 e) the tipmost head specified with -b
1093 e) the tipmost head specified with -b
1094 f) the tipmost head specified with the url#branch source syntax
1094 f) the tipmost head specified with the url#branch source syntax
1095 g) the tipmost head of the default branch
1095 g) the tipmost head of the default branch
1096 h) tip
1096 h) tip
1097
1097
1098 Examples:
1098 Examples:
1099
1099
1100 - clone a remote repository to a new directory named hg/::
1100 - clone a remote repository to a new directory named hg/::
1101
1101
1102 hg clone http://selenic.com/hg
1102 hg clone http://selenic.com/hg
1103
1103
1104 - create a lightweight local clone::
1104 - create a lightweight local clone::
1105
1105
1106 hg clone project/ project-feature/
1106 hg clone project/ project-feature/
1107
1107
1108 - clone from an absolute path on an ssh server (note double-slash)::
1108 - clone from an absolute path on an ssh server (note double-slash)::
1109
1109
1110 hg clone ssh://user@server//home/projects/alpha/
1110 hg clone ssh://user@server//home/projects/alpha/
1111
1111
1112 - do a high-speed clone over a LAN while checking out a
1112 - do a high-speed clone over a LAN while checking out a
1113 specified version::
1113 specified version::
1114
1114
1115 hg clone --uncompressed http://server/repo -u 1.5
1115 hg clone --uncompressed http://server/repo -u 1.5
1116
1116
1117 - create a repository without changesets after a particular revision::
1117 - create a repository without changesets after a particular revision::
1118
1118
1119 hg clone -r 04e544 experimental/ good/
1119 hg clone -r 04e544 experimental/ good/
1120
1120
1121 - clone (and track) a particular named branch::
1121 - clone (and track) a particular named branch::
1122
1122
1123 hg clone http://selenic.com/hg#stable
1123 hg clone http://selenic.com/hg#stable
1124
1124
1125 See :hg:`help urls` for details on specifying URLs.
1125 See :hg:`help urls` for details on specifying URLs.
1126
1126
1127 Returns 0 on success.
1127 Returns 0 on success.
1128 """
1128 """
1129 if opts.get('noupdate') and opts.get('updaterev'):
1129 if opts.get('noupdate') and opts.get('updaterev'):
1130 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1130 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1131
1131
1132 r = hg.clone(ui, opts, source, dest,
1132 r = hg.clone(ui, opts, source, dest,
1133 pull=opts.get('pull'),
1133 pull=opts.get('pull'),
1134 stream=opts.get('uncompressed'),
1134 stream=opts.get('uncompressed'),
1135 rev=opts.get('rev'),
1135 rev=opts.get('rev'),
1136 update=opts.get('updaterev') or not opts.get('noupdate'),
1136 update=opts.get('updaterev') or not opts.get('noupdate'),
1137 branch=opts.get('branch'))
1137 branch=opts.get('branch'))
1138
1138
1139 return r is None
1139 return r is None
1140
1140
1141 @command('^commit|ci',
1141 @command('^commit|ci',
1142 [('A', 'addremove', None,
1142 [('A', 'addremove', None,
1143 _('mark new/missing files as added/removed before committing')),
1143 _('mark new/missing files as added/removed before committing')),
1144 ('', 'close-branch', None,
1144 ('', 'close-branch', None,
1145 _('mark a branch as closed, hiding it from the branch list')),
1145 _('mark a branch as closed, hiding it from the branch list')),
1146 ] + walkopts + commitopts + commitopts2,
1146 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1147 _('[OPTION]... [FILE]...'))
1147 _('[OPTION]... [FILE]...'))
1148 def commit(ui, repo, *pats, **opts):
1148 def commit(ui, repo, *pats, **opts):
1149 """commit the specified files or all outstanding changes
1149 """commit the specified files or all outstanding changes
1150
1150
1151 Commit changes to the given files into the repository. Unlike a
1151 Commit changes to the given files into the repository. Unlike a
1152 centralized SCM, this operation is a local operation. See
1152 centralized SCM, this operation is a local operation. See
1153 :hg:`push` for a way to actively distribute your changes.
1153 :hg:`push` for a way to actively distribute your changes.
1154
1154
1155 If a list of files is omitted, all changes reported by :hg:`status`
1155 If a list of files is omitted, all changes reported by :hg:`status`
1156 will be committed.
1156 will be committed.
1157
1157
1158 If you are committing the result of a merge, do not provide any
1158 If you are committing the result of a merge, do not provide any
1159 filenames or -I/-X filters.
1159 filenames or -I/-X filters.
1160
1160
1161 If no commit message is specified, Mercurial starts your
1161 If no commit message is specified, Mercurial starts your
1162 configured editor where you can enter a message. In case your
1162 configured editor where you can enter a message. In case your
1163 commit fails, you will find a backup of your message in
1163 commit fails, you will find a backup of your message in
1164 ``.hg/last-message.txt``.
1164 ``.hg/last-message.txt``.
1165
1165
1166 See :hg:`help dates` for a list of formats valid for -d/--date.
1166 See :hg:`help dates` for a list of formats valid for -d/--date.
1167
1167
1168 Returns 0 on success, 1 if nothing changed.
1168 Returns 0 on success, 1 if nothing changed.
1169 """
1169 """
1170 if opts.get('subrepos'):
1171 # Let --subrepos on the command line overide config setting.
1172 ui.setconfig('ui', 'commitsubrepos', True)
1173
1170 extra = {}
1174 extra = {}
1171 if opts.get('close_branch'):
1175 if opts.get('close_branch'):
1172 if repo['.'].node() not in repo.branchheads():
1176 if repo['.'].node() not in repo.branchheads():
1173 # The topo heads set is included in the branch heads set of the
1177 # The topo heads set is included in the branch heads set of the
1174 # current branch, so it's sufficient to test branchheads
1178 # current branch, so it's sufficient to test branchheads
1175 raise util.Abort(_('can only close branch heads'))
1179 raise util.Abort(_('can only close branch heads'))
1176 extra['close'] = 1
1180 extra['close'] = 1
1177 e = cmdutil.commiteditor
1181 e = cmdutil.commiteditor
1178 if opts.get('force_editor'):
1182 if opts.get('force_editor'):
1179 e = cmdutil.commitforceeditor
1183 e = cmdutil.commitforceeditor
1180
1184
1181 def commitfunc(ui, repo, message, match, opts):
1185 def commitfunc(ui, repo, message, match, opts):
1182 return repo.commit(message, opts.get('user'), opts.get('date'), match,
1186 return repo.commit(message, opts.get('user'), opts.get('date'), match,
1183 editor=e, extra=extra)
1187 editor=e, extra=extra)
1184
1188
1185 branch = repo[None].branch()
1189 branch = repo[None].branch()
1186 bheads = repo.branchheads(branch)
1190 bheads = repo.branchheads(branch)
1187
1191
1188 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1192 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1189 if not node:
1193 if not node:
1190 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1194 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1191 if stat[3]:
1195 if stat[3]:
1192 ui.status(_("nothing changed (%d missing files, see 'hg status')\n")
1196 ui.status(_("nothing changed (%d missing files, see 'hg status')\n")
1193 % len(stat[3]))
1197 % len(stat[3]))
1194 else:
1198 else:
1195 ui.status(_("nothing changed\n"))
1199 ui.status(_("nothing changed\n"))
1196 return 1
1200 return 1
1197
1201
1198 ctx = repo[node]
1202 ctx = repo[node]
1199 parents = ctx.parents()
1203 parents = ctx.parents()
1200
1204
1201 if (bheads and node not in bheads and not
1205 if (bheads and node not in bheads and not
1202 [x for x in parents if x.node() in bheads and x.branch() == branch]):
1206 [x for x in parents if x.node() in bheads and x.branch() == branch]):
1203 ui.status(_('created new head\n'))
1207 ui.status(_('created new head\n'))
1204 # The message is not printed for initial roots. For the other
1208 # The message is not printed for initial roots. For the other
1205 # changesets, it is printed in the following situations:
1209 # changesets, it is printed in the following situations:
1206 #
1210 #
1207 # Par column: for the 2 parents with ...
1211 # Par column: for the 2 parents with ...
1208 # N: null or no parent
1212 # N: null or no parent
1209 # B: parent is on another named branch
1213 # B: parent is on another named branch
1210 # C: parent is a regular non head changeset
1214 # C: parent is a regular non head changeset
1211 # H: parent was a branch head of the current branch
1215 # H: parent was a branch head of the current branch
1212 # Msg column: whether we print "created new head" message
1216 # Msg column: whether we print "created new head" message
1213 # In the following, it is assumed that there already exists some
1217 # In the following, it is assumed that there already exists some
1214 # initial branch heads of the current branch, otherwise nothing is
1218 # initial branch heads of the current branch, otherwise nothing is
1215 # printed anyway.
1219 # printed anyway.
1216 #
1220 #
1217 # Par Msg Comment
1221 # Par Msg Comment
1218 # NN y additional topo root
1222 # NN y additional topo root
1219 #
1223 #
1220 # BN y additional branch root
1224 # BN y additional branch root
1221 # CN y additional topo head
1225 # CN y additional topo head
1222 # HN n usual case
1226 # HN n usual case
1223 #
1227 #
1224 # BB y weird additional branch root
1228 # BB y weird additional branch root
1225 # CB y branch merge
1229 # CB y branch merge
1226 # HB n merge with named branch
1230 # HB n merge with named branch
1227 #
1231 #
1228 # CC y additional head from merge
1232 # CC y additional head from merge
1229 # CH n merge with a head
1233 # CH n merge with a head
1230 #
1234 #
1231 # HH n head merge: head count decreases
1235 # HH n head merge: head count decreases
1232
1236
1233 if not opts.get('close_branch'):
1237 if not opts.get('close_branch'):
1234 for r in parents:
1238 for r in parents:
1235 if r.extra().get('close') and r.branch() == branch:
1239 if r.extra().get('close') and r.branch() == branch:
1236 ui.status(_('reopening closed branch head %d\n') % r)
1240 ui.status(_('reopening closed branch head %d\n') % r)
1237
1241
1238 if ui.debugflag:
1242 if ui.debugflag:
1239 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1243 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1240 elif ui.verbose:
1244 elif ui.verbose:
1241 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1245 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1242
1246
1243 @command('copy|cp',
1247 @command('copy|cp',
1244 [('A', 'after', None, _('record a copy that has already occurred')),
1248 [('A', 'after', None, _('record a copy that has already occurred')),
1245 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1249 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1246 ] + walkopts + dryrunopts,
1250 ] + walkopts + dryrunopts,
1247 _('[OPTION]... [SOURCE]... DEST'))
1251 _('[OPTION]... [SOURCE]... DEST'))
1248 def copy(ui, repo, *pats, **opts):
1252 def copy(ui, repo, *pats, **opts):
1249 """mark files as copied for the next commit
1253 """mark files as copied for the next commit
1250
1254
1251 Mark dest as having copies of source files. If dest is a
1255 Mark dest as having copies of source files. If dest is a
1252 directory, copies are put in that directory. If dest is a file,
1256 directory, copies are put in that directory. If dest is a file,
1253 the source must be a single file.
1257 the source must be a single file.
1254
1258
1255 By default, this command copies the contents of files as they
1259 By default, this command copies the contents of files as they
1256 exist in the working directory. If invoked with -A/--after, the
1260 exist in the working directory. If invoked with -A/--after, the
1257 operation is recorded, but no copying is performed.
1261 operation is recorded, but no copying is performed.
1258
1262
1259 This command takes effect with the next commit. To undo a copy
1263 This command takes effect with the next commit. To undo a copy
1260 before that, see :hg:`revert`.
1264 before that, see :hg:`revert`.
1261
1265
1262 Returns 0 on success, 1 if errors are encountered.
1266 Returns 0 on success, 1 if errors are encountered.
1263 """
1267 """
1264 wlock = repo.wlock(False)
1268 wlock = repo.wlock(False)
1265 try:
1269 try:
1266 return cmdutil.copy(ui, repo, pats, opts)
1270 return cmdutil.copy(ui, repo, pats, opts)
1267 finally:
1271 finally:
1268 wlock.release()
1272 wlock.release()
1269
1273
1270 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1274 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1271 def debugancestor(ui, repo, *args):
1275 def debugancestor(ui, repo, *args):
1272 """find the ancestor revision of two revisions in a given index"""
1276 """find the ancestor revision of two revisions in a given index"""
1273 if len(args) == 3:
1277 if len(args) == 3:
1274 index, rev1, rev2 = args
1278 index, rev1, rev2 = args
1275 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1279 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1276 lookup = r.lookup
1280 lookup = r.lookup
1277 elif len(args) == 2:
1281 elif len(args) == 2:
1278 if not repo:
1282 if not repo:
1279 raise util.Abort(_("there is no Mercurial repository here "
1283 raise util.Abort(_("there is no Mercurial repository here "
1280 "(.hg not found)"))
1284 "(.hg not found)"))
1281 rev1, rev2 = args
1285 rev1, rev2 = args
1282 r = repo.changelog
1286 r = repo.changelog
1283 lookup = repo.lookup
1287 lookup = repo.lookup
1284 else:
1288 else:
1285 raise util.Abort(_('either two or three arguments required'))
1289 raise util.Abort(_('either two or three arguments required'))
1286 a = r.ancestor(lookup(rev1), lookup(rev2))
1290 a = r.ancestor(lookup(rev1), lookup(rev2))
1287 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1291 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1288
1292
1289 @command('debugbuilddag',
1293 @command('debugbuilddag',
1290 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1294 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1291 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1295 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1292 ('n', 'new-file', None, _('add new file at each rev'))],
1296 ('n', 'new-file', None, _('add new file at each rev'))],
1293 _('[OPTION]... [TEXT]'))
1297 _('[OPTION]... [TEXT]'))
1294 def debugbuilddag(ui, repo, text=None,
1298 def debugbuilddag(ui, repo, text=None,
1295 mergeable_file=False,
1299 mergeable_file=False,
1296 overwritten_file=False,
1300 overwritten_file=False,
1297 new_file=False):
1301 new_file=False):
1298 """builds a repo with a given DAG from scratch in the current empty repo
1302 """builds a repo with a given DAG from scratch in the current empty repo
1299
1303
1300 The description of the DAG is read from stdin if not given on the
1304 The description of the DAG is read from stdin if not given on the
1301 command line.
1305 command line.
1302
1306
1303 Elements:
1307 Elements:
1304
1308
1305 - "+n" is a linear run of n nodes based on the current default parent
1309 - "+n" is a linear run of n nodes based on the current default parent
1306 - "." is a single node based on the current default parent
1310 - "." is a single node based on the current default parent
1307 - "$" resets the default parent to null (implied at the start);
1311 - "$" resets the default parent to null (implied at the start);
1308 otherwise the default parent is always the last node created
1312 otherwise the default parent is always the last node created
1309 - "<p" sets the default parent to the backref p
1313 - "<p" sets the default parent to the backref p
1310 - "*p" is a fork at parent p, which is a backref
1314 - "*p" is a fork at parent p, which is a backref
1311 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1315 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1312 - "/p2" is a merge of the preceding node and p2
1316 - "/p2" is a merge of the preceding node and p2
1313 - ":tag" defines a local tag for the preceding node
1317 - ":tag" defines a local tag for the preceding node
1314 - "@branch" sets the named branch for subsequent nodes
1318 - "@branch" sets the named branch for subsequent nodes
1315 - "#...\\n" is a comment up to the end of the line
1319 - "#...\\n" is a comment up to the end of the line
1316
1320
1317 Whitespace between the above elements is ignored.
1321 Whitespace between the above elements is ignored.
1318
1322
1319 A backref is either
1323 A backref is either
1320
1324
1321 - a number n, which references the node curr-n, where curr is the current
1325 - a number n, which references the node curr-n, where curr is the current
1322 node, or
1326 node, or
1323 - the name of a local tag you placed earlier using ":tag", or
1327 - the name of a local tag you placed earlier using ":tag", or
1324 - empty to denote the default parent.
1328 - empty to denote the default parent.
1325
1329
1326 All string valued-elements are either strictly alphanumeric, or must
1330 All string valued-elements are either strictly alphanumeric, or must
1327 be enclosed in double quotes ("..."), with "\\" as escape character.
1331 be enclosed in double quotes ("..."), with "\\" as escape character.
1328 """
1332 """
1329
1333
1330 if text is None:
1334 if text is None:
1331 ui.status(_("reading DAG from stdin\n"))
1335 ui.status(_("reading DAG from stdin\n"))
1332 text = ui.fin.read()
1336 text = ui.fin.read()
1333
1337
1334 cl = repo.changelog
1338 cl = repo.changelog
1335 if len(cl) > 0:
1339 if len(cl) > 0:
1336 raise util.Abort(_('repository is not empty'))
1340 raise util.Abort(_('repository is not empty'))
1337
1341
1338 # determine number of revs in DAG
1342 # determine number of revs in DAG
1339 total = 0
1343 total = 0
1340 for type, data in dagparser.parsedag(text):
1344 for type, data in dagparser.parsedag(text):
1341 if type == 'n':
1345 if type == 'n':
1342 total += 1
1346 total += 1
1343
1347
1344 if mergeable_file:
1348 if mergeable_file:
1345 linesperrev = 2
1349 linesperrev = 2
1346 # make a file with k lines per rev
1350 # make a file with k lines per rev
1347 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1351 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1348 initialmergedlines.append("")
1352 initialmergedlines.append("")
1349
1353
1350 tags = []
1354 tags = []
1351
1355
1352 tr = repo.transaction("builddag")
1356 tr = repo.transaction("builddag")
1353 try:
1357 try:
1354
1358
1355 at = -1
1359 at = -1
1356 atbranch = 'default'
1360 atbranch = 'default'
1357 nodeids = []
1361 nodeids = []
1358 ui.progress(_('building'), 0, unit=_('revisions'), total=total)
1362 ui.progress(_('building'), 0, unit=_('revisions'), total=total)
1359 for type, data in dagparser.parsedag(text):
1363 for type, data in dagparser.parsedag(text):
1360 if type == 'n':
1364 if type == 'n':
1361 ui.note('node %s\n' % str(data))
1365 ui.note('node %s\n' % str(data))
1362 id, ps = data
1366 id, ps = data
1363
1367
1364 files = []
1368 files = []
1365 fctxs = {}
1369 fctxs = {}
1366
1370
1367 p2 = None
1371 p2 = None
1368 if mergeable_file:
1372 if mergeable_file:
1369 fn = "mf"
1373 fn = "mf"
1370 p1 = repo[ps[0]]
1374 p1 = repo[ps[0]]
1371 if len(ps) > 1:
1375 if len(ps) > 1:
1372 p2 = repo[ps[1]]
1376 p2 = repo[ps[1]]
1373 pa = p1.ancestor(p2)
1377 pa = p1.ancestor(p2)
1374 base, local, other = [x[fn].data() for x in pa, p1, p2]
1378 base, local, other = [x[fn].data() for x in pa, p1, p2]
1375 m3 = simplemerge.Merge3Text(base, local, other)
1379 m3 = simplemerge.Merge3Text(base, local, other)
1376 ml = [l.strip() for l in m3.merge_lines()]
1380 ml = [l.strip() for l in m3.merge_lines()]
1377 ml.append("")
1381 ml.append("")
1378 elif at > 0:
1382 elif at > 0:
1379 ml = p1[fn].data().split("\n")
1383 ml = p1[fn].data().split("\n")
1380 else:
1384 else:
1381 ml = initialmergedlines
1385 ml = initialmergedlines
1382 ml[id * linesperrev] += " r%i" % id
1386 ml[id * linesperrev] += " r%i" % id
1383 mergedtext = "\n".join(ml)
1387 mergedtext = "\n".join(ml)
1384 files.append(fn)
1388 files.append(fn)
1385 fctxs[fn] = context.memfilectx(fn, mergedtext)
1389 fctxs[fn] = context.memfilectx(fn, mergedtext)
1386
1390
1387 if overwritten_file:
1391 if overwritten_file:
1388 fn = "of"
1392 fn = "of"
1389 files.append(fn)
1393 files.append(fn)
1390 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1394 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1391
1395
1392 if new_file:
1396 if new_file:
1393 fn = "nf%i" % id
1397 fn = "nf%i" % id
1394 files.append(fn)
1398 files.append(fn)
1395 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1399 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1396 if len(ps) > 1:
1400 if len(ps) > 1:
1397 if not p2:
1401 if not p2:
1398 p2 = repo[ps[1]]
1402 p2 = repo[ps[1]]
1399 for fn in p2:
1403 for fn in p2:
1400 if fn.startswith("nf"):
1404 if fn.startswith("nf"):
1401 files.append(fn)
1405 files.append(fn)
1402 fctxs[fn] = p2[fn]
1406 fctxs[fn] = p2[fn]
1403
1407
1404 def fctxfn(repo, cx, path):
1408 def fctxfn(repo, cx, path):
1405 return fctxs.get(path)
1409 return fctxs.get(path)
1406
1410
1407 if len(ps) == 0 or ps[0] < 0:
1411 if len(ps) == 0 or ps[0] < 0:
1408 pars = [None, None]
1412 pars = [None, None]
1409 elif len(ps) == 1:
1413 elif len(ps) == 1:
1410 pars = [nodeids[ps[0]], None]
1414 pars = [nodeids[ps[0]], None]
1411 else:
1415 else:
1412 pars = [nodeids[p] for p in ps]
1416 pars = [nodeids[p] for p in ps]
1413 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1417 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1414 date=(id, 0),
1418 date=(id, 0),
1415 user="debugbuilddag",
1419 user="debugbuilddag",
1416 extra={'branch': atbranch})
1420 extra={'branch': atbranch})
1417 nodeid = repo.commitctx(cx)
1421 nodeid = repo.commitctx(cx)
1418 nodeids.append(nodeid)
1422 nodeids.append(nodeid)
1419 at = id
1423 at = id
1420 elif type == 'l':
1424 elif type == 'l':
1421 id, name = data
1425 id, name = data
1422 ui.note('tag %s\n' % name)
1426 ui.note('tag %s\n' % name)
1423 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1427 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1424 elif type == 'a':
1428 elif type == 'a':
1425 ui.note('branch %s\n' % data)
1429 ui.note('branch %s\n' % data)
1426 atbranch = data
1430 atbranch = data
1427 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1431 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1428 tr.close()
1432 tr.close()
1429 finally:
1433 finally:
1430 ui.progress(_('building'), None)
1434 ui.progress(_('building'), None)
1431 tr.release()
1435 tr.release()
1432
1436
1433 if tags:
1437 if tags:
1434 repo.opener.write("localtags", "".join(tags))
1438 repo.opener.write("localtags", "".join(tags))
1435
1439
1436 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1440 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1437 def debugbundle(ui, bundlepath, all=None, **opts):
1441 def debugbundle(ui, bundlepath, all=None, **opts):
1438 """lists the contents of a bundle"""
1442 """lists the contents of a bundle"""
1439 f = url.open(ui, bundlepath)
1443 f = url.open(ui, bundlepath)
1440 try:
1444 try:
1441 gen = changegroup.readbundle(f, bundlepath)
1445 gen = changegroup.readbundle(f, bundlepath)
1442 if all:
1446 if all:
1443 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1447 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1444
1448
1445 def showchunks(named):
1449 def showchunks(named):
1446 ui.write("\n%s\n" % named)
1450 ui.write("\n%s\n" % named)
1447 chain = None
1451 chain = None
1448 while True:
1452 while True:
1449 chunkdata = gen.deltachunk(chain)
1453 chunkdata = gen.deltachunk(chain)
1450 if not chunkdata:
1454 if not chunkdata:
1451 break
1455 break
1452 node = chunkdata['node']
1456 node = chunkdata['node']
1453 p1 = chunkdata['p1']
1457 p1 = chunkdata['p1']
1454 p2 = chunkdata['p2']
1458 p2 = chunkdata['p2']
1455 cs = chunkdata['cs']
1459 cs = chunkdata['cs']
1456 deltabase = chunkdata['deltabase']
1460 deltabase = chunkdata['deltabase']
1457 delta = chunkdata['delta']
1461 delta = chunkdata['delta']
1458 ui.write("%s %s %s %s %s %s\n" %
1462 ui.write("%s %s %s %s %s %s\n" %
1459 (hex(node), hex(p1), hex(p2),
1463 (hex(node), hex(p1), hex(p2),
1460 hex(cs), hex(deltabase), len(delta)))
1464 hex(cs), hex(deltabase), len(delta)))
1461 chain = node
1465 chain = node
1462
1466
1463 chunkdata = gen.changelogheader()
1467 chunkdata = gen.changelogheader()
1464 showchunks("changelog")
1468 showchunks("changelog")
1465 chunkdata = gen.manifestheader()
1469 chunkdata = gen.manifestheader()
1466 showchunks("manifest")
1470 showchunks("manifest")
1467 while True:
1471 while True:
1468 chunkdata = gen.filelogheader()
1472 chunkdata = gen.filelogheader()
1469 if not chunkdata:
1473 if not chunkdata:
1470 break
1474 break
1471 fname = chunkdata['filename']
1475 fname = chunkdata['filename']
1472 showchunks(fname)
1476 showchunks(fname)
1473 else:
1477 else:
1474 chunkdata = gen.changelogheader()
1478 chunkdata = gen.changelogheader()
1475 chain = None
1479 chain = None
1476 while True:
1480 while True:
1477 chunkdata = gen.deltachunk(chain)
1481 chunkdata = gen.deltachunk(chain)
1478 if not chunkdata:
1482 if not chunkdata:
1479 break
1483 break
1480 node = chunkdata['node']
1484 node = chunkdata['node']
1481 ui.write("%s\n" % hex(node))
1485 ui.write("%s\n" % hex(node))
1482 chain = node
1486 chain = node
1483 finally:
1487 finally:
1484 f.close()
1488 f.close()
1485
1489
1486 @command('debugcheckstate', [], '')
1490 @command('debugcheckstate', [], '')
1487 def debugcheckstate(ui, repo):
1491 def debugcheckstate(ui, repo):
1488 """validate the correctness of the current dirstate"""
1492 """validate the correctness of the current dirstate"""
1489 parent1, parent2 = repo.dirstate.parents()
1493 parent1, parent2 = repo.dirstate.parents()
1490 m1 = repo[parent1].manifest()
1494 m1 = repo[parent1].manifest()
1491 m2 = repo[parent2].manifest()
1495 m2 = repo[parent2].manifest()
1492 errors = 0
1496 errors = 0
1493 for f in repo.dirstate:
1497 for f in repo.dirstate:
1494 state = repo.dirstate[f]
1498 state = repo.dirstate[f]
1495 if state in "nr" and f not in m1:
1499 if state in "nr" and f not in m1:
1496 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1500 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1497 errors += 1
1501 errors += 1
1498 if state in "a" and f in m1:
1502 if state in "a" and f in m1:
1499 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1503 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1500 errors += 1
1504 errors += 1
1501 if state in "m" and f not in m1 and f not in m2:
1505 if state in "m" and f not in m1 and f not in m2:
1502 ui.warn(_("%s in state %s, but not in either manifest\n") %
1506 ui.warn(_("%s in state %s, but not in either manifest\n") %
1503 (f, state))
1507 (f, state))
1504 errors += 1
1508 errors += 1
1505 for f in m1:
1509 for f in m1:
1506 state = repo.dirstate[f]
1510 state = repo.dirstate[f]
1507 if state not in "nrm":
1511 if state not in "nrm":
1508 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1512 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1509 errors += 1
1513 errors += 1
1510 if errors:
1514 if errors:
1511 error = _(".hg/dirstate inconsistent with current parent's manifest")
1515 error = _(".hg/dirstate inconsistent with current parent's manifest")
1512 raise util.Abort(error)
1516 raise util.Abort(error)
1513
1517
1514 @command('debugcommands', [], _('[COMMAND]'))
1518 @command('debugcommands', [], _('[COMMAND]'))
1515 def debugcommands(ui, cmd='', *args):
1519 def debugcommands(ui, cmd='', *args):
1516 """list all available commands and options"""
1520 """list all available commands and options"""
1517 for cmd, vals in sorted(table.iteritems()):
1521 for cmd, vals in sorted(table.iteritems()):
1518 cmd = cmd.split('|')[0].strip('^')
1522 cmd = cmd.split('|')[0].strip('^')
1519 opts = ', '.join([i[1] for i in vals[1]])
1523 opts = ', '.join([i[1] for i in vals[1]])
1520 ui.write('%s: %s\n' % (cmd, opts))
1524 ui.write('%s: %s\n' % (cmd, opts))
1521
1525
1522 @command('debugcomplete',
1526 @command('debugcomplete',
1523 [('o', 'options', None, _('show the command options'))],
1527 [('o', 'options', None, _('show the command options'))],
1524 _('[-o] CMD'))
1528 _('[-o] CMD'))
1525 def debugcomplete(ui, cmd='', **opts):
1529 def debugcomplete(ui, cmd='', **opts):
1526 """returns the completion list associated with the given command"""
1530 """returns the completion list associated with the given command"""
1527
1531
1528 if opts.get('options'):
1532 if opts.get('options'):
1529 options = []
1533 options = []
1530 otables = [globalopts]
1534 otables = [globalopts]
1531 if cmd:
1535 if cmd:
1532 aliases, entry = cmdutil.findcmd(cmd, table, False)
1536 aliases, entry = cmdutil.findcmd(cmd, table, False)
1533 otables.append(entry[1])
1537 otables.append(entry[1])
1534 for t in otables:
1538 for t in otables:
1535 for o in t:
1539 for o in t:
1536 if "(DEPRECATED)" in o[3]:
1540 if "(DEPRECATED)" in o[3]:
1537 continue
1541 continue
1538 if o[0]:
1542 if o[0]:
1539 options.append('-%s' % o[0])
1543 options.append('-%s' % o[0])
1540 options.append('--%s' % o[1])
1544 options.append('--%s' % o[1])
1541 ui.write("%s\n" % "\n".join(options))
1545 ui.write("%s\n" % "\n".join(options))
1542 return
1546 return
1543
1547
1544 cmdlist = cmdutil.findpossible(cmd, table)
1548 cmdlist = cmdutil.findpossible(cmd, table)
1545 if ui.verbose:
1549 if ui.verbose:
1546 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1550 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1547 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1551 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1548
1552
1549 @command('debugdag',
1553 @command('debugdag',
1550 [('t', 'tags', None, _('use tags as labels')),
1554 [('t', 'tags', None, _('use tags as labels')),
1551 ('b', 'branches', None, _('annotate with branch names')),
1555 ('b', 'branches', None, _('annotate with branch names')),
1552 ('', 'dots', None, _('use dots for runs')),
1556 ('', 'dots', None, _('use dots for runs')),
1553 ('s', 'spaces', None, _('separate elements by spaces'))],
1557 ('s', 'spaces', None, _('separate elements by spaces'))],
1554 _('[OPTION]... [FILE [REV]...]'))
1558 _('[OPTION]... [FILE [REV]...]'))
1555 def debugdag(ui, repo, file_=None, *revs, **opts):
1559 def debugdag(ui, repo, file_=None, *revs, **opts):
1556 """format the changelog or an index DAG as a concise textual description
1560 """format the changelog or an index DAG as a concise textual description
1557
1561
1558 If you pass a revlog index, the revlog's DAG is emitted. If you list
1562 If you pass a revlog index, the revlog's DAG is emitted. If you list
1559 revision numbers, they get labelled in the output as rN.
1563 revision numbers, they get labelled in the output as rN.
1560
1564
1561 Otherwise, the changelog DAG of the current repo is emitted.
1565 Otherwise, the changelog DAG of the current repo is emitted.
1562 """
1566 """
1563 spaces = opts.get('spaces')
1567 spaces = opts.get('spaces')
1564 dots = opts.get('dots')
1568 dots = opts.get('dots')
1565 if file_:
1569 if file_:
1566 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1570 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1567 revs = set((int(r) for r in revs))
1571 revs = set((int(r) for r in revs))
1568 def events():
1572 def events():
1569 for r in rlog:
1573 for r in rlog:
1570 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1574 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1571 if r in revs:
1575 if r in revs:
1572 yield 'l', (r, "r%i" % r)
1576 yield 'l', (r, "r%i" % r)
1573 elif repo:
1577 elif repo:
1574 cl = repo.changelog
1578 cl = repo.changelog
1575 tags = opts.get('tags')
1579 tags = opts.get('tags')
1576 branches = opts.get('branches')
1580 branches = opts.get('branches')
1577 if tags:
1581 if tags:
1578 labels = {}
1582 labels = {}
1579 for l, n in repo.tags().items():
1583 for l, n in repo.tags().items():
1580 labels.setdefault(cl.rev(n), []).append(l)
1584 labels.setdefault(cl.rev(n), []).append(l)
1581 def events():
1585 def events():
1582 b = "default"
1586 b = "default"
1583 for r in cl:
1587 for r in cl:
1584 if branches:
1588 if branches:
1585 newb = cl.read(cl.node(r))[5]['branch']
1589 newb = cl.read(cl.node(r))[5]['branch']
1586 if newb != b:
1590 if newb != b:
1587 yield 'a', newb
1591 yield 'a', newb
1588 b = newb
1592 b = newb
1589 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1593 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1590 if tags:
1594 if tags:
1591 ls = labels.get(r)
1595 ls = labels.get(r)
1592 if ls:
1596 if ls:
1593 for l in ls:
1597 for l in ls:
1594 yield 'l', (r, l)
1598 yield 'l', (r, l)
1595 else:
1599 else:
1596 raise util.Abort(_('need repo for changelog dag'))
1600 raise util.Abort(_('need repo for changelog dag'))
1597
1601
1598 for line in dagparser.dagtextlines(events(),
1602 for line in dagparser.dagtextlines(events(),
1599 addspaces=spaces,
1603 addspaces=spaces,
1600 wraplabels=True,
1604 wraplabels=True,
1601 wrapannotations=True,
1605 wrapannotations=True,
1602 wrapnonlinear=dots,
1606 wrapnonlinear=dots,
1603 usedots=dots,
1607 usedots=dots,
1604 maxlinewidth=70):
1608 maxlinewidth=70):
1605 ui.write(line)
1609 ui.write(line)
1606 ui.write("\n")
1610 ui.write("\n")
1607
1611
1608 @command('debugdata',
1612 @command('debugdata',
1609 [('c', 'changelog', False, _('open changelog')),
1613 [('c', 'changelog', False, _('open changelog')),
1610 ('m', 'manifest', False, _('open manifest'))],
1614 ('m', 'manifest', False, _('open manifest'))],
1611 _('-c|-m|FILE REV'))
1615 _('-c|-m|FILE REV'))
1612 def debugdata(ui, repo, file_, rev = None, **opts):
1616 def debugdata(ui, repo, file_, rev = None, **opts):
1613 """dump the contents of a data file revision"""
1617 """dump the contents of a data file revision"""
1614 if opts.get('changelog') or opts.get('manifest'):
1618 if opts.get('changelog') or opts.get('manifest'):
1615 file_, rev = None, file_
1619 file_, rev = None, file_
1616 elif rev is None:
1620 elif rev is None:
1617 raise error.CommandError('debugdata', _('invalid arguments'))
1621 raise error.CommandError('debugdata', _('invalid arguments'))
1618 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1622 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1619 try:
1623 try:
1620 ui.write(r.revision(r.lookup(rev)))
1624 ui.write(r.revision(r.lookup(rev)))
1621 except KeyError:
1625 except KeyError:
1622 raise util.Abort(_('invalid revision identifier %s') % rev)
1626 raise util.Abort(_('invalid revision identifier %s') % rev)
1623
1627
1624 @command('debugdate',
1628 @command('debugdate',
1625 [('e', 'extended', None, _('try extended date formats'))],
1629 [('e', 'extended', None, _('try extended date formats'))],
1626 _('[-e] DATE [RANGE]'))
1630 _('[-e] DATE [RANGE]'))
1627 def debugdate(ui, date, range=None, **opts):
1631 def debugdate(ui, date, range=None, **opts):
1628 """parse and display a date"""
1632 """parse and display a date"""
1629 if opts["extended"]:
1633 if opts["extended"]:
1630 d = util.parsedate(date, util.extendeddateformats)
1634 d = util.parsedate(date, util.extendeddateformats)
1631 else:
1635 else:
1632 d = util.parsedate(date)
1636 d = util.parsedate(date)
1633 ui.write("internal: %s %s\n" % d)
1637 ui.write("internal: %s %s\n" % d)
1634 ui.write("standard: %s\n" % util.datestr(d))
1638 ui.write("standard: %s\n" % util.datestr(d))
1635 if range:
1639 if range:
1636 m = util.matchdate(range)
1640 m = util.matchdate(range)
1637 ui.write("match: %s\n" % m(d[0]))
1641 ui.write("match: %s\n" % m(d[0]))
1638
1642
1639 @command('debugdiscovery',
1643 @command('debugdiscovery',
1640 [('', 'old', None, _('use old-style discovery')),
1644 [('', 'old', None, _('use old-style discovery')),
1641 ('', 'nonheads', None,
1645 ('', 'nonheads', None,
1642 _('use old-style discovery with non-heads included')),
1646 _('use old-style discovery with non-heads included')),
1643 ] + remoteopts,
1647 ] + remoteopts,
1644 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1648 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1645 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1649 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1646 """runs the changeset discovery protocol in isolation"""
1650 """runs the changeset discovery protocol in isolation"""
1647 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl), opts.get('branch'))
1651 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl), opts.get('branch'))
1648 remote = hg.peer(repo, opts, remoteurl)
1652 remote = hg.peer(repo, opts, remoteurl)
1649 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1653 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1650
1654
1651 # make sure tests are repeatable
1655 # make sure tests are repeatable
1652 random.seed(12323)
1656 random.seed(12323)
1653
1657
1654 def doit(localheads, remoteheads):
1658 def doit(localheads, remoteheads):
1655 if opts.get('old'):
1659 if opts.get('old'):
1656 if localheads:
1660 if localheads:
1657 raise util.Abort('cannot use localheads with old style discovery')
1661 raise util.Abort('cannot use localheads with old style discovery')
1658 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1662 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1659 force=True)
1663 force=True)
1660 common = set(common)
1664 common = set(common)
1661 if not opts.get('nonheads'):
1665 if not opts.get('nonheads'):
1662 ui.write("unpruned common: %s\n" % " ".join([short(n)
1666 ui.write("unpruned common: %s\n" % " ".join([short(n)
1663 for n in common]))
1667 for n in common]))
1664 dag = dagutil.revlogdag(repo.changelog)
1668 dag = dagutil.revlogdag(repo.changelog)
1665 all = dag.ancestorset(dag.internalizeall(common))
1669 all = dag.ancestorset(dag.internalizeall(common))
1666 common = dag.externalizeall(dag.headsetofconnecteds(all))
1670 common = dag.externalizeall(dag.headsetofconnecteds(all))
1667 else:
1671 else:
1668 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1672 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1669 common = set(common)
1673 common = set(common)
1670 rheads = set(hds)
1674 rheads = set(hds)
1671 lheads = set(repo.heads())
1675 lheads = set(repo.heads())
1672 ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
1676 ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
1673 if lheads <= common:
1677 if lheads <= common:
1674 ui.write("local is subset\n")
1678 ui.write("local is subset\n")
1675 elif rheads <= common:
1679 elif rheads <= common:
1676 ui.write("remote is subset\n")
1680 ui.write("remote is subset\n")
1677
1681
1678 serverlogs = opts.get('serverlog')
1682 serverlogs = opts.get('serverlog')
1679 if serverlogs:
1683 if serverlogs:
1680 for filename in serverlogs:
1684 for filename in serverlogs:
1681 logfile = open(filename, 'r')
1685 logfile = open(filename, 'r')
1682 try:
1686 try:
1683 line = logfile.readline()
1687 line = logfile.readline()
1684 while line:
1688 while line:
1685 parts = line.strip().split(';')
1689 parts = line.strip().split(';')
1686 op = parts[1]
1690 op = parts[1]
1687 if op == 'cg':
1691 if op == 'cg':
1688 pass
1692 pass
1689 elif op == 'cgss':
1693 elif op == 'cgss':
1690 doit(parts[2].split(' '), parts[3].split(' '))
1694 doit(parts[2].split(' '), parts[3].split(' '))
1691 elif op == 'unb':
1695 elif op == 'unb':
1692 doit(parts[3].split(' '), parts[2].split(' '))
1696 doit(parts[3].split(' '), parts[2].split(' '))
1693 line = logfile.readline()
1697 line = logfile.readline()
1694 finally:
1698 finally:
1695 logfile.close()
1699 logfile.close()
1696
1700
1697 else:
1701 else:
1698 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1702 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1699 opts.get('remote_head'))
1703 opts.get('remote_head'))
1700 localrevs = opts.get('local_head')
1704 localrevs = opts.get('local_head')
1701 doit(localrevs, remoterevs)
1705 doit(localrevs, remoterevs)
1702
1706
1703 @command('debugfileset', [], ('REVSPEC'))
1707 @command('debugfileset', [], ('REVSPEC'))
1704 def debugfileset(ui, repo, expr):
1708 def debugfileset(ui, repo, expr):
1705 '''parse and apply a fileset specification'''
1709 '''parse and apply a fileset specification'''
1706 if ui.verbose:
1710 if ui.verbose:
1707 tree = fileset.parse(expr)[0]
1711 tree = fileset.parse(expr)[0]
1708 ui.note(tree, "\n")
1712 ui.note(tree, "\n")
1709
1713
1710 for f in fileset.getfileset(repo[None], expr):
1714 for f in fileset.getfileset(repo[None], expr):
1711 ui.write("%s\n" % f)
1715 ui.write("%s\n" % f)
1712
1716
1713 @command('debugfsinfo', [], _('[PATH]'))
1717 @command('debugfsinfo', [], _('[PATH]'))
1714 def debugfsinfo(ui, path = "."):
1718 def debugfsinfo(ui, path = "."):
1715 """show information detected about current filesystem"""
1719 """show information detected about current filesystem"""
1716 util.writefile('.debugfsinfo', '')
1720 util.writefile('.debugfsinfo', '')
1717 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1721 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1718 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1722 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1719 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1723 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1720 and 'yes' or 'no'))
1724 and 'yes' or 'no'))
1721 os.unlink('.debugfsinfo')
1725 os.unlink('.debugfsinfo')
1722
1726
1723 @command('debuggetbundle',
1727 @command('debuggetbundle',
1724 [('H', 'head', [], _('id of head node'), _('ID')),
1728 [('H', 'head', [], _('id of head node'), _('ID')),
1725 ('C', 'common', [], _('id of common node'), _('ID')),
1729 ('C', 'common', [], _('id of common node'), _('ID')),
1726 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1730 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1727 _('REPO FILE [-H|-C ID]...'))
1731 _('REPO FILE [-H|-C ID]...'))
1728 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1732 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1729 """retrieves a bundle from a repo
1733 """retrieves a bundle from a repo
1730
1734
1731 Every ID must be a full-length hex node id string. Saves the bundle to the
1735 Every ID must be a full-length hex node id string. Saves the bundle to the
1732 given file.
1736 given file.
1733 """
1737 """
1734 repo = hg.peer(ui, opts, repopath)
1738 repo = hg.peer(ui, opts, repopath)
1735 if not repo.capable('getbundle'):
1739 if not repo.capable('getbundle'):
1736 raise util.Abort("getbundle() not supported by target repository")
1740 raise util.Abort("getbundle() not supported by target repository")
1737 args = {}
1741 args = {}
1738 if common:
1742 if common:
1739 args['common'] = [bin(s) for s in common]
1743 args['common'] = [bin(s) for s in common]
1740 if head:
1744 if head:
1741 args['heads'] = [bin(s) for s in head]
1745 args['heads'] = [bin(s) for s in head]
1742 bundle = repo.getbundle('debug', **args)
1746 bundle = repo.getbundle('debug', **args)
1743
1747
1744 bundletype = opts.get('type', 'bzip2').lower()
1748 bundletype = opts.get('type', 'bzip2').lower()
1745 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1749 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1746 bundletype = btypes.get(bundletype)
1750 bundletype = btypes.get(bundletype)
1747 if bundletype not in changegroup.bundletypes:
1751 if bundletype not in changegroup.bundletypes:
1748 raise util.Abort(_('unknown bundle type specified with --type'))
1752 raise util.Abort(_('unknown bundle type specified with --type'))
1749 changegroup.writebundle(bundle, bundlepath, bundletype)
1753 changegroup.writebundle(bundle, bundlepath, bundletype)
1750
1754
1751 @command('debugignore', [], '')
1755 @command('debugignore', [], '')
1752 def debugignore(ui, repo, *values, **opts):
1756 def debugignore(ui, repo, *values, **opts):
1753 """display the combined ignore pattern"""
1757 """display the combined ignore pattern"""
1754 ignore = repo.dirstate._ignore
1758 ignore = repo.dirstate._ignore
1755 includepat = getattr(ignore, 'includepat', None)
1759 includepat = getattr(ignore, 'includepat', None)
1756 if includepat is not None:
1760 if includepat is not None:
1757 ui.write("%s\n" % includepat)
1761 ui.write("%s\n" % includepat)
1758 else:
1762 else:
1759 raise util.Abort(_("no ignore patterns found"))
1763 raise util.Abort(_("no ignore patterns found"))
1760
1764
1761 @command('debugindex',
1765 @command('debugindex',
1762 [('c', 'changelog', False, _('open changelog')),
1766 [('c', 'changelog', False, _('open changelog')),
1763 ('m', 'manifest', False, _('open manifest')),
1767 ('m', 'manifest', False, _('open manifest')),
1764 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1768 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1765 _('[-f FORMAT] -c|-m|FILE'))
1769 _('[-f FORMAT] -c|-m|FILE'))
1766 def debugindex(ui, repo, file_ = None, **opts):
1770 def debugindex(ui, repo, file_ = None, **opts):
1767 """dump the contents of an index file"""
1771 """dump the contents of an index file"""
1768 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1772 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1769 format = opts.get('format', 0)
1773 format = opts.get('format', 0)
1770 if format not in (0, 1):
1774 if format not in (0, 1):
1771 raise util.Abort(_("unknown format %d") % format)
1775 raise util.Abort(_("unknown format %d") % format)
1772
1776
1773 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1777 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1774 if generaldelta:
1778 if generaldelta:
1775 basehdr = ' delta'
1779 basehdr = ' delta'
1776 else:
1780 else:
1777 basehdr = ' base'
1781 basehdr = ' base'
1778
1782
1779 if format == 0:
1783 if format == 0:
1780 ui.write(" rev offset length " + basehdr + " linkrev"
1784 ui.write(" rev offset length " + basehdr + " linkrev"
1781 " nodeid p1 p2\n")
1785 " nodeid p1 p2\n")
1782 elif format == 1:
1786 elif format == 1:
1783 ui.write(" rev flag offset length"
1787 ui.write(" rev flag offset length"
1784 " size " + basehdr + " link p1 p2 nodeid\n")
1788 " size " + basehdr + " link p1 p2 nodeid\n")
1785
1789
1786 for i in r:
1790 for i in r:
1787 node = r.node(i)
1791 node = r.node(i)
1788 if generaldelta:
1792 if generaldelta:
1789 base = r.deltaparent(i)
1793 base = r.deltaparent(i)
1790 else:
1794 else:
1791 base = r.chainbase(i)
1795 base = r.chainbase(i)
1792 if format == 0:
1796 if format == 0:
1793 try:
1797 try:
1794 pp = r.parents(node)
1798 pp = r.parents(node)
1795 except:
1799 except:
1796 pp = [nullid, nullid]
1800 pp = [nullid, nullid]
1797 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1801 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1798 i, r.start(i), r.length(i), base, r.linkrev(i),
1802 i, r.start(i), r.length(i), base, r.linkrev(i),
1799 short(node), short(pp[0]), short(pp[1])))
1803 short(node), short(pp[0]), short(pp[1])))
1800 elif format == 1:
1804 elif format == 1:
1801 pr = r.parentrevs(i)
1805 pr = r.parentrevs(i)
1802 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1806 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1803 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1807 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1804 base, r.linkrev(i), pr[0], pr[1], short(node)))
1808 base, r.linkrev(i), pr[0], pr[1], short(node)))
1805
1809
1806 @command('debugindexdot', [], _('FILE'))
1810 @command('debugindexdot', [], _('FILE'))
1807 def debugindexdot(ui, repo, file_):
1811 def debugindexdot(ui, repo, file_):
1808 """dump an index DAG as a graphviz dot file"""
1812 """dump an index DAG as a graphviz dot file"""
1809 r = None
1813 r = None
1810 if repo:
1814 if repo:
1811 filelog = repo.file(file_)
1815 filelog = repo.file(file_)
1812 if len(filelog):
1816 if len(filelog):
1813 r = filelog
1817 r = filelog
1814 if not r:
1818 if not r:
1815 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1819 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1816 ui.write("digraph G {\n")
1820 ui.write("digraph G {\n")
1817 for i in r:
1821 for i in r:
1818 node = r.node(i)
1822 node = r.node(i)
1819 pp = r.parents(node)
1823 pp = r.parents(node)
1820 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1824 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1821 if pp[1] != nullid:
1825 if pp[1] != nullid:
1822 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1826 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1823 ui.write("}\n")
1827 ui.write("}\n")
1824
1828
1825 @command('debuginstall', [], '')
1829 @command('debuginstall', [], '')
1826 def debuginstall(ui):
1830 def debuginstall(ui):
1827 '''test Mercurial installation
1831 '''test Mercurial installation
1828
1832
1829 Returns 0 on success.
1833 Returns 0 on success.
1830 '''
1834 '''
1831
1835
1832 def writetemp(contents):
1836 def writetemp(contents):
1833 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1837 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1834 f = os.fdopen(fd, "wb")
1838 f = os.fdopen(fd, "wb")
1835 f.write(contents)
1839 f.write(contents)
1836 f.close()
1840 f.close()
1837 return name
1841 return name
1838
1842
1839 problems = 0
1843 problems = 0
1840
1844
1841 # encoding
1845 # encoding
1842 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1846 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1843 try:
1847 try:
1844 encoding.fromlocal("test")
1848 encoding.fromlocal("test")
1845 except util.Abort, inst:
1849 except util.Abort, inst:
1846 ui.write(" %s\n" % inst)
1850 ui.write(" %s\n" % inst)
1847 ui.write(_(" (check that your locale is properly set)\n"))
1851 ui.write(_(" (check that your locale is properly set)\n"))
1848 problems += 1
1852 problems += 1
1849
1853
1850 # compiled modules
1854 # compiled modules
1851 ui.status(_("Checking installed modules (%s)...\n")
1855 ui.status(_("Checking installed modules (%s)...\n")
1852 % os.path.dirname(__file__))
1856 % os.path.dirname(__file__))
1853 try:
1857 try:
1854 import bdiff, mpatch, base85, osutil
1858 import bdiff, mpatch, base85, osutil
1855 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
1859 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
1856 except Exception, inst:
1860 except Exception, inst:
1857 ui.write(" %s\n" % inst)
1861 ui.write(" %s\n" % inst)
1858 ui.write(_(" One or more extensions could not be found"))
1862 ui.write(_(" One or more extensions could not be found"))
1859 ui.write(_(" (check that you compiled the extensions)\n"))
1863 ui.write(_(" (check that you compiled the extensions)\n"))
1860 problems += 1
1864 problems += 1
1861
1865
1862 # templates
1866 # templates
1863 import templater
1867 import templater
1864 p = templater.templatepath()
1868 p = templater.templatepath()
1865 ui.status(_("Checking templates (%s)...\n") % ' '.join(p))
1869 ui.status(_("Checking templates (%s)...\n") % ' '.join(p))
1866 try:
1870 try:
1867 templater.templater(templater.templatepath("map-cmdline.default"))
1871 templater.templater(templater.templatepath("map-cmdline.default"))
1868 except Exception, inst:
1872 except Exception, inst:
1869 ui.write(" %s\n" % inst)
1873 ui.write(" %s\n" % inst)
1870 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1874 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1871 problems += 1
1875 problems += 1
1872
1876
1873 # editor
1877 # editor
1874 ui.status(_("Checking commit editor...\n"))
1878 ui.status(_("Checking commit editor...\n"))
1875 editor = ui.geteditor()
1879 editor = ui.geteditor()
1876 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
1880 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
1877 if not cmdpath:
1881 if not cmdpath:
1878 if editor == 'vi':
1882 if editor == 'vi':
1879 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1883 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1880 ui.write(_(" (specify a commit editor in your configuration"
1884 ui.write(_(" (specify a commit editor in your configuration"
1881 " file)\n"))
1885 " file)\n"))
1882 else:
1886 else:
1883 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1887 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1884 ui.write(_(" (specify a commit editor in your configuration"
1888 ui.write(_(" (specify a commit editor in your configuration"
1885 " file)\n"))
1889 " file)\n"))
1886 problems += 1
1890 problems += 1
1887
1891
1888 # check username
1892 # check username
1889 ui.status(_("Checking username...\n"))
1893 ui.status(_("Checking username...\n"))
1890 try:
1894 try:
1891 ui.username()
1895 ui.username()
1892 except util.Abort, e:
1896 except util.Abort, e:
1893 ui.write(" %s\n" % e)
1897 ui.write(" %s\n" % e)
1894 ui.write(_(" (specify a username in your configuration file)\n"))
1898 ui.write(_(" (specify a username in your configuration file)\n"))
1895 problems += 1
1899 problems += 1
1896
1900
1897 if not problems:
1901 if not problems:
1898 ui.status(_("No problems detected\n"))
1902 ui.status(_("No problems detected\n"))
1899 else:
1903 else:
1900 ui.write(_("%s problems detected,"
1904 ui.write(_("%s problems detected,"
1901 " please check your install!\n") % problems)
1905 " please check your install!\n") % problems)
1902
1906
1903 return problems
1907 return problems
1904
1908
1905 @command('debugknown', [], _('REPO ID...'))
1909 @command('debugknown', [], _('REPO ID...'))
1906 def debugknown(ui, repopath, *ids, **opts):
1910 def debugknown(ui, repopath, *ids, **opts):
1907 """test whether node ids are known to a repo
1911 """test whether node ids are known to a repo
1908
1912
1909 Every ID must be a full-length hex node id string. Returns a list of 0s and 1s
1913 Every ID must be a full-length hex node id string. Returns a list of 0s and 1s
1910 indicating unknown/known.
1914 indicating unknown/known.
1911 """
1915 """
1912 repo = hg.peer(ui, opts, repopath)
1916 repo = hg.peer(ui, opts, repopath)
1913 if not repo.capable('known'):
1917 if not repo.capable('known'):
1914 raise util.Abort("known() not supported by target repository")
1918 raise util.Abort("known() not supported by target repository")
1915 flags = repo.known([bin(s) for s in ids])
1919 flags = repo.known([bin(s) for s in ids])
1916 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1920 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1917
1921
1918 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
1922 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
1919 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
1923 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
1920 '''access the pushkey key/value protocol
1924 '''access the pushkey key/value protocol
1921
1925
1922 With two args, list the keys in the given namespace.
1926 With two args, list the keys in the given namespace.
1923
1927
1924 With five args, set a key to new if it currently is set to old.
1928 With five args, set a key to new if it currently is set to old.
1925 Reports success or failure.
1929 Reports success or failure.
1926 '''
1930 '''
1927
1931
1928 target = hg.peer(ui, {}, repopath)
1932 target = hg.peer(ui, {}, repopath)
1929 if keyinfo:
1933 if keyinfo:
1930 key, old, new = keyinfo
1934 key, old, new = keyinfo
1931 r = target.pushkey(namespace, key, old, new)
1935 r = target.pushkey(namespace, key, old, new)
1932 ui.status(str(r) + '\n')
1936 ui.status(str(r) + '\n')
1933 return not r
1937 return not r
1934 else:
1938 else:
1935 for k, v in target.listkeys(namespace).iteritems():
1939 for k, v in target.listkeys(namespace).iteritems():
1936 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1940 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1937 v.encode('string-escape')))
1941 v.encode('string-escape')))
1938
1942
1939 @command('debugrebuildstate',
1943 @command('debugrebuildstate',
1940 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
1944 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
1941 _('[-r REV] [REV]'))
1945 _('[-r REV] [REV]'))
1942 def debugrebuildstate(ui, repo, rev="tip"):
1946 def debugrebuildstate(ui, repo, rev="tip"):
1943 """rebuild the dirstate as it would look like for the given revision"""
1947 """rebuild the dirstate as it would look like for the given revision"""
1944 ctx = scmutil.revsingle(repo, rev)
1948 ctx = scmutil.revsingle(repo, rev)
1945 wlock = repo.wlock()
1949 wlock = repo.wlock()
1946 try:
1950 try:
1947 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1951 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1948 finally:
1952 finally:
1949 wlock.release()
1953 wlock.release()
1950
1954
1951 @command('debugrename',
1955 @command('debugrename',
1952 [('r', 'rev', '', _('revision to debug'), _('REV'))],
1956 [('r', 'rev', '', _('revision to debug'), _('REV'))],
1953 _('[-r REV] FILE'))
1957 _('[-r REV] FILE'))
1954 def debugrename(ui, repo, file1, *pats, **opts):
1958 def debugrename(ui, repo, file1, *pats, **opts):
1955 """dump rename information"""
1959 """dump rename information"""
1956
1960
1957 ctx = scmutil.revsingle(repo, opts.get('rev'))
1961 ctx = scmutil.revsingle(repo, opts.get('rev'))
1958 m = scmutil.match(ctx, (file1,) + pats, opts)
1962 m = scmutil.match(ctx, (file1,) + pats, opts)
1959 for abs in ctx.walk(m):
1963 for abs in ctx.walk(m):
1960 fctx = ctx[abs]
1964 fctx = ctx[abs]
1961 o = fctx.filelog().renamed(fctx.filenode())
1965 o = fctx.filelog().renamed(fctx.filenode())
1962 rel = m.rel(abs)
1966 rel = m.rel(abs)
1963 if o:
1967 if o:
1964 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1968 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1965 else:
1969 else:
1966 ui.write(_("%s not renamed\n") % rel)
1970 ui.write(_("%s not renamed\n") % rel)
1967
1971
1968 @command('debugrevlog',
1972 @command('debugrevlog',
1969 [('c', 'changelog', False, _('open changelog')),
1973 [('c', 'changelog', False, _('open changelog')),
1970 ('m', 'manifest', False, _('open manifest')),
1974 ('m', 'manifest', False, _('open manifest')),
1971 ('d', 'dump', False, _('dump index data'))],
1975 ('d', 'dump', False, _('dump index data'))],
1972 _('-c|-m|FILE'))
1976 _('-c|-m|FILE'))
1973 def debugrevlog(ui, repo, file_ = None, **opts):
1977 def debugrevlog(ui, repo, file_ = None, **opts):
1974 """show data and statistics about a revlog"""
1978 """show data and statistics about a revlog"""
1975 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
1979 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
1976
1980
1977 if opts.get("dump"):
1981 if opts.get("dump"):
1978 numrevs = len(r)
1982 numrevs = len(r)
1979 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
1983 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
1980 " rawsize totalsize compression heads\n")
1984 " rawsize totalsize compression heads\n")
1981 ts = 0
1985 ts = 0
1982 heads = set()
1986 heads = set()
1983 for rev in xrange(numrevs):
1987 for rev in xrange(numrevs):
1984 dbase = r.deltaparent(rev)
1988 dbase = r.deltaparent(rev)
1985 if dbase == -1:
1989 if dbase == -1:
1986 dbase = rev
1990 dbase = rev
1987 cbase = r.chainbase(rev)
1991 cbase = r.chainbase(rev)
1988 p1, p2 = r.parentrevs(rev)
1992 p1, p2 = r.parentrevs(rev)
1989 rs = r.rawsize(rev)
1993 rs = r.rawsize(rev)
1990 ts = ts + rs
1994 ts = ts + rs
1991 heads -= set(r.parentrevs(rev))
1995 heads -= set(r.parentrevs(rev))
1992 heads.add(rev)
1996 heads.add(rev)
1993 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
1997 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
1994 (rev, p1, p2, r.start(rev), r.end(rev),
1998 (rev, p1, p2, r.start(rev), r.end(rev),
1995 r.start(dbase), r.start(cbase),
1999 r.start(dbase), r.start(cbase),
1996 r.start(p1), r.start(p2),
2000 r.start(p1), r.start(p2),
1997 rs, ts, ts / r.end(rev), len(heads)))
2001 rs, ts, ts / r.end(rev), len(heads)))
1998 return 0
2002 return 0
1999
2003
2000 v = r.version
2004 v = r.version
2001 format = v & 0xFFFF
2005 format = v & 0xFFFF
2002 flags = []
2006 flags = []
2003 gdelta = False
2007 gdelta = False
2004 if v & revlog.REVLOGNGINLINEDATA:
2008 if v & revlog.REVLOGNGINLINEDATA:
2005 flags.append('inline')
2009 flags.append('inline')
2006 if v & revlog.REVLOGGENERALDELTA:
2010 if v & revlog.REVLOGGENERALDELTA:
2007 gdelta = True
2011 gdelta = True
2008 flags.append('generaldelta')
2012 flags.append('generaldelta')
2009 if not flags:
2013 if not flags:
2010 flags = ['(none)']
2014 flags = ['(none)']
2011
2015
2012 nummerges = 0
2016 nummerges = 0
2013 numfull = 0
2017 numfull = 0
2014 numprev = 0
2018 numprev = 0
2015 nump1 = 0
2019 nump1 = 0
2016 nump2 = 0
2020 nump2 = 0
2017 numother = 0
2021 numother = 0
2018 nump1prev = 0
2022 nump1prev = 0
2019 nump2prev = 0
2023 nump2prev = 0
2020 chainlengths = []
2024 chainlengths = []
2021
2025
2022 datasize = [None, 0, 0L]
2026 datasize = [None, 0, 0L]
2023 fullsize = [None, 0, 0L]
2027 fullsize = [None, 0, 0L]
2024 deltasize = [None, 0, 0L]
2028 deltasize = [None, 0, 0L]
2025
2029
2026 def addsize(size, l):
2030 def addsize(size, l):
2027 if l[0] is None or size < l[0]:
2031 if l[0] is None or size < l[0]:
2028 l[0] = size
2032 l[0] = size
2029 if size > l[1]:
2033 if size > l[1]:
2030 l[1] = size
2034 l[1] = size
2031 l[2] += size
2035 l[2] += size
2032
2036
2033 numrevs = len(r)
2037 numrevs = len(r)
2034 for rev in xrange(numrevs):
2038 for rev in xrange(numrevs):
2035 p1, p2 = r.parentrevs(rev)
2039 p1, p2 = r.parentrevs(rev)
2036 delta = r.deltaparent(rev)
2040 delta = r.deltaparent(rev)
2037 if format > 0:
2041 if format > 0:
2038 addsize(r.rawsize(rev), datasize)
2042 addsize(r.rawsize(rev), datasize)
2039 if p2 != nullrev:
2043 if p2 != nullrev:
2040 nummerges += 1
2044 nummerges += 1
2041 size = r.length(rev)
2045 size = r.length(rev)
2042 if delta == nullrev:
2046 if delta == nullrev:
2043 chainlengths.append(0)
2047 chainlengths.append(0)
2044 numfull += 1
2048 numfull += 1
2045 addsize(size, fullsize)
2049 addsize(size, fullsize)
2046 else:
2050 else:
2047 chainlengths.append(chainlengths[delta] + 1)
2051 chainlengths.append(chainlengths[delta] + 1)
2048 addsize(size, deltasize)
2052 addsize(size, deltasize)
2049 if delta == rev - 1:
2053 if delta == rev - 1:
2050 numprev += 1
2054 numprev += 1
2051 if delta == p1:
2055 if delta == p1:
2052 nump1prev += 1
2056 nump1prev += 1
2053 elif delta == p2:
2057 elif delta == p2:
2054 nump2prev += 1
2058 nump2prev += 1
2055 elif delta == p1:
2059 elif delta == p1:
2056 nump1 += 1
2060 nump1 += 1
2057 elif delta == p2:
2061 elif delta == p2:
2058 nump2 += 1
2062 nump2 += 1
2059 elif delta != nullrev:
2063 elif delta != nullrev:
2060 numother += 1
2064 numother += 1
2061
2065
2062 numdeltas = numrevs - numfull
2066 numdeltas = numrevs - numfull
2063 numoprev = numprev - nump1prev - nump2prev
2067 numoprev = numprev - nump1prev - nump2prev
2064 totalrawsize = datasize[2]
2068 totalrawsize = datasize[2]
2065 datasize[2] /= numrevs
2069 datasize[2] /= numrevs
2066 fulltotal = fullsize[2]
2070 fulltotal = fullsize[2]
2067 fullsize[2] /= numfull
2071 fullsize[2] /= numfull
2068 deltatotal = deltasize[2]
2072 deltatotal = deltasize[2]
2069 deltasize[2] /= numrevs - numfull
2073 deltasize[2] /= numrevs - numfull
2070 totalsize = fulltotal + deltatotal
2074 totalsize = fulltotal + deltatotal
2071 avgchainlen = sum(chainlengths) / numrevs
2075 avgchainlen = sum(chainlengths) / numrevs
2072 compratio = totalrawsize / totalsize
2076 compratio = totalrawsize / totalsize
2073
2077
2074 basedfmtstr = '%%%dd\n'
2078 basedfmtstr = '%%%dd\n'
2075 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2079 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2076
2080
2077 def dfmtstr(max):
2081 def dfmtstr(max):
2078 return basedfmtstr % len(str(max))
2082 return basedfmtstr % len(str(max))
2079 def pcfmtstr(max, padding=0):
2083 def pcfmtstr(max, padding=0):
2080 return basepcfmtstr % (len(str(max)), ' ' * padding)
2084 return basepcfmtstr % (len(str(max)), ' ' * padding)
2081
2085
2082 def pcfmt(value, total):
2086 def pcfmt(value, total):
2083 return (value, 100 * float(value) / total)
2087 return (value, 100 * float(value) / total)
2084
2088
2085 ui.write('format : %d\n' % format)
2089 ui.write('format : %d\n' % format)
2086 ui.write('flags : %s\n' % ', '.join(flags))
2090 ui.write('flags : %s\n' % ', '.join(flags))
2087
2091
2088 ui.write('\n')
2092 ui.write('\n')
2089 fmt = pcfmtstr(totalsize)
2093 fmt = pcfmtstr(totalsize)
2090 fmt2 = dfmtstr(totalsize)
2094 fmt2 = dfmtstr(totalsize)
2091 ui.write('revisions : ' + fmt2 % numrevs)
2095 ui.write('revisions : ' + fmt2 % numrevs)
2092 ui.write(' merges : ' + fmt % pcfmt(nummerges, numrevs))
2096 ui.write(' merges : ' + fmt % pcfmt(nummerges, numrevs))
2093 ui.write(' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs))
2097 ui.write(' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs))
2094 ui.write('revisions : ' + fmt2 % numrevs)
2098 ui.write('revisions : ' + fmt2 % numrevs)
2095 ui.write(' full : ' + fmt % pcfmt(numfull, numrevs))
2099 ui.write(' full : ' + fmt % pcfmt(numfull, numrevs))
2096 ui.write(' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
2100 ui.write(' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
2097 ui.write('revision size : ' + fmt2 % totalsize)
2101 ui.write('revision size : ' + fmt2 % totalsize)
2098 ui.write(' full : ' + fmt % pcfmt(fulltotal, totalsize))
2102 ui.write(' full : ' + fmt % pcfmt(fulltotal, totalsize))
2099 ui.write(' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
2103 ui.write(' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
2100
2104
2101 ui.write('\n')
2105 ui.write('\n')
2102 fmt = dfmtstr(max(avgchainlen, compratio))
2106 fmt = dfmtstr(max(avgchainlen, compratio))
2103 ui.write('avg chain length : ' + fmt % avgchainlen)
2107 ui.write('avg chain length : ' + fmt % avgchainlen)
2104 ui.write('compression ratio : ' + fmt % compratio)
2108 ui.write('compression ratio : ' + fmt % compratio)
2105
2109
2106 if format > 0:
2110 if format > 0:
2107 ui.write('\n')
2111 ui.write('\n')
2108 ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
2112 ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
2109 % tuple(datasize))
2113 % tuple(datasize))
2110 ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
2114 ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
2111 % tuple(fullsize))
2115 % tuple(fullsize))
2112 ui.write('delta size (min/max/avg) : %d / %d / %d\n'
2116 ui.write('delta size (min/max/avg) : %d / %d / %d\n'
2113 % tuple(deltasize))
2117 % tuple(deltasize))
2114
2118
2115 if numdeltas > 0:
2119 if numdeltas > 0:
2116 ui.write('\n')
2120 ui.write('\n')
2117 fmt = pcfmtstr(numdeltas)
2121 fmt = pcfmtstr(numdeltas)
2118 fmt2 = pcfmtstr(numdeltas, 4)
2122 fmt2 = pcfmtstr(numdeltas, 4)
2119 ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
2123 ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
2120 if numprev > 0:
2124 if numprev > 0:
2121 ui.write(' where prev = p1 : ' + fmt2 % pcfmt(nump1prev, numprev))
2125 ui.write(' where prev = p1 : ' + fmt2 % pcfmt(nump1prev, numprev))
2122 ui.write(' where prev = p2 : ' + fmt2 % pcfmt(nump2prev, numprev))
2126 ui.write(' where prev = p2 : ' + fmt2 % pcfmt(nump2prev, numprev))
2123 ui.write(' other : ' + fmt2 % pcfmt(numoprev, numprev))
2127 ui.write(' other : ' + fmt2 % pcfmt(numoprev, numprev))
2124 if gdelta:
2128 if gdelta:
2125 ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
2129 ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
2126 ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
2130 ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
2127 ui.write('deltas against other : ' + fmt % pcfmt(numother, numdeltas))
2131 ui.write('deltas against other : ' + fmt % pcfmt(numother, numdeltas))
2128
2132
2129 @command('debugrevspec', [], ('REVSPEC'))
2133 @command('debugrevspec', [], ('REVSPEC'))
2130 def debugrevspec(ui, repo, expr):
2134 def debugrevspec(ui, repo, expr):
2131 '''parse and apply a revision specification'''
2135 '''parse and apply a revision specification'''
2132 if ui.verbose:
2136 if ui.verbose:
2133 tree = revset.parse(expr)[0]
2137 tree = revset.parse(expr)[0]
2134 ui.note(tree, "\n")
2138 ui.note(tree, "\n")
2135 newtree = revset.findaliases(ui, tree)
2139 newtree = revset.findaliases(ui, tree)
2136 if newtree != tree:
2140 if newtree != tree:
2137 ui.note(newtree, "\n")
2141 ui.note(newtree, "\n")
2138 func = revset.match(ui, expr)
2142 func = revset.match(ui, expr)
2139 for c in func(repo, range(len(repo))):
2143 for c in func(repo, range(len(repo))):
2140 ui.write("%s\n" % c)
2144 ui.write("%s\n" % c)
2141
2145
2142 @command('debugsetparents', [], _('REV1 [REV2]'))
2146 @command('debugsetparents', [], _('REV1 [REV2]'))
2143 def debugsetparents(ui, repo, rev1, rev2=None):
2147 def debugsetparents(ui, repo, rev1, rev2=None):
2144 """manually set the parents of the current working directory
2148 """manually set the parents of the current working directory
2145
2149
2146 This is useful for writing repository conversion tools, but should
2150 This is useful for writing repository conversion tools, but should
2147 be used with care.
2151 be used with care.
2148
2152
2149 Returns 0 on success.
2153 Returns 0 on success.
2150 """
2154 """
2151
2155
2152 r1 = scmutil.revsingle(repo, rev1).node()
2156 r1 = scmutil.revsingle(repo, rev1).node()
2153 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2157 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2154
2158
2155 wlock = repo.wlock()
2159 wlock = repo.wlock()
2156 try:
2160 try:
2157 repo.dirstate.setparents(r1, r2)
2161 repo.dirstate.setparents(r1, r2)
2158 finally:
2162 finally:
2159 wlock.release()
2163 wlock.release()
2160
2164
2161 @command('debugstate',
2165 @command('debugstate',
2162 [('', 'nodates', None, _('do not display the saved mtime')),
2166 [('', 'nodates', None, _('do not display the saved mtime')),
2163 ('', 'datesort', None, _('sort by saved mtime'))],
2167 ('', 'datesort', None, _('sort by saved mtime'))],
2164 _('[OPTION]...'))
2168 _('[OPTION]...'))
2165 def debugstate(ui, repo, nodates=None, datesort=None):
2169 def debugstate(ui, repo, nodates=None, datesort=None):
2166 """show the contents of the current dirstate"""
2170 """show the contents of the current dirstate"""
2167 timestr = ""
2171 timestr = ""
2168 showdate = not nodates
2172 showdate = not nodates
2169 if datesort:
2173 if datesort:
2170 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2174 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2171 else:
2175 else:
2172 keyfunc = None # sort by filename
2176 keyfunc = None # sort by filename
2173 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2177 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2174 if showdate:
2178 if showdate:
2175 if ent[3] == -1:
2179 if ent[3] == -1:
2176 # Pad or slice to locale representation
2180 # Pad or slice to locale representation
2177 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2181 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2178 time.localtime(0)))
2182 time.localtime(0)))
2179 timestr = 'unset'
2183 timestr = 'unset'
2180 timestr = (timestr[:locale_len] +
2184 timestr = (timestr[:locale_len] +
2181 ' ' * (locale_len - len(timestr)))
2185 ' ' * (locale_len - len(timestr)))
2182 else:
2186 else:
2183 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2187 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2184 time.localtime(ent[3]))
2188 time.localtime(ent[3]))
2185 if ent[1] & 020000:
2189 if ent[1] & 020000:
2186 mode = 'lnk'
2190 mode = 'lnk'
2187 else:
2191 else:
2188 mode = '%3o' % (ent[1] & 0777)
2192 mode = '%3o' % (ent[1] & 0777)
2189 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2193 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2190 for f in repo.dirstate.copies():
2194 for f in repo.dirstate.copies():
2191 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2195 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2192
2196
2193 @command('debugsub',
2197 @command('debugsub',
2194 [('r', 'rev', '',
2198 [('r', 'rev', '',
2195 _('revision to check'), _('REV'))],
2199 _('revision to check'), _('REV'))],
2196 _('[-r REV] [REV]'))
2200 _('[-r REV] [REV]'))
2197 def debugsub(ui, repo, rev=None):
2201 def debugsub(ui, repo, rev=None):
2198 ctx = scmutil.revsingle(repo, rev, None)
2202 ctx = scmutil.revsingle(repo, rev, None)
2199 for k, v in sorted(ctx.substate.items()):
2203 for k, v in sorted(ctx.substate.items()):
2200 ui.write('path %s\n' % k)
2204 ui.write('path %s\n' % k)
2201 ui.write(' source %s\n' % v[0])
2205 ui.write(' source %s\n' % v[0])
2202 ui.write(' revision %s\n' % v[1])
2206 ui.write(' revision %s\n' % v[1])
2203
2207
2204 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2208 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2205 def debugwalk(ui, repo, *pats, **opts):
2209 def debugwalk(ui, repo, *pats, **opts):
2206 """show how files match on given patterns"""
2210 """show how files match on given patterns"""
2207 m = scmutil.match(repo[None], pats, opts)
2211 m = scmutil.match(repo[None], pats, opts)
2208 items = list(repo.walk(m))
2212 items = list(repo.walk(m))
2209 if not items:
2213 if not items:
2210 return
2214 return
2211 fmt = 'f %%-%ds %%-%ds %%s' % (
2215 fmt = 'f %%-%ds %%-%ds %%s' % (
2212 max([len(abs) for abs in items]),
2216 max([len(abs) for abs in items]),
2213 max([len(m.rel(abs)) for abs in items]))
2217 max([len(m.rel(abs)) for abs in items]))
2214 for abs in items:
2218 for abs in items:
2215 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
2219 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
2216 ui.write("%s\n" % line.rstrip())
2220 ui.write("%s\n" % line.rstrip())
2217
2221
2218 @command('debugwireargs',
2222 @command('debugwireargs',
2219 [('', 'three', '', 'three'),
2223 [('', 'three', '', 'three'),
2220 ('', 'four', '', 'four'),
2224 ('', 'four', '', 'four'),
2221 ('', 'five', '', 'five'),
2225 ('', 'five', '', 'five'),
2222 ] + remoteopts,
2226 ] + remoteopts,
2223 _('REPO [OPTIONS]... [ONE [TWO]]'))
2227 _('REPO [OPTIONS]... [ONE [TWO]]'))
2224 def debugwireargs(ui, repopath, *vals, **opts):
2228 def debugwireargs(ui, repopath, *vals, **opts):
2225 repo = hg.peer(ui, opts, repopath)
2229 repo = hg.peer(ui, opts, repopath)
2226 for opt in remoteopts:
2230 for opt in remoteopts:
2227 del opts[opt[1]]
2231 del opts[opt[1]]
2228 args = {}
2232 args = {}
2229 for k, v in opts.iteritems():
2233 for k, v in opts.iteritems():
2230 if v:
2234 if v:
2231 args[k] = v
2235 args[k] = v
2232 # run twice to check that we don't mess up the stream for the next command
2236 # run twice to check that we don't mess up the stream for the next command
2233 res1 = repo.debugwireargs(*vals, **args)
2237 res1 = repo.debugwireargs(*vals, **args)
2234 res2 = repo.debugwireargs(*vals, **args)
2238 res2 = repo.debugwireargs(*vals, **args)
2235 ui.write("%s\n" % res1)
2239 ui.write("%s\n" % res1)
2236 if res1 != res2:
2240 if res1 != res2:
2237 ui.warn("%s\n" % res2)
2241 ui.warn("%s\n" % res2)
2238
2242
2239 @command('^diff',
2243 @command('^diff',
2240 [('r', 'rev', [], _('revision'), _('REV')),
2244 [('r', 'rev', [], _('revision'), _('REV')),
2241 ('c', 'change', '', _('change made by revision'), _('REV'))
2245 ('c', 'change', '', _('change made by revision'), _('REV'))
2242 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2246 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2243 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2247 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2244 def diff(ui, repo, *pats, **opts):
2248 def diff(ui, repo, *pats, **opts):
2245 """diff repository (or selected files)
2249 """diff repository (or selected files)
2246
2250
2247 Show differences between revisions for the specified files.
2251 Show differences between revisions for the specified files.
2248
2252
2249 Differences between files are shown using the unified diff format.
2253 Differences between files are shown using the unified diff format.
2250
2254
2251 .. note::
2255 .. note::
2252 diff may generate unexpected results for merges, as it will
2256 diff may generate unexpected results for merges, as it will
2253 default to comparing against the working directory's first
2257 default to comparing against the working directory's first
2254 parent changeset if no revisions are specified.
2258 parent changeset if no revisions are specified.
2255
2259
2256 When two revision arguments are given, then changes are shown
2260 When two revision arguments are given, then changes are shown
2257 between those revisions. If only one revision is specified then
2261 between those revisions. If only one revision is specified then
2258 that revision is compared to the working directory, and, when no
2262 that revision is compared to the working directory, and, when no
2259 revisions are specified, the working directory files are compared
2263 revisions are specified, the working directory files are compared
2260 to its parent.
2264 to its parent.
2261
2265
2262 Alternatively you can specify -c/--change with a revision to see
2266 Alternatively you can specify -c/--change with a revision to see
2263 the changes in that changeset relative to its first parent.
2267 the changes in that changeset relative to its first parent.
2264
2268
2265 Without the -a/--text option, diff will avoid generating diffs of
2269 Without the -a/--text option, diff will avoid generating diffs of
2266 files it detects as binary. With -a, diff will generate a diff
2270 files it detects as binary. With -a, diff will generate a diff
2267 anyway, probably with undesirable results.
2271 anyway, probably with undesirable results.
2268
2272
2269 Use the -g/--git option to generate diffs in the git extended diff
2273 Use the -g/--git option to generate diffs in the git extended diff
2270 format. For more information, read :hg:`help diffs`.
2274 format. For more information, read :hg:`help diffs`.
2271
2275
2272 .. container:: verbose
2276 .. container:: verbose
2273
2277
2274 Examples:
2278 Examples:
2275
2279
2276 - compare a file in the current working directory to its parent::
2280 - compare a file in the current working directory to its parent::
2277
2281
2278 hg diff foo.c
2282 hg diff foo.c
2279
2283
2280 - compare two historical versions of a directory, with rename info::
2284 - compare two historical versions of a directory, with rename info::
2281
2285
2282 hg diff --git -r 1.0:1.2 lib/
2286 hg diff --git -r 1.0:1.2 lib/
2283
2287
2284 - get change stats relative to the last change on some date::
2288 - get change stats relative to the last change on some date::
2285
2289
2286 hg diff --stat -r "date('may 2')"
2290 hg diff --stat -r "date('may 2')"
2287
2291
2288 - diff all newly-added files that contain a keyword::
2292 - diff all newly-added files that contain a keyword::
2289
2293
2290 hg diff "set:added() and grep(GNU)"
2294 hg diff "set:added() and grep(GNU)"
2291
2295
2292 - compare a revision and its parents::
2296 - compare a revision and its parents::
2293
2297
2294 hg diff -c 9353 # compare against first parent
2298 hg diff -c 9353 # compare against first parent
2295 hg diff -r 9353^:9353 # same using revset syntax
2299 hg diff -r 9353^:9353 # same using revset syntax
2296 hg diff -r 9353^2:9353 # compare against the second parent
2300 hg diff -r 9353^2:9353 # compare against the second parent
2297
2301
2298 Returns 0 on success.
2302 Returns 0 on success.
2299 """
2303 """
2300
2304
2301 revs = opts.get('rev')
2305 revs = opts.get('rev')
2302 change = opts.get('change')
2306 change = opts.get('change')
2303 stat = opts.get('stat')
2307 stat = opts.get('stat')
2304 reverse = opts.get('reverse')
2308 reverse = opts.get('reverse')
2305
2309
2306 if revs and change:
2310 if revs and change:
2307 msg = _('cannot specify --rev and --change at the same time')
2311 msg = _('cannot specify --rev and --change at the same time')
2308 raise util.Abort(msg)
2312 raise util.Abort(msg)
2309 elif change:
2313 elif change:
2310 node2 = scmutil.revsingle(repo, change, None).node()
2314 node2 = scmutil.revsingle(repo, change, None).node()
2311 node1 = repo[node2].p1().node()
2315 node1 = repo[node2].p1().node()
2312 else:
2316 else:
2313 node1, node2 = scmutil.revpair(repo, revs)
2317 node1, node2 = scmutil.revpair(repo, revs)
2314
2318
2315 if reverse:
2319 if reverse:
2316 node1, node2 = node2, node1
2320 node1, node2 = node2, node1
2317
2321
2318 diffopts = patch.diffopts(ui, opts)
2322 diffopts = patch.diffopts(ui, opts)
2319 m = scmutil.match(repo[node2], pats, opts)
2323 m = scmutil.match(repo[node2], pats, opts)
2320 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2324 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2321 listsubrepos=opts.get('subrepos'))
2325 listsubrepos=opts.get('subrepos'))
2322
2326
2323 @command('^export',
2327 @command('^export',
2324 [('o', 'output', '',
2328 [('o', 'output', '',
2325 _('print output to file with formatted name'), _('FORMAT')),
2329 _('print output to file with formatted name'), _('FORMAT')),
2326 ('', 'switch-parent', None, _('diff against the second parent')),
2330 ('', 'switch-parent', None, _('diff against the second parent')),
2327 ('r', 'rev', [], _('revisions to export'), _('REV')),
2331 ('r', 'rev', [], _('revisions to export'), _('REV')),
2328 ] + diffopts,
2332 ] + diffopts,
2329 _('[OPTION]... [-o OUTFILESPEC] REV...'))
2333 _('[OPTION]... [-o OUTFILESPEC] REV...'))
2330 def export(ui, repo, *changesets, **opts):
2334 def export(ui, repo, *changesets, **opts):
2331 """dump the header and diffs for one or more changesets
2335 """dump the header and diffs for one or more changesets
2332
2336
2333 Print the changeset header and diffs for one or more revisions.
2337 Print the changeset header and diffs for one or more revisions.
2334
2338
2335 The information shown in the changeset header is: author, date,
2339 The information shown in the changeset header is: author, date,
2336 branch name (if non-default), changeset hash, parent(s) and commit
2340 branch name (if non-default), changeset hash, parent(s) and commit
2337 comment.
2341 comment.
2338
2342
2339 .. note::
2343 .. note::
2340 export may generate unexpected diff output for merge
2344 export may generate unexpected diff output for merge
2341 changesets, as it will compare the merge changeset against its
2345 changesets, as it will compare the merge changeset against its
2342 first parent only.
2346 first parent only.
2343
2347
2344 Output may be to a file, in which case the name of the file is
2348 Output may be to a file, in which case the name of the file is
2345 given using a format string. The formatting rules are as follows:
2349 given using a format string. The formatting rules are as follows:
2346
2350
2347 :``%%``: literal "%" character
2351 :``%%``: literal "%" character
2348 :``%H``: changeset hash (40 hexadecimal digits)
2352 :``%H``: changeset hash (40 hexadecimal digits)
2349 :``%N``: number of patches being generated
2353 :``%N``: number of patches being generated
2350 :``%R``: changeset revision number
2354 :``%R``: changeset revision number
2351 :``%b``: basename of the exporting repository
2355 :``%b``: basename of the exporting repository
2352 :``%h``: short-form changeset hash (12 hexadecimal digits)
2356 :``%h``: short-form changeset hash (12 hexadecimal digits)
2353 :``%m``: first line of the commit message (only alphanumeric characters)
2357 :``%m``: first line of the commit message (only alphanumeric characters)
2354 :``%n``: zero-padded sequence number, starting at 1
2358 :``%n``: zero-padded sequence number, starting at 1
2355 :``%r``: zero-padded changeset revision number
2359 :``%r``: zero-padded changeset revision number
2356
2360
2357 Without the -a/--text option, export will avoid generating diffs
2361 Without the -a/--text option, export will avoid generating diffs
2358 of files it detects as binary. With -a, export will generate a
2362 of files it detects as binary. With -a, export will generate a
2359 diff anyway, probably with undesirable results.
2363 diff anyway, probably with undesirable results.
2360
2364
2361 Use the -g/--git option to generate diffs in the git extended diff
2365 Use the -g/--git option to generate diffs in the git extended diff
2362 format. See :hg:`help diffs` for more information.
2366 format. See :hg:`help diffs` for more information.
2363
2367
2364 With the --switch-parent option, the diff will be against the
2368 With the --switch-parent option, the diff will be against the
2365 second parent. It can be useful to review a merge.
2369 second parent. It can be useful to review a merge.
2366
2370
2367 .. container:: verbose
2371 .. container:: verbose
2368
2372
2369 Examples:
2373 Examples:
2370
2374
2371 - use export and import to transplant a bugfix to the current
2375 - use export and import to transplant a bugfix to the current
2372 branch::
2376 branch::
2373
2377
2374 hg export -r 9353 | hg import -
2378 hg export -r 9353 | hg import -
2375
2379
2376 - export all the changesets between two revisions to a file with
2380 - export all the changesets between two revisions to a file with
2377 rename information::
2381 rename information::
2378
2382
2379 hg export --git -r 123:150 > changes.txt
2383 hg export --git -r 123:150 > changes.txt
2380
2384
2381 - split outgoing changes into a series of patches with
2385 - split outgoing changes into a series of patches with
2382 descriptive names::
2386 descriptive names::
2383
2387
2384 hg export -r "outgoing()" -o "%n-%m.patch"
2388 hg export -r "outgoing()" -o "%n-%m.patch"
2385
2389
2386 Returns 0 on success.
2390 Returns 0 on success.
2387 """
2391 """
2388 changesets += tuple(opts.get('rev', []))
2392 changesets += tuple(opts.get('rev', []))
2389 if not changesets:
2393 if not changesets:
2390 raise util.Abort(_("export requires at least one changeset"))
2394 raise util.Abort(_("export requires at least one changeset"))
2391 revs = scmutil.revrange(repo, changesets)
2395 revs = scmutil.revrange(repo, changesets)
2392 if len(revs) > 1:
2396 if len(revs) > 1:
2393 ui.note(_('exporting patches:\n'))
2397 ui.note(_('exporting patches:\n'))
2394 else:
2398 else:
2395 ui.note(_('exporting patch:\n'))
2399 ui.note(_('exporting patch:\n'))
2396 cmdutil.export(repo, revs, template=opts.get('output'),
2400 cmdutil.export(repo, revs, template=opts.get('output'),
2397 switch_parent=opts.get('switch_parent'),
2401 switch_parent=opts.get('switch_parent'),
2398 opts=patch.diffopts(ui, opts))
2402 opts=patch.diffopts(ui, opts))
2399
2403
2400 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2404 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2401 def forget(ui, repo, *pats, **opts):
2405 def forget(ui, repo, *pats, **opts):
2402 """forget the specified files on the next commit
2406 """forget the specified files on the next commit
2403
2407
2404 Mark the specified files so they will no longer be tracked
2408 Mark the specified files so they will no longer be tracked
2405 after the next commit.
2409 after the next commit.
2406
2410
2407 This only removes files from the current branch, not from the
2411 This only removes files from the current branch, not from the
2408 entire project history, and it does not delete them from the
2412 entire project history, and it does not delete them from the
2409 working directory.
2413 working directory.
2410
2414
2411 To undo a forget before the next commit, see :hg:`add`.
2415 To undo a forget before the next commit, see :hg:`add`.
2412
2416
2413 .. container:: verbose
2417 .. container:: verbose
2414
2418
2415 Examples:
2419 Examples:
2416
2420
2417 - forget newly-added binary files::
2421 - forget newly-added binary files::
2418
2422
2419 hg forget "set:added() and binary()"
2423 hg forget "set:added() and binary()"
2420
2424
2421 - forget files that would be excluded by .hgignore::
2425 - forget files that would be excluded by .hgignore::
2422
2426
2423 hg forget "set:hgignore()"
2427 hg forget "set:hgignore()"
2424
2428
2425 Returns 0 on success.
2429 Returns 0 on success.
2426 """
2430 """
2427
2431
2428 if not pats:
2432 if not pats:
2429 raise util.Abort(_('no files specified'))
2433 raise util.Abort(_('no files specified'))
2430
2434
2431 m = scmutil.match(repo[None], pats, opts)
2435 m = scmutil.match(repo[None], pats, opts)
2432 s = repo.status(match=m, clean=True)
2436 s = repo.status(match=m, clean=True)
2433 forget = sorted(s[0] + s[1] + s[3] + s[6])
2437 forget = sorted(s[0] + s[1] + s[3] + s[6])
2434 errs = 0
2438 errs = 0
2435
2439
2436 for f in m.files():
2440 for f in m.files():
2437 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
2441 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
2438 if os.path.exists(m.rel(f)):
2442 if os.path.exists(m.rel(f)):
2439 ui.warn(_('not removing %s: file is already untracked\n')
2443 ui.warn(_('not removing %s: file is already untracked\n')
2440 % m.rel(f))
2444 % m.rel(f))
2441 errs = 1
2445 errs = 1
2442
2446
2443 for f in forget:
2447 for f in forget:
2444 if ui.verbose or not m.exact(f):
2448 if ui.verbose or not m.exact(f):
2445 ui.status(_('removing %s\n') % m.rel(f))
2449 ui.status(_('removing %s\n') % m.rel(f))
2446
2450
2447 repo[None].forget(forget)
2451 repo[None].forget(forget)
2448 return errs
2452 return errs
2449
2453
2450 @command(
2454 @command(
2451 'graft',
2455 'graft',
2452 [('c', 'continue', False, _('resume interrupted graft')),
2456 [('c', 'continue', False, _('resume interrupted graft')),
2453 ('e', 'edit', False, _('invoke editor on commit messages')),
2457 ('e', 'edit', False, _('invoke editor on commit messages')),
2454 ('D', 'currentdate', False,
2458 ('D', 'currentdate', False,
2455 _('record the current date as commit date')),
2459 _('record the current date as commit date')),
2456 ('U', 'currentuser', False,
2460 ('U', 'currentuser', False,
2457 _('record the current user as committer'), _('DATE'))]
2461 _('record the current user as committer'), _('DATE'))]
2458 + commitopts2 + mergetoolopts,
2462 + commitopts2 + mergetoolopts,
2459 _('[OPTION]... REVISION...'))
2463 _('[OPTION]... REVISION...'))
2460 def graft(ui, repo, *revs, **opts):
2464 def graft(ui, repo, *revs, **opts):
2461 '''copy changes from other branches onto the current branch
2465 '''copy changes from other branches onto the current branch
2462
2466
2463 This command uses Mercurial's merge logic to copy individual
2467 This command uses Mercurial's merge logic to copy individual
2464 changes from other branches without merging branches in the
2468 changes from other branches without merging branches in the
2465 history graph. This is sometimes known as 'backporting' or
2469 history graph. This is sometimes known as 'backporting' or
2466 'cherry-picking'. By default, graft will copy user, date, and
2470 'cherry-picking'. By default, graft will copy user, date, and
2467 description from the source changesets.
2471 description from the source changesets.
2468
2472
2469 Changesets that are ancestors of the current revision, that have
2473 Changesets that are ancestors of the current revision, that have
2470 already been grafted, or that are merges will be skipped.
2474 already been grafted, or that are merges will be skipped.
2471
2475
2472 If a graft merge results in conflicts, the graft process is
2476 If a graft merge results in conflicts, the graft process is
2473 aborted so that the current merge can be manually resolved. Once
2477 aborted so that the current merge can be manually resolved. Once
2474 all conflicts are addressed, the graft process can be continued
2478 all conflicts are addressed, the graft process can be continued
2475 with the -c/--continue option.
2479 with the -c/--continue option.
2476
2480
2477 .. note::
2481 .. note::
2478 The -c/--continue option does not reapply earlier options.
2482 The -c/--continue option does not reapply earlier options.
2479
2483
2480 .. container:: verbose
2484 .. container:: verbose
2481
2485
2482 Examples:
2486 Examples:
2483
2487
2484 - copy a single change to the stable branch and edit its description::
2488 - copy a single change to the stable branch and edit its description::
2485
2489
2486 hg update stable
2490 hg update stable
2487 hg graft --edit 9393
2491 hg graft --edit 9393
2488
2492
2489 - graft a range of changesets with one exception, updating dates::
2493 - graft a range of changesets with one exception, updating dates::
2490
2494
2491 hg graft -D "2085::2093 and not 2091"
2495 hg graft -D "2085::2093 and not 2091"
2492
2496
2493 - continue a graft after resolving conflicts::
2497 - continue a graft after resolving conflicts::
2494
2498
2495 hg graft -c
2499 hg graft -c
2496
2500
2497 - show the source of a grafted changeset::
2501 - show the source of a grafted changeset::
2498
2502
2499 hg log --debug -r tip
2503 hg log --debug -r tip
2500
2504
2501 Returns 0 on successful completion.
2505 Returns 0 on successful completion.
2502 '''
2506 '''
2503
2507
2504 if not opts.get('user') and opts.get('currentuser'):
2508 if not opts.get('user') and opts.get('currentuser'):
2505 opts['user'] = ui.username()
2509 opts['user'] = ui.username()
2506 if not opts.get('date') and opts.get('currentdate'):
2510 if not opts.get('date') and opts.get('currentdate'):
2507 opts['date'] = "%d %d" % util.makedate()
2511 opts['date'] = "%d %d" % util.makedate()
2508
2512
2509 editor = None
2513 editor = None
2510 if opts.get('edit'):
2514 if opts.get('edit'):
2511 editor = cmdutil.commitforceeditor
2515 editor = cmdutil.commitforceeditor
2512
2516
2513 cont = False
2517 cont = False
2514 if opts['continue']:
2518 if opts['continue']:
2515 cont = True
2519 cont = True
2516 if revs:
2520 if revs:
2517 raise util.Abort(_("can't specify --continue and revisions"))
2521 raise util.Abort(_("can't specify --continue and revisions"))
2518 # read in unfinished revisions
2522 # read in unfinished revisions
2519 try:
2523 try:
2520 nodes = repo.opener.read('graftstate').splitlines()
2524 nodes = repo.opener.read('graftstate').splitlines()
2521 revs = [repo[node].rev() for node in nodes]
2525 revs = [repo[node].rev() for node in nodes]
2522 except IOError, inst:
2526 except IOError, inst:
2523 if inst.errno != errno.ENOENT:
2527 if inst.errno != errno.ENOENT:
2524 raise
2528 raise
2525 raise util.Abort(_("no graft state found, can't continue"))
2529 raise util.Abort(_("no graft state found, can't continue"))
2526 else:
2530 else:
2527 cmdutil.bailifchanged(repo)
2531 cmdutil.bailifchanged(repo)
2528 if not revs:
2532 if not revs:
2529 raise util.Abort(_('no revisions specified'))
2533 raise util.Abort(_('no revisions specified'))
2530 revs = scmutil.revrange(repo, revs)
2534 revs = scmutil.revrange(repo, revs)
2531
2535
2532 # check for merges
2536 # check for merges
2533 for ctx in repo.set('%ld and merge()', revs):
2537 for ctx in repo.set('%ld and merge()', revs):
2534 ui.warn(_('skipping ungraftable merge revision %s\n') % ctx.rev())
2538 ui.warn(_('skipping ungraftable merge revision %s\n') % ctx.rev())
2535 revs.remove(ctx.rev())
2539 revs.remove(ctx.rev())
2536 if not revs:
2540 if not revs:
2537 return -1
2541 return -1
2538
2542
2539 # check for ancestors of dest branch
2543 # check for ancestors of dest branch
2540 for ctx in repo.set('::. and %ld', revs):
2544 for ctx in repo.set('::. and %ld', revs):
2541 ui.warn(_('skipping ancestor revision %s\n') % ctx.rev())
2545 ui.warn(_('skipping ancestor revision %s\n') % ctx.rev())
2542 revs.remove(ctx.rev())
2546 revs.remove(ctx.rev())
2543 if not revs:
2547 if not revs:
2544 return -1
2548 return -1
2545
2549
2546 # check ancestors for earlier grafts
2550 # check ancestors for earlier grafts
2547 ui.debug('scanning for existing transplants')
2551 ui.debug('scanning for existing transplants')
2548 for ctx in repo.set("::. - ::%ld", revs):
2552 for ctx in repo.set("::. - ::%ld", revs):
2549 n = ctx.extra().get('source')
2553 n = ctx.extra().get('source')
2550 if n and n in repo:
2554 if n and n in repo:
2551 r = repo[n].rev()
2555 r = repo[n].rev()
2552 ui.warn(_('skipping already grafted revision %s\n') % r)
2556 ui.warn(_('skipping already grafted revision %s\n') % r)
2553 revs.remove(r)
2557 revs.remove(r)
2554 if not revs:
2558 if not revs:
2555 return -1
2559 return -1
2556
2560
2557 for pos, ctx in enumerate(repo.set("%ld", revs)):
2561 for pos, ctx in enumerate(repo.set("%ld", revs)):
2558 current = repo['.']
2562 current = repo['.']
2559 ui.status('grafting revision %s', ctx.rev())
2563 ui.status('grafting revision %s', ctx.rev())
2560
2564
2561 # we don't merge the first commit when continuing
2565 # we don't merge the first commit when continuing
2562 if not cont:
2566 if not cont:
2563 # perform the graft merge with p1(rev) as 'ancestor'
2567 # perform the graft merge with p1(rev) as 'ancestor'
2564 try:
2568 try:
2565 # ui.forcemerge is an internal variable, do not document
2569 # ui.forcemerge is an internal variable, do not document
2566 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2570 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2567 stats = mergemod.update(repo, ctx.node(), True, True, False,
2571 stats = mergemod.update(repo, ctx.node(), True, True, False,
2568 ctx.p1().node())
2572 ctx.p1().node())
2569 finally:
2573 finally:
2570 ui.setconfig('ui', 'forcemerge', '')
2574 ui.setconfig('ui', 'forcemerge', '')
2571 # drop the second merge parent
2575 # drop the second merge parent
2572 repo.dirstate.setparents(current.node(), nullid)
2576 repo.dirstate.setparents(current.node(), nullid)
2573 repo.dirstate.write()
2577 repo.dirstate.write()
2574 # fix up dirstate for copies and renames
2578 # fix up dirstate for copies and renames
2575 cmdutil.duplicatecopies(repo, ctx.rev(), current.node(), nullid)
2579 cmdutil.duplicatecopies(repo, ctx.rev(), current.node(), nullid)
2576 # report any conflicts
2580 # report any conflicts
2577 if stats and stats[3] > 0:
2581 if stats and stats[3] > 0:
2578 # write out state for --continue
2582 # write out state for --continue
2579 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2583 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2580 repo.opener.write('graftstate', ''.join(nodelines))
2584 repo.opener.write('graftstate', ''.join(nodelines))
2581 raise util.Abort(
2585 raise util.Abort(
2582 _("unresolved conflicts, can't continue"),
2586 _("unresolved conflicts, can't continue"),
2583 hint=_('use hg resolve and hg graft --continue'))
2587 hint=_('use hg resolve and hg graft --continue'))
2584 else:
2588 else:
2585 cont = False
2589 cont = False
2586
2590
2587 # commit
2591 # commit
2588 extra = {'source': ctx.hex()}
2592 extra = {'source': ctx.hex()}
2589 user = ctx.user()
2593 user = ctx.user()
2590 if opts.get('user'):
2594 if opts.get('user'):
2591 user = opts['user']
2595 user = opts['user']
2592 date = ctx.date()
2596 date = ctx.date()
2593 if opts.get('date'):
2597 if opts.get('date'):
2594 date = opts['date']
2598 date = opts['date']
2595 repo.commit(text=ctx.description(), user=user,
2599 repo.commit(text=ctx.description(), user=user,
2596 date=date, extra=extra, editor=editor)
2600 date=date, extra=extra, editor=editor)
2597
2601
2598 # remove state when we complete successfully
2602 # remove state when we complete successfully
2599 if os.path.exists(repo.join('graftstate')):
2603 if os.path.exists(repo.join('graftstate')):
2600 util.unlinkpath(repo.join('graftstate'))
2604 util.unlinkpath(repo.join('graftstate'))
2601
2605
2602 return 0
2606 return 0
2603
2607
2604 @command('grep',
2608 @command('grep',
2605 [('0', 'print0', None, _('end fields with NUL')),
2609 [('0', 'print0', None, _('end fields with NUL')),
2606 ('', 'all', None, _('print all revisions that match')),
2610 ('', 'all', None, _('print all revisions that match')),
2607 ('a', 'text', None, _('treat all files as text')),
2611 ('a', 'text', None, _('treat all files as text')),
2608 ('f', 'follow', None,
2612 ('f', 'follow', None,
2609 _('follow changeset history,'
2613 _('follow changeset history,'
2610 ' or file history across copies and renames')),
2614 ' or file history across copies and renames')),
2611 ('i', 'ignore-case', None, _('ignore case when matching')),
2615 ('i', 'ignore-case', None, _('ignore case when matching')),
2612 ('l', 'files-with-matches', None,
2616 ('l', 'files-with-matches', None,
2613 _('print only filenames and revisions that match')),
2617 _('print only filenames and revisions that match')),
2614 ('n', 'line-number', None, _('print matching line numbers')),
2618 ('n', 'line-number', None, _('print matching line numbers')),
2615 ('r', 'rev', [],
2619 ('r', 'rev', [],
2616 _('only search files changed within revision range'), _('REV')),
2620 _('only search files changed within revision range'), _('REV')),
2617 ('u', 'user', None, _('list the author (long with -v)')),
2621 ('u', 'user', None, _('list the author (long with -v)')),
2618 ('d', 'date', None, _('list the date (short with -q)')),
2622 ('d', 'date', None, _('list the date (short with -q)')),
2619 ] + walkopts,
2623 ] + walkopts,
2620 _('[OPTION]... PATTERN [FILE]...'))
2624 _('[OPTION]... PATTERN [FILE]...'))
2621 def grep(ui, repo, pattern, *pats, **opts):
2625 def grep(ui, repo, pattern, *pats, **opts):
2622 """search for a pattern in specified files and revisions
2626 """search for a pattern in specified files and revisions
2623
2627
2624 Search revisions of files for a regular expression.
2628 Search revisions of files for a regular expression.
2625
2629
2626 This command behaves differently than Unix grep. It only accepts
2630 This command behaves differently than Unix grep. It only accepts
2627 Python/Perl regexps. It searches repository history, not the
2631 Python/Perl regexps. It searches repository history, not the
2628 working directory. It always prints the revision number in which a
2632 working directory. It always prints the revision number in which a
2629 match appears.
2633 match appears.
2630
2634
2631 By default, grep only prints output for the first revision of a
2635 By default, grep only prints output for the first revision of a
2632 file in which it finds a match. To get it to print every revision
2636 file in which it finds a match. To get it to print every revision
2633 that contains a change in match status ("-" for a match that
2637 that contains a change in match status ("-" for a match that
2634 becomes a non-match, or "+" for a non-match that becomes a match),
2638 becomes a non-match, or "+" for a non-match that becomes a match),
2635 use the --all flag.
2639 use the --all flag.
2636
2640
2637 Returns 0 if a match is found, 1 otherwise.
2641 Returns 0 if a match is found, 1 otherwise.
2638 """
2642 """
2639 reflags = 0
2643 reflags = 0
2640 if opts.get('ignore_case'):
2644 if opts.get('ignore_case'):
2641 reflags |= re.I
2645 reflags |= re.I
2642 try:
2646 try:
2643 regexp = re.compile(pattern, reflags)
2647 regexp = re.compile(pattern, reflags)
2644 except re.error, inst:
2648 except re.error, inst:
2645 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2649 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2646 return 1
2650 return 1
2647 sep, eol = ':', '\n'
2651 sep, eol = ':', '\n'
2648 if opts.get('print0'):
2652 if opts.get('print0'):
2649 sep = eol = '\0'
2653 sep = eol = '\0'
2650
2654
2651 getfile = util.lrucachefunc(repo.file)
2655 getfile = util.lrucachefunc(repo.file)
2652
2656
2653 def matchlines(body):
2657 def matchlines(body):
2654 begin = 0
2658 begin = 0
2655 linenum = 0
2659 linenum = 0
2656 while True:
2660 while True:
2657 match = regexp.search(body, begin)
2661 match = regexp.search(body, begin)
2658 if not match:
2662 if not match:
2659 break
2663 break
2660 mstart, mend = match.span()
2664 mstart, mend = match.span()
2661 linenum += body.count('\n', begin, mstart) + 1
2665 linenum += body.count('\n', begin, mstart) + 1
2662 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2666 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2663 begin = body.find('\n', mend) + 1 or len(body) + 1
2667 begin = body.find('\n', mend) + 1 or len(body) + 1
2664 lend = begin - 1
2668 lend = begin - 1
2665 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2669 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2666
2670
2667 class linestate(object):
2671 class linestate(object):
2668 def __init__(self, line, linenum, colstart, colend):
2672 def __init__(self, line, linenum, colstart, colend):
2669 self.line = line
2673 self.line = line
2670 self.linenum = linenum
2674 self.linenum = linenum
2671 self.colstart = colstart
2675 self.colstart = colstart
2672 self.colend = colend
2676 self.colend = colend
2673
2677
2674 def __hash__(self):
2678 def __hash__(self):
2675 return hash((self.linenum, self.line))
2679 return hash((self.linenum, self.line))
2676
2680
2677 def __eq__(self, other):
2681 def __eq__(self, other):
2678 return self.line == other.line
2682 return self.line == other.line
2679
2683
2680 matches = {}
2684 matches = {}
2681 copies = {}
2685 copies = {}
2682 def grepbody(fn, rev, body):
2686 def grepbody(fn, rev, body):
2683 matches[rev].setdefault(fn, [])
2687 matches[rev].setdefault(fn, [])
2684 m = matches[rev][fn]
2688 m = matches[rev][fn]
2685 for lnum, cstart, cend, line in matchlines(body):
2689 for lnum, cstart, cend, line in matchlines(body):
2686 s = linestate(line, lnum, cstart, cend)
2690 s = linestate(line, lnum, cstart, cend)
2687 m.append(s)
2691 m.append(s)
2688
2692
2689 def difflinestates(a, b):
2693 def difflinestates(a, b):
2690 sm = difflib.SequenceMatcher(None, a, b)
2694 sm = difflib.SequenceMatcher(None, a, b)
2691 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2695 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2692 if tag == 'insert':
2696 if tag == 'insert':
2693 for i in xrange(blo, bhi):
2697 for i in xrange(blo, bhi):
2694 yield ('+', b[i])
2698 yield ('+', b[i])
2695 elif tag == 'delete':
2699 elif tag == 'delete':
2696 for i in xrange(alo, ahi):
2700 for i in xrange(alo, ahi):
2697 yield ('-', a[i])
2701 yield ('-', a[i])
2698 elif tag == 'replace':
2702 elif tag == 'replace':
2699 for i in xrange(alo, ahi):
2703 for i in xrange(alo, ahi):
2700 yield ('-', a[i])
2704 yield ('-', a[i])
2701 for i in xrange(blo, bhi):
2705 for i in xrange(blo, bhi):
2702 yield ('+', b[i])
2706 yield ('+', b[i])
2703
2707
2704 def display(fn, ctx, pstates, states):
2708 def display(fn, ctx, pstates, states):
2705 rev = ctx.rev()
2709 rev = ctx.rev()
2706 datefunc = ui.quiet and util.shortdate or util.datestr
2710 datefunc = ui.quiet and util.shortdate or util.datestr
2707 found = False
2711 found = False
2708 filerevmatches = {}
2712 filerevmatches = {}
2709 def binary():
2713 def binary():
2710 flog = getfile(fn)
2714 flog = getfile(fn)
2711 return util.binary(flog.read(ctx.filenode(fn)))
2715 return util.binary(flog.read(ctx.filenode(fn)))
2712
2716
2713 if opts.get('all'):
2717 if opts.get('all'):
2714 iter = difflinestates(pstates, states)
2718 iter = difflinestates(pstates, states)
2715 else:
2719 else:
2716 iter = [('', l) for l in states]
2720 iter = [('', l) for l in states]
2717 for change, l in iter:
2721 for change, l in iter:
2718 cols = [fn, str(rev)]
2722 cols = [fn, str(rev)]
2719 before, match, after = None, None, None
2723 before, match, after = None, None, None
2720 if opts.get('line_number'):
2724 if opts.get('line_number'):
2721 cols.append(str(l.linenum))
2725 cols.append(str(l.linenum))
2722 if opts.get('all'):
2726 if opts.get('all'):
2723 cols.append(change)
2727 cols.append(change)
2724 if opts.get('user'):
2728 if opts.get('user'):
2725 cols.append(ui.shortuser(ctx.user()))
2729 cols.append(ui.shortuser(ctx.user()))
2726 if opts.get('date'):
2730 if opts.get('date'):
2727 cols.append(datefunc(ctx.date()))
2731 cols.append(datefunc(ctx.date()))
2728 if opts.get('files_with_matches'):
2732 if opts.get('files_with_matches'):
2729 c = (fn, rev)
2733 c = (fn, rev)
2730 if c in filerevmatches:
2734 if c in filerevmatches:
2731 continue
2735 continue
2732 filerevmatches[c] = 1
2736 filerevmatches[c] = 1
2733 else:
2737 else:
2734 before = l.line[:l.colstart]
2738 before = l.line[:l.colstart]
2735 match = l.line[l.colstart:l.colend]
2739 match = l.line[l.colstart:l.colend]
2736 after = l.line[l.colend:]
2740 after = l.line[l.colend:]
2737 ui.write(sep.join(cols))
2741 ui.write(sep.join(cols))
2738 if before is not None:
2742 if before is not None:
2739 if not opts.get('text') and binary():
2743 if not opts.get('text') and binary():
2740 ui.write(sep + " Binary file matches")
2744 ui.write(sep + " Binary file matches")
2741 else:
2745 else:
2742 ui.write(sep + before)
2746 ui.write(sep + before)
2743 ui.write(match, label='grep.match')
2747 ui.write(match, label='grep.match')
2744 ui.write(after)
2748 ui.write(after)
2745 ui.write(eol)
2749 ui.write(eol)
2746 found = True
2750 found = True
2747 return found
2751 return found
2748
2752
2749 skip = {}
2753 skip = {}
2750 revfiles = {}
2754 revfiles = {}
2751 matchfn = scmutil.match(repo[None], pats, opts)
2755 matchfn = scmutil.match(repo[None], pats, opts)
2752 found = False
2756 found = False
2753 follow = opts.get('follow')
2757 follow = opts.get('follow')
2754
2758
2755 def prep(ctx, fns):
2759 def prep(ctx, fns):
2756 rev = ctx.rev()
2760 rev = ctx.rev()
2757 pctx = ctx.p1()
2761 pctx = ctx.p1()
2758 parent = pctx.rev()
2762 parent = pctx.rev()
2759 matches.setdefault(rev, {})
2763 matches.setdefault(rev, {})
2760 matches.setdefault(parent, {})
2764 matches.setdefault(parent, {})
2761 files = revfiles.setdefault(rev, [])
2765 files = revfiles.setdefault(rev, [])
2762 for fn in fns:
2766 for fn in fns:
2763 flog = getfile(fn)
2767 flog = getfile(fn)
2764 try:
2768 try:
2765 fnode = ctx.filenode(fn)
2769 fnode = ctx.filenode(fn)
2766 except error.LookupError:
2770 except error.LookupError:
2767 continue
2771 continue
2768
2772
2769 copied = flog.renamed(fnode)
2773 copied = flog.renamed(fnode)
2770 copy = follow and copied and copied[0]
2774 copy = follow and copied and copied[0]
2771 if copy:
2775 if copy:
2772 copies.setdefault(rev, {})[fn] = copy
2776 copies.setdefault(rev, {})[fn] = copy
2773 if fn in skip:
2777 if fn in skip:
2774 if copy:
2778 if copy:
2775 skip[copy] = True
2779 skip[copy] = True
2776 continue
2780 continue
2777 files.append(fn)
2781 files.append(fn)
2778
2782
2779 if fn not in matches[rev]:
2783 if fn not in matches[rev]:
2780 grepbody(fn, rev, flog.read(fnode))
2784 grepbody(fn, rev, flog.read(fnode))
2781
2785
2782 pfn = copy or fn
2786 pfn = copy or fn
2783 if pfn not in matches[parent]:
2787 if pfn not in matches[parent]:
2784 try:
2788 try:
2785 fnode = pctx.filenode(pfn)
2789 fnode = pctx.filenode(pfn)
2786 grepbody(pfn, parent, flog.read(fnode))
2790 grepbody(pfn, parent, flog.read(fnode))
2787 except error.LookupError:
2791 except error.LookupError:
2788 pass
2792 pass
2789
2793
2790 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2794 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2791 rev = ctx.rev()
2795 rev = ctx.rev()
2792 parent = ctx.p1().rev()
2796 parent = ctx.p1().rev()
2793 for fn in sorted(revfiles.get(rev, [])):
2797 for fn in sorted(revfiles.get(rev, [])):
2794 states = matches[rev][fn]
2798 states = matches[rev][fn]
2795 copy = copies.get(rev, {}).get(fn)
2799 copy = copies.get(rev, {}).get(fn)
2796 if fn in skip:
2800 if fn in skip:
2797 if copy:
2801 if copy:
2798 skip[copy] = True
2802 skip[copy] = True
2799 continue
2803 continue
2800 pstates = matches.get(parent, {}).get(copy or fn, [])
2804 pstates = matches.get(parent, {}).get(copy or fn, [])
2801 if pstates or states:
2805 if pstates or states:
2802 r = display(fn, ctx, pstates, states)
2806 r = display(fn, ctx, pstates, states)
2803 found = found or r
2807 found = found or r
2804 if r and not opts.get('all'):
2808 if r and not opts.get('all'):
2805 skip[fn] = True
2809 skip[fn] = True
2806 if copy:
2810 if copy:
2807 skip[copy] = True
2811 skip[copy] = True
2808 del matches[rev]
2812 del matches[rev]
2809 del revfiles[rev]
2813 del revfiles[rev]
2810
2814
2811 return not found
2815 return not found
2812
2816
2813 @command('heads',
2817 @command('heads',
2814 [('r', 'rev', '',
2818 [('r', 'rev', '',
2815 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2819 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2816 ('t', 'topo', False, _('show topological heads only')),
2820 ('t', 'topo', False, _('show topological heads only')),
2817 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2821 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2818 ('c', 'closed', False, _('show normal and closed branch heads')),
2822 ('c', 'closed', False, _('show normal and closed branch heads')),
2819 ] + templateopts,
2823 ] + templateopts,
2820 _('[-ac] [-r STARTREV] [REV]...'))
2824 _('[-ac] [-r STARTREV] [REV]...'))
2821 def heads(ui, repo, *branchrevs, **opts):
2825 def heads(ui, repo, *branchrevs, **opts):
2822 """show current repository heads or show branch heads
2826 """show current repository heads or show branch heads
2823
2827
2824 With no arguments, show all repository branch heads.
2828 With no arguments, show all repository branch heads.
2825
2829
2826 Repository "heads" are changesets with no child changesets. They are
2830 Repository "heads" are changesets with no child changesets. They are
2827 where development generally takes place and are the usual targets
2831 where development generally takes place and are the usual targets
2828 for update and merge operations. Branch heads are changesets that have
2832 for update and merge operations. Branch heads are changesets that have
2829 no child changeset on the same branch.
2833 no child changeset on the same branch.
2830
2834
2831 If one or more REVs are given, only branch heads on the branches
2835 If one or more REVs are given, only branch heads on the branches
2832 associated with the specified changesets are shown. This means
2836 associated with the specified changesets are shown. This means
2833 that you can use :hg:`heads foo` to see the heads on a branch
2837 that you can use :hg:`heads foo` to see the heads on a branch
2834 named ``foo``.
2838 named ``foo``.
2835
2839
2836 If -c/--closed is specified, also show branch heads marked closed
2840 If -c/--closed is specified, also show branch heads marked closed
2837 (see :hg:`commit --close-branch`).
2841 (see :hg:`commit --close-branch`).
2838
2842
2839 If STARTREV is specified, only those heads that are descendants of
2843 If STARTREV is specified, only those heads that are descendants of
2840 STARTREV will be displayed.
2844 STARTREV will be displayed.
2841
2845
2842 If -t/--topo is specified, named branch mechanics will be ignored and only
2846 If -t/--topo is specified, named branch mechanics will be ignored and only
2843 changesets without children will be shown.
2847 changesets without children will be shown.
2844
2848
2845 Returns 0 if matching heads are found, 1 if not.
2849 Returns 0 if matching heads are found, 1 if not.
2846 """
2850 """
2847
2851
2848 start = None
2852 start = None
2849 if 'rev' in opts:
2853 if 'rev' in opts:
2850 start = scmutil.revsingle(repo, opts['rev'], None).node()
2854 start = scmutil.revsingle(repo, opts['rev'], None).node()
2851
2855
2852 if opts.get('topo'):
2856 if opts.get('topo'):
2853 heads = [repo[h] for h in repo.heads(start)]
2857 heads = [repo[h] for h in repo.heads(start)]
2854 else:
2858 else:
2855 heads = []
2859 heads = []
2856 for branch in repo.branchmap():
2860 for branch in repo.branchmap():
2857 heads += repo.branchheads(branch, start, opts.get('closed'))
2861 heads += repo.branchheads(branch, start, opts.get('closed'))
2858 heads = [repo[h] for h in heads]
2862 heads = [repo[h] for h in heads]
2859
2863
2860 if branchrevs:
2864 if branchrevs:
2861 branches = set(repo[br].branch() for br in branchrevs)
2865 branches = set(repo[br].branch() for br in branchrevs)
2862 heads = [h for h in heads if h.branch() in branches]
2866 heads = [h for h in heads if h.branch() in branches]
2863
2867
2864 if opts.get('active') and branchrevs:
2868 if opts.get('active') and branchrevs:
2865 dagheads = repo.heads(start)
2869 dagheads = repo.heads(start)
2866 heads = [h for h in heads if h.node() in dagheads]
2870 heads = [h for h in heads if h.node() in dagheads]
2867
2871
2868 if branchrevs:
2872 if branchrevs:
2869 haveheads = set(h.branch() for h in heads)
2873 haveheads = set(h.branch() for h in heads)
2870 if branches - haveheads:
2874 if branches - haveheads:
2871 headless = ', '.join(b for b in branches - haveheads)
2875 headless = ', '.join(b for b in branches - haveheads)
2872 msg = _('no open branch heads found on branches %s')
2876 msg = _('no open branch heads found on branches %s')
2873 if opts.get('rev'):
2877 if opts.get('rev'):
2874 msg += _(' (started at %s)' % opts['rev'])
2878 msg += _(' (started at %s)' % opts['rev'])
2875 ui.warn((msg + '\n') % headless)
2879 ui.warn((msg + '\n') % headless)
2876
2880
2877 if not heads:
2881 if not heads:
2878 return 1
2882 return 1
2879
2883
2880 heads = sorted(heads, key=lambda x: -x.rev())
2884 heads = sorted(heads, key=lambda x: -x.rev())
2881 displayer = cmdutil.show_changeset(ui, repo, opts)
2885 displayer = cmdutil.show_changeset(ui, repo, opts)
2882 for ctx in heads:
2886 for ctx in heads:
2883 displayer.show(ctx)
2887 displayer.show(ctx)
2884 displayer.close()
2888 displayer.close()
2885
2889
2886 @command('help',
2890 @command('help',
2887 [('e', 'extension', None, _('show only help for extensions')),
2891 [('e', 'extension', None, _('show only help for extensions')),
2888 ('c', 'command', None, _('show only help for commands'))],
2892 ('c', 'command', None, _('show only help for commands'))],
2889 _('[-ec] [TOPIC]'))
2893 _('[-ec] [TOPIC]'))
2890 def help_(ui, name=None, unknowncmd=False, full=True, **opts):
2894 def help_(ui, name=None, unknowncmd=False, full=True, **opts):
2891 """show help for a given topic or a help overview
2895 """show help for a given topic or a help overview
2892
2896
2893 With no arguments, print a list of commands with short help messages.
2897 With no arguments, print a list of commands with short help messages.
2894
2898
2895 Given a topic, extension, or command name, print help for that
2899 Given a topic, extension, or command name, print help for that
2896 topic.
2900 topic.
2897
2901
2898 Returns 0 if successful.
2902 Returns 0 if successful.
2899 """
2903 """
2900
2904
2901 textwidth = min(ui.termwidth(), 80) - 2
2905 textwidth = min(ui.termwidth(), 80) - 2
2902
2906
2903 def optrst(options):
2907 def optrst(options):
2904 data = []
2908 data = []
2905 multioccur = False
2909 multioccur = False
2906 for option in options:
2910 for option in options:
2907 if len(option) == 5:
2911 if len(option) == 5:
2908 shortopt, longopt, default, desc, optlabel = option
2912 shortopt, longopt, default, desc, optlabel = option
2909 else:
2913 else:
2910 shortopt, longopt, default, desc = option
2914 shortopt, longopt, default, desc = option
2911 optlabel = _("VALUE") # default label
2915 optlabel = _("VALUE") # default label
2912
2916
2913 if _("DEPRECATED") in desc and not ui.verbose:
2917 if _("DEPRECATED") in desc and not ui.verbose:
2914 continue
2918 continue
2915
2919
2916 so = ''
2920 so = ''
2917 if shortopt:
2921 if shortopt:
2918 so = '-' + shortopt
2922 so = '-' + shortopt
2919 lo = '--' + longopt
2923 lo = '--' + longopt
2920 if default:
2924 if default:
2921 desc += _(" (default: %s)") % default
2925 desc += _(" (default: %s)") % default
2922
2926
2923 if isinstance(default, list):
2927 if isinstance(default, list):
2924 lo += " %s [+]" % optlabel
2928 lo += " %s [+]" % optlabel
2925 multioccur = True
2929 multioccur = True
2926 elif (default is not None) and not isinstance(default, bool):
2930 elif (default is not None) and not isinstance(default, bool):
2927 lo += " %s" % optlabel
2931 lo += " %s" % optlabel
2928
2932
2929 data.append((so, lo, desc))
2933 data.append((so, lo, desc))
2930
2934
2931 rst = minirst.maketable(data, 1)
2935 rst = minirst.maketable(data, 1)
2932
2936
2933 if multioccur:
2937 if multioccur:
2934 rst += _("\n[+] marked option can be specified multiple times\n")
2938 rst += _("\n[+] marked option can be specified multiple times\n")
2935
2939
2936 return rst
2940 return rst
2937
2941
2938 # list all option lists
2942 # list all option lists
2939 def opttext(optlist, width):
2943 def opttext(optlist, width):
2940 rst = ''
2944 rst = ''
2941 if not optlist:
2945 if not optlist:
2942 return ''
2946 return ''
2943
2947
2944 for title, options in optlist:
2948 for title, options in optlist:
2945 rst += '\n%s\n' % title
2949 rst += '\n%s\n' % title
2946 if options:
2950 if options:
2947 rst += "\n"
2951 rst += "\n"
2948 rst += optrst(options)
2952 rst += optrst(options)
2949 rst += '\n'
2953 rst += '\n'
2950
2954
2951 return '\n' + minirst.format(rst, width)
2955 return '\n' + minirst.format(rst, width)
2952
2956
2953 def addglobalopts(optlist, aliases):
2957 def addglobalopts(optlist, aliases):
2954 if ui.quiet:
2958 if ui.quiet:
2955 return []
2959 return []
2956
2960
2957 if ui.verbose:
2961 if ui.verbose:
2958 optlist.append((_("global options:"), globalopts))
2962 optlist.append((_("global options:"), globalopts))
2959 if name == 'shortlist':
2963 if name == 'shortlist':
2960 optlist.append((_('use "hg help" for the full list '
2964 optlist.append((_('use "hg help" for the full list '
2961 'of commands'), ()))
2965 'of commands'), ()))
2962 else:
2966 else:
2963 if name == 'shortlist':
2967 if name == 'shortlist':
2964 msg = _('use "hg help" for the full list of commands '
2968 msg = _('use "hg help" for the full list of commands '
2965 'or "hg -v" for details')
2969 'or "hg -v" for details')
2966 elif name and not full:
2970 elif name and not full:
2967 msg = _('use "hg help %s" to show the full help text' % name)
2971 msg = _('use "hg help %s" to show the full help text' % name)
2968 elif aliases:
2972 elif aliases:
2969 msg = _('use "hg -v help%s" to show builtin aliases and '
2973 msg = _('use "hg -v help%s" to show builtin aliases and '
2970 'global options') % (name and " " + name or "")
2974 'global options') % (name and " " + name or "")
2971 else:
2975 else:
2972 msg = _('use "hg -v help %s" to show more info') % name
2976 msg = _('use "hg -v help %s" to show more info') % name
2973 optlist.append((msg, ()))
2977 optlist.append((msg, ()))
2974
2978
2975 def helpcmd(name):
2979 def helpcmd(name):
2976 try:
2980 try:
2977 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
2981 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
2978 except error.AmbiguousCommand, inst:
2982 except error.AmbiguousCommand, inst:
2979 # py3k fix: except vars can't be used outside the scope of the
2983 # py3k fix: except vars can't be used outside the scope of the
2980 # except block, nor can be used inside a lambda. python issue4617
2984 # except block, nor can be used inside a lambda. python issue4617
2981 prefix = inst.args[0]
2985 prefix = inst.args[0]
2982 select = lambda c: c.lstrip('^').startswith(prefix)
2986 select = lambda c: c.lstrip('^').startswith(prefix)
2983 helplist(select)
2987 helplist(select)
2984 return
2988 return
2985
2989
2986 # check if it's an invalid alias and display its error if it is
2990 # check if it's an invalid alias and display its error if it is
2987 if getattr(entry[0], 'badalias', False):
2991 if getattr(entry[0], 'badalias', False):
2988 if not unknowncmd:
2992 if not unknowncmd:
2989 entry[0](ui)
2993 entry[0](ui)
2990 return
2994 return
2991
2995
2992 rst = ""
2996 rst = ""
2993
2997
2994 # synopsis
2998 # synopsis
2995 if len(entry) > 2:
2999 if len(entry) > 2:
2996 if entry[2].startswith('hg'):
3000 if entry[2].startswith('hg'):
2997 rst += "%s\n" % entry[2]
3001 rst += "%s\n" % entry[2]
2998 else:
3002 else:
2999 rst += 'hg %s %s\n' % (aliases[0], entry[2])
3003 rst += 'hg %s %s\n' % (aliases[0], entry[2])
3000 else:
3004 else:
3001 rst += 'hg %s\n' % aliases[0]
3005 rst += 'hg %s\n' % aliases[0]
3002
3006
3003 # aliases
3007 # aliases
3004 if full and not ui.quiet and len(aliases) > 1:
3008 if full and not ui.quiet and len(aliases) > 1:
3005 rst += _("\naliases: %s\n") % ', '.join(aliases[1:])
3009 rst += _("\naliases: %s\n") % ', '.join(aliases[1:])
3006
3010
3007 # description
3011 # description
3008 doc = gettext(entry[0].__doc__)
3012 doc = gettext(entry[0].__doc__)
3009 if not doc:
3013 if not doc:
3010 doc = _("(no help text available)")
3014 doc = _("(no help text available)")
3011 if util.safehasattr(entry[0], 'definition'): # aliased command
3015 if util.safehasattr(entry[0], 'definition'): # aliased command
3012 if entry[0].definition.startswith('!'): # shell alias
3016 if entry[0].definition.startswith('!'): # shell alias
3013 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
3017 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
3014 else:
3018 else:
3015 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
3019 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
3016 if ui.quiet or not full:
3020 if ui.quiet or not full:
3017 doc = doc.splitlines()[0]
3021 doc = doc.splitlines()[0]
3018 rst += "\n" + doc + "\n"
3022 rst += "\n" + doc + "\n"
3019
3023
3020 # check if this command shadows a non-trivial (multi-line)
3024 # check if this command shadows a non-trivial (multi-line)
3021 # extension help text
3025 # extension help text
3022 try:
3026 try:
3023 mod = extensions.find(name)
3027 mod = extensions.find(name)
3024 doc = gettext(mod.__doc__) or ''
3028 doc = gettext(mod.__doc__) or ''
3025 if '\n' in doc.strip():
3029 if '\n' in doc.strip():
3026 msg = _('use "hg help -e %s" to show help for '
3030 msg = _('use "hg help -e %s" to show help for '
3027 'the %s extension') % (name, name)
3031 'the %s extension') % (name, name)
3028 rst += '\n%s\n' % msg
3032 rst += '\n%s\n' % msg
3029 except KeyError:
3033 except KeyError:
3030 pass
3034 pass
3031
3035
3032 # options
3036 # options
3033 if not ui.quiet and entry[1]:
3037 if not ui.quiet and entry[1]:
3034 rst += '\noptions:\n\n'
3038 rst += '\noptions:\n\n'
3035 rst += optrst(entry[1])
3039 rst += optrst(entry[1])
3036
3040
3037 if ui.verbose:
3041 if ui.verbose:
3038 rst += '\nglobal options:\n\n'
3042 rst += '\nglobal options:\n\n'
3039 rst += optrst(globalopts)
3043 rst += optrst(globalopts)
3040
3044
3041 keep = ui.verbose and ['verbose'] or []
3045 keep = ui.verbose and ['verbose'] or []
3042 formatted, pruned = minirst.format(rst, textwidth, keep=keep)
3046 formatted, pruned = minirst.format(rst, textwidth, keep=keep)
3043 ui.write(formatted)
3047 ui.write(formatted)
3044
3048
3045 if not ui.verbose:
3049 if not ui.verbose:
3046 if not full:
3050 if not full:
3047 ui.write(_('\nuse "hg help %s" to show the full help text\n')
3051 ui.write(_('\nuse "hg help %s" to show the full help text\n')
3048 % name)
3052 % name)
3049 elif not ui.quiet:
3053 elif not ui.quiet:
3050 ui.write(_('\nuse "hg -v help %s" to show more info\n') % name)
3054 ui.write(_('\nuse "hg -v help %s" to show more info\n') % name)
3051
3055
3052
3056
3053 def helplist(select=None):
3057 def helplist(select=None):
3054 # list of commands
3058 # list of commands
3055 if name == "shortlist":
3059 if name == "shortlist":
3056 header = _('basic commands:\n\n')
3060 header = _('basic commands:\n\n')
3057 else:
3061 else:
3058 header = _('list of commands:\n\n')
3062 header = _('list of commands:\n\n')
3059
3063
3060 h = {}
3064 h = {}
3061 cmds = {}
3065 cmds = {}
3062 for c, e in table.iteritems():
3066 for c, e in table.iteritems():
3063 f = c.split("|", 1)[0]
3067 f = c.split("|", 1)[0]
3064 if select and not select(f):
3068 if select and not select(f):
3065 continue
3069 continue
3066 if (not select and name != 'shortlist' and
3070 if (not select and name != 'shortlist' and
3067 e[0].__module__ != __name__):
3071 e[0].__module__ != __name__):
3068 continue
3072 continue
3069 if name == "shortlist" and not f.startswith("^"):
3073 if name == "shortlist" and not f.startswith("^"):
3070 continue
3074 continue
3071 f = f.lstrip("^")
3075 f = f.lstrip("^")
3072 if not ui.debugflag and f.startswith("debug"):
3076 if not ui.debugflag and f.startswith("debug"):
3073 continue
3077 continue
3074 doc = e[0].__doc__
3078 doc = e[0].__doc__
3075 if doc and 'DEPRECATED' in doc and not ui.verbose:
3079 if doc and 'DEPRECATED' in doc and not ui.verbose:
3076 continue
3080 continue
3077 doc = gettext(doc)
3081 doc = gettext(doc)
3078 if not doc:
3082 if not doc:
3079 doc = _("(no help text available)")
3083 doc = _("(no help text available)")
3080 h[f] = doc.splitlines()[0].rstrip()
3084 h[f] = doc.splitlines()[0].rstrip()
3081 cmds[f] = c.lstrip("^")
3085 cmds[f] = c.lstrip("^")
3082
3086
3083 if not h:
3087 if not h:
3084 ui.status(_('no commands defined\n'))
3088 ui.status(_('no commands defined\n'))
3085 return
3089 return
3086
3090
3087 ui.status(header)
3091 ui.status(header)
3088 fns = sorted(h)
3092 fns = sorted(h)
3089 m = max(map(len, fns))
3093 m = max(map(len, fns))
3090 for f in fns:
3094 for f in fns:
3091 if ui.verbose:
3095 if ui.verbose:
3092 commands = cmds[f].replace("|",", ")
3096 commands = cmds[f].replace("|",", ")
3093 ui.write(" %s:\n %s\n"%(commands, h[f]))
3097 ui.write(" %s:\n %s\n"%(commands, h[f]))
3094 else:
3098 else:
3095 ui.write('%s\n' % (util.wrap(h[f], textwidth,
3099 ui.write('%s\n' % (util.wrap(h[f], textwidth,
3096 initindent=' %-*s ' % (m, f),
3100 initindent=' %-*s ' % (m, f),
3097 hangindent=' ' * (m + 4))))
3101 hangindent=' ' * (m + 4))))
3098
3102
3099 if not name:
3103 if not name:
3100 text = help.listexts(_('enabled extensions:'), extensions.enabled())
3104 text = help.listexts(_('enabled extensions:'), extensions.enabled())
3101 if text:
3105 if text:
3102 ui.write("\n%s" % minirst.format(text, textwidth))
3106 ui.write("\n%s" % minirst.format(text, textwidth))
3103
3107
3104 ui.write(_("\nadditional help topics:\n\n"))
3108 ui.write(_("\nadditional help topics:\n\n"))
3105 topics = []
3109 topics = []
3106 for names, header, doc in help.helptable:
3110 for names, header, doc in help.helptable:
3107 topics.append((sorted(names, key=len, reverse=True)[0], header))
3111 topics.append((sorted(names, key=len, reverse=True)[0], header))
3108 topics_len = max([len(s[0]) for s in topics])
3112 topics_len = max([len(s[0]) for s in topics])
3109 for t, desc in topics:
3113 for t, desc in topics:
3110 ui.write(" %-*s %s\n" % (topics_len, t, desc))
3114 ui.write(" %-*s %s\n" % (topics_len, t, desc))
3111
3115
3112 optlist = []
3116 optlist = []
3113 addglobalopts(optlist, True)
3117 addglobalopts(optlist, True)
3114 ui.write(opttext(optlist, textwidth))
3118 ui.write(opttext(optlist, textwidth))
3115
3119
3116 def helptopic(name):
3120 def helptopic(name):
3117 for names, header, doc in help.helptable:
3121 for names, header, doc in help.helptable:
3118 if name in names:
3122 if name in names:
3119 break
3123 break
3120 else:
3124 else:
3121 raise error.UnknownCommand(name)
3125 raise error.UnknownCommand(name)
3122
3126
3123 # description
3127 # description
3124 if not doc:
3128 if not doc:
3125 doc = _("(no help text available)")
3129 doc = _("(no help text available)")
3126 if util.safehasattr(doc, '__call__'):
3130 if util.safehasattr(doc, '__call__'):
3127 doc = doc()
3131 doc = doc()
3128
3132
3129 ui.write("%s\n\n" % header)
3133 ui.write("%s\n\n" % header)
3130 ui.write("%s" % minirst.format(doc, textwidth, indent=4))
3134 ui.write("%s" % minirst.format(doc, textwidth, indent=4))
3131 try:
3135 try:
3132 cmdutil.findcmd(name, table)
3136 cmdutil.findcmd(name, table)
3133 ui.write(_('\nuse "hg help -c %s" to see help for '
3137 ui.write(_('\nuse "hg help -c %s" to see help for '
3134 'the %s command\n') % (name, name))
3138 'the %s command\n') % (name, name))
3135 except error.UnknownCommand:
3139 except error.UnknownCommand:
3136 pass
3140 pass
3137
3141
3138 def helpext(name):
3142 def helpext(name):
3139 try:
3143 try:
3140 mod = extensions.find(name)
3144 mod = extensions.find(name)
3141 doc = gettext(mod.__doc__) or _('no help text available')
3145 doc = gettext(mod.__doc__) or _('no help text available')
3142 except KeyError:
3146 except KeyError:
3143 mod = None
3147 mod = None
3144 doc = extensions.disabledext(name)
3148 doc = extensions.disabledext(name)
3145 if not doc:
3149 if not doc:
3146 raise error.UnknownCommand(name)
3150 raise error.UnknownCommand(name)
3147
3151
3148 if '\n' not in doc:
3152 if '\n' not in doc:
3149 head, tail = doc, ""
3153 head, tail = doc, ""
3150 else:
3154 else:
3151 head, tail = doc.split('\n', 1)
3155 head, tail = doc.split('\n', 1)
3152 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
3156 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
3153 if tail:
3157 if tail:
3154 ui.write(minirst.format(tail, textwidth))
3158 ui.write(minirst.format(tail, textwidth))
3155 ui.status('\n')
3159 ui.status('\n')
3156
3160
3157 if mod:
3161 if mod:
3158 try:
3162 try:
3159 ct = mod.cmdtable
3163 ct = mod.cmdtable
3160 except AttributeError:
3164 except AttributeError:
3161 ct = {}
3165 ct = {}
3162 modcmds = set([c.split('|', 1)[0] for c in ct])
3166 modcmds = set([c.split('|', 1)[0] for c in ct])
3163 helplist(modcmds.__contains__)
3167 helplist(modcmds.__contains__)
3164 else:
3168 else:
3165 ui.write(_('use "hg help extensions" for information on enabling '
3169 ui.write(_('use "hg help extensions" for information on enabling '
3166 'extensions\n'))
3170 'extensions\n'))
3167
3171
3168 def helpextcmd(name):
3172 def helpextcmd(name):
3169 cmd, ext, mod = extensions.disabledcmd(ui, name, ui.config('ui', 'strict'))
3173 cmd, ext, mod = extensions.disabledcmd(ui, name, ui.config('ui', 'strict'))
3170 doc = gettext(mod.__doc__).splitlines()[0]
3174 doc = gettext(mod.__doc__).splitlines()[0]
3171
3175
3172 msg = help.listexts(_("'%s' is provided by the following "
3176 msg = help.listexts(_("'%s' is provided by the following "
3173 "extension:") % cmd, {ext: doc}, indent=4)
3177 "extension:") % cmd, {ext: doc}, indent=4)
3174 ui.write(minirst.format(msg, textwidth))
3178 ui.write(minirst.format(msg, textwidth))
3175 ui.write('\n')
3179 ui.write('\n')
3176 ui.write(_('use "hg help extensions" for information on enabling '
3180 ui.write(_('use "hg help extensions" for information on enabling '
3177 'extensions\n'))
3181 'extensions\n'))
3178
3182
3179 if name and name != 'shortlist':
3183 if name and name != 'shortlist':
3180 i = None
3184 i = None
3181 if unknowncmd:
3185 if unknowncmd:
3182 queries = (helpextcmd,)
3186 queries = (helpextcmd,)
3183 elif opts.get('extension'):
3187 elif opts.get('extension'):
3184 queries = (helpext,)
3188 queries = (helpext,)
3185 elif opts.get('command'):
3189 elif opts.get('command'):
3186 queries = (helpcmd,)
3190 queries = (helpcmd,)
3187 else:
3191 else:
3188 queries = (helptopic, helpcmd, helpext, helpextcmd)
3192 queries = (helptopic, helpcmd, helpext, helpextcmd)
3189 for f in queries:
3193 for f in queries:
3190 try:
3194 try:
3191 f(name)
3195 f(name)
3192 i = None
3196 i = None
3193 break
3197 break
3194 except error.UnknownCommand, inst:
3198 except error.UnknownCommand, inst:
3195 i = inst
3199 i = inst
3196 if i:
3200 if i:
3197 raise i
3201 raise i
3198 else:
3202 else:
3199 # program name
3203 # program name
3200 ui.status(_("Mercurial Distributed SCM\n"))
3204 ui.status(_("Mercurial Distributed SCM\n"))
3201 ui.status('\n')
3205 ui.status('\n')
3202 helplist()
3206 helplist()
3203
3207
3204
3208
3205 @command('identify|id',
3209 @command('identify|id',
3206 [('r', 'rev', '',
3210 [('r', 'rev', '',
3207 _('identify the specified revision'), _('REV')),
3211 _('identify the specified revision'), _('REV')),
3208 ('n', 'num', None, _('show local revision number')),
3212 ('n', 'num', None, _('show local revision number')),
3209 ('i', 'id', None, _('show global revision id')),
3213 ('i', 'id', None, _('show global revision id')),
3210 ('b', 'branch', None, _('show branch')),
3214 ('b', 'branch', None, _('show branch')),
3211 ('t', 'tags', None, _('show tags')),
3215 ('t', 'tags', None, _('show tags')),
3212 ('B', 'bookmarks', None, _('show bookmarks'))],
3216 ('B', 'bookmarks', None, _('show bookmarks'))],
3213 _('[-nibtB] [-r REV] [SOURCE]'))
3217 _('[-nibtB] [-r REV] [SOURCE]'))
3214 def identify(ui, repo, source=None, rev=None,
3218 def identify(ui, repo, source=None, rev=None,
3215 num=None, id=None, branch=None, tags=None, bookmarks=None):
3219 num=None, id=None, branch=None, tags=None, bookmarks=None):
3216 """identify the working copy or specified revision
3220 """identify the working copy or specified revision
3217
3221
3218 Print a summary identifying the repository state at REV using one or
3222 Print a summary identifying the repository state at REV using one or
3219 two parent hash identifiers, followed by a "+" if the working
3223 two parent hash identifiers, followed by a "+" if the working
3220 directory has uncommitted changes, the branch name (if not default),
3224 directory has uncommitted changes, the branch name (if not default),
3221 a list of tags, and a list of bookmarks.
3225 a list of tags, and a list of bookmarks.
3222
3226
3223 When REV is not given, print a summary of the current state of the
3227 When REV is not given, print a summary of the current state of the
3224 repository.
3228 repository.
3225
3229
3226 Specifying a path to a repository root or Mercurial bundle will
3230 Specifying a path to a repository root or Mercurial bundle will
3227 cause lookup to operate on that repository/bundle.
3231 cause lookup to operate on that repository/bundle.
3228
3232
3229 .. container:: verbose
3233 .. container:: verbose
3230
3234
3231 Examples:
3235 Examples:
3232
3236
3233 - generate a build identifier for the working directory::
3237 - generate a build identifier for the working directory::
3234
3238
3235 hg id --id > build-id.dat
3239 hg id --id > build-id.dat
3236
3240
3237 - find the revision corresponding to a tag::
3241 - find the revision corresponding to a tag::
3238
3242
3239 hg id -n -r 1.3
3243 hg id -n -r 1.3
3240
3244
3241 - check the most recent revision of a remote repository::
3245 - check the most recent revision of a remote repository::
3242
3246
3243 hg id -r tip http://selenic.com/hg/
3247 hg id -r tip http://selenic.com/hg/
3244
3248
3245 Returns 0 if successful.
3249 Returns 0 if successful.
3246 """
3250 """
3247
3251
3248 if not repo and not source:
3252 if not repo and not source:
3249 raise util.Abort(_("there is no Mercurial repository here "
3253 raise util.Abort(_("there is no Mercurial repository here "
3250 "(.hg not found)"))
3254 "(.hg not found)"))
3251
3255
3252 hexfunc = ui.debugflag and hex or short
3256 hexfunc = ui.debugflag and hex or short
3253 default = not (num or id or branch or tags or bookmarks)
3257 default = not (num or id or branch or tags or bookmarks)
3254 output = []
3258 output = []
3255 revs = []
3259 revs = []
3256
3260
3257 if source:
3261 if source:
3258 source, branches = hg.parseurl(ui.expandpath(source))
3262 source, branches = hg.parseurl(ui.expandpath(source))
3259 repo = hg.peer(ui, {}, source)
3263 repo = hg.peer(ui, {}, source)
3260 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
3264 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
3261
3265
3262 if not repo.local():
3266 if not repo.local():
3263 if num or branch or tags:
3267 if num or branch or tags:
3264 raise util.Abort(
3268 raise util.Abort(
3265 _("can't query remote revision number, branch, or tags"))
3269 _("can't query remote revision number, branch, or tags"))
3266 if not rev and revs:
3270 if not rev and revs:
3267 rev = revs[0]
3271 rev = revs[0]
3268 if not rev:
3272 if not rev:
3269 rev = "tip"
3273 rev = "tip"
3270
3274
3271 remoterev = repo.lookup(rev)
3275 remoterev = repo.lookup(rev)
3272 if default or id:
3276 if default or id:
3273 output = [hexfunc(remoterev)]
3277 output = [hexfunc(remoterev)]
3274
3278
3275 def getbms():
3279 def getbms():
3276 bms = []
3280 bms = []
3277
3281
3278 if 'bookmarks' in repo.listkeys('namespaces'):
3282 if 'bookmarks' in repo.listkeys('namespaces'):
3279 hexremoterev = hex(remoterev)
3283 hexremoterev = hex(remoterev)
3280 bms = [bm for bm, bmr in repo.listkeys('bookmarks').iteritems()
3284 bms = [bm for bm, bmr in repo.listkeys('bookmarks').iteritems()
3281 if bmr == hexremoterev]
3285 if bmr == hexremoterev]
3282
3286
3283 return bms
3287 return bms
3284
3288
3285 if bookmarks:
3289 if bookmarks:
3286 output.extend(getbms())
3290 output.extend(getbms())
3287 elif default and not ui.quiet:
3291 elif default and not ui.quiet:
3288 # multiple bookmarks for a single parent separated by '/'
3292 # multiple bookmarks for a single parent separated by '/'
3289 bm = '/'.join(getbms())
3293 bm = '/'.join(getbms())
3290 if bm:
3294 if bm:
3291 output.append(bm)
3295 output.append(bm)
3292 else:
3296 else:
3293 if not rev:
3297 if not rev:
3294 ctx = repo[None]
3298 ctx = repo[None]
3295 parents = ctx.parents()
3299 parents = ctx.parents()
3296 changed = ""
3300 changed = ""
3297 if default or id or num:
3301 if default or id or num:
3298 changed = util.any(repo.status()) and "+" or ""
3302 changed = util.any(repo.status()) and "+" or ""
3299 if default or id:
3303 if default or id:
3300 output = ["%s%s" %
3304 output = ["%s%s" %
3301 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3305 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3302 if num:
3306 if num:
3303 output.append("%s%s" %
3307 output.append("%s%s" %
3304 ('+'.join([str(p.rev()) for p in parents]), changed))
3308 ('+'.join([str(p.rev()) for p in parents]), changed))
3305 else:
3309 else:
3306 ctx = scmutil.revsingle(repo, rev)
3310 ctx = scmutil.revsingle(repo, rev)
3307 if default or id:
3311 if default or id:
3308 output = [hexfunc(ctx.node())]
3312 output = [hexfunc(ctx.node())]
3309 if num:
3313 if num:
3310 output.append(str(ctx.rev()))
3314 output.append(str(ctx.rev()))
3311
3315
3312 if default and not ui.quiet:
3316 if default and not ui.quiet:
3313 b = ctx.branch()
3317 b = ctx.branch()
3314 if b != 'default':
3318 if b != 'default':
3315 output.append("(%s)" % b)
3319 output.append("(%s)" % b)
3316
3320
3317 # multiple tags for a single parent separated by '/'
3321 # multiple tags for a single parent separated by '/'
3318 t = '/'.join(ctx.tags())
3322 t = '/'.join(ctx.tags())
3319 if t:
3323 if t:
3320 output.append(t)
3324 output.append(t)
3321
3325
3322 # multiple bookmarks for a single parent separated by '/'
3326 # multiple bookmarks for a single parent separated by '/'
3323 bm = '/'.join(ctx.bookmarks())
3327 bm = '/'.join(ctx.bookmarks())
3324 if bm:
3328 if bm:
3325 output.append(bm)
3329 output.append(bm)
3326 else:
3330 else:
3327 if branch:
3331 if branch:
3328 output.append(ctx.branch())
3332 output.append(ctx.branch())
3329
3333
3330 if tags:
3334 if tags:
3331 output.extend(ctx.tags())
3335 output.extend(ctx.tags())
3332
3336
3333 if bookmarks:
3337 if bookmarks:
3334 output.extend(ctx.bookmarks())
3338 output.extend(ctx.bookmarks())
3335
3339
3336 ui.write("%s\n" % ' '.join(output))
3340 ui.write("%s\n" % ' '.join(output))
3337
3341
3338 @command('import|patch',
3342 @command('import|patch',
3339 [('p', 'strip', 1,
3343 [('p', 'strip', 1,
3340 _('directory strip option for patch. This has the same '
3344 _('directory strip option for patch. This has the same '
3341 'meaning as the corresponding patch option'), _('NUM')),
3345 'meaning as the corresponding patch option'), _('NUM')),
3342 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3346 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3343 ('e', 'edit', False, _('invoke editor on commit messages')),
3347 ('e', 'edit', False, _('invoke editor on commit messages')),
3344 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3348 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3345 ('', 'no-commit', None,
3349 ('', 'no-commit', None,
3346 _("don't commit, just update the working directory")),
3350 _("don't commit, just update the working directory")),
3347 ('', 'bypass', None,
3351 ('', 'bypass', None,
3348 _("apply patch without touching the working directory")),
3352 _("apply patch without touching the working directory")),
3349 ('', 'exact', None,
3353 ('', 'exact', None,
3350 _('apply patch to the nodes from which it was generated')),
3354 _('apply patch to the nodes from which it was generated')),
3351 ('', 'import-branch', None,
3355 ('', 'import-branch', None,
3352 _('use any branch information in patch (implied by --exact)'))] +
3356 _('use any branch information in patch (implied by --exact)'))] +
3353 commitopts + commitopts2 + similarityopts,
3357 commitopts + commitopts2 + similarityopts,
3354 _('[OPTION]... PATCH...'))
3358 _('[OPTION]... PATCH...'))
3355 def import_(ui, repo, patch1, *patches, **opts):
3359 def import_(ui, repo, patch1, *patches, **opts):
3356 """import an ordered set of patches
3360 """import an ordered set of patches
3357
3361
3358 Import a list of patches and commit them individually (unless
3362 Import a list of patches and commit them individually (unless
3359 --no-commit is specified).
3363 --no-commit is specified).
3360
3364
3361 If there are outstanding changes in the working directory, import
3365 If there are outstanding changes in the working directory, import
3362 will abort unless given the -f/--force flag.
3366 will abort unless given the -f/--force flag.
3363
3367
3364 You can import a patch straight from a mail message. Even patches
3368 You can import a patch straight from a mail message. Even patches
3365 as attachments work (to use the body part, it must have type
3369 as attachments work (to use the body part, it must have type
3366 text/plain or text/x-patch). From and Subject headers of email
3370 text/plain or text/x-patch). From and Subject headers of email
3367 message are used as default committer and commit message. All
3371 message are used as default committer and commit message. All
3368 text/plain body parts before first diff are added to commit
3372 text/plain body parts before first diff are added to commit
3369 message.
3373 message.
3370
3374
3371 If the imported patch was generated by :hg:`export`, user and
3375 If the imported patch was generated by :hg:`export`, user and
3372 description from patch override values from message headers and
3376 description from patch override values from message headers and
3373 body. Values given on command line with -m/--message and -u/--user
3377 body. Values given on command line with -m/--message and -u/--user
3374 override these.
3378 override these.
3375
3379
3376 If --exact is specified, import will set the working directory to
3380 If --exact is specified, import will set the working directory to
3377 the parent of each patch before applying it, and will abort if the
3381 the parent of each patch before applying it, and will abort if the
3378 resulting changeset has a different ID than the one recorded in
3382 resulting changeset has a different ID than the one recorded in
3379 the patch. This may happen due to character set problems or other
3383 the patch. This may happen due to character set problems or other
3380 deficiencies in the text patch format.
3384 deficiencies in the text patch format.
3381
3385
3382 Use --bypass to apply and commit patches directly to the
3386 Use --bypass to apply and commit patches directly to the
3383 repository, not touching the working directory. Without --exact,
3387 repository, not touching the working directory. Without --exact,
3384 patches will be applied on top of the working directory parent
3388 patches will be applied on top of the working directory parent
3385 revision.
3389 revision.
3386
3390
3387 With -s/--similarity, hg will attempt to discover renames and
3391 With -s/--similarity, hg will attempt to discover renames and
3388 copies in the patch in the same way as 'addremove'.
3392 copies in the patch in the same way as 'addremove'.
3389
3393
3390 To read a patch from standard input, use "-" as the patch name. If
3394 To read a patch from standard input, use "-" as the patch name. If
3391 a URL is specified, the patch will be downloaded from it.
3395 a URL is specified, the patch will be downloaded from it.
3392 See :hg:`help dates` for a list of formats valid for -d/--date.
3396 See :hg:`help dates` for a list of formats valid for -d/--date.
3393
3397
3394 .. container:: verbose
3398 .. container:: verbose
3395
3399
3396 Examples:
3400 Examples:
3397
3401
3398 - import a traditional patch from a website and detect renames::
3402 - import a traditional patch from a website and detect renames::
3399
3403
3400 hg import -s 80 http://example.com/bugfix.patch
3404 hg import -s 80 http://example.com/bugfix.patch
3401
3405
3402 - import a changeset from an hgweb server::
3406 - import a changeset from an hgweb server::
3403
3407
3404 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3408 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3405
3409
3406 - import all the patches in an Unix-style mbox::
3410 - import all the patches in an Unix-style mbox::
3407
3411
3408 hg import incoming-patches.mbox
3412 hg import incoming-patches.mbox
3409
3413
3410 - attempt to exactly restore an exported changeset (not always
3414 - attempt to exactly restore an exported changeset (not always
3411 possible)::
3415 possible)::
3412
3416
3413 hg import --exact proposed-fix.patch
3417 hg import --exact proposed-fix.patch
3414
3418
3415 Returns 0 on success.
3419 Returns 0 on success.
3416 """
3420 """
3417 patches = (patch1,) + patches
3421 patches = (patch1,) + patches
3418
3422
3419 date = opts.get('date')
3423 date = opts.get('date')
3420 if date:
3424 if date:
3421 opts['date'] = util.parsedate(date)
3425 opts['date'] = util.parsedate(date)
3422
3426
3423 editor = cmdutil.commiteditor
3427 editor = cmdutil.commiteditor
3424 if opts.get('edit'):
3428 if opts.get('edit'):
3425 editor = cmdutil.commitforceeditor
3429 editor = cmdutil.commitforceeditor
3426
3430
3427 update = not opts.get('bypass')
3431 update = not opts.get('bypass')
3428 if not update and opts.get('no_commit'):
3432 if not update and opts.get('no_commit'):
3429 raise util.Abort(_('cannot use --no-commit with --bypass'))
3433 raise util.Abort(_('cannot use --no-commit with --bypass'))
3430 try:
3434 try:
3431 sim = float(opts.get('similarity') or 0)
3435 sim = float(opts.get('similarity') or 0)
3432 except ValueError:
3436 except ValueError:
3433 raise util.Abort(_('similarity must be a number'))
3437 raise util.Abort(_('similarity must be a number'))
3434 if sim < 0 or sim > 100:
3438 if sim < 0 or sim > 100:
3435 raise util.Abort(_('similarity must be between 0 and 100'))
3439 raise util.Abort(_('similarity must be between 0 and 100'))
3436 if sim and not update:
3440 if sim and not update:
3437 raise util.Abort(_('cannot use --similarity with --bypass'))
3441 raise util.Abort(_('cannot use --similarity with --bypass'))
3438
3442
3439 if (opts.get('exact') or not opts.get('force')) and update:
3443 if (opts.get('exact') or not opts.get('force')) and update:
3440 cmdutil.bailifchanged(repo)
3444 cmdutil.bailifchanged(repo)
3441
3445
3442 base = opts["base"]
3446 base = opts["base"]
3443 strip = opts["strip"]
3447 strip = opts["strip"]
3444 wlock = lock = tr = None
3448 wlock = lock = tr = None
3445 msgs = []
3449 msgs = []
3446
3450
3447 def checkexact(repo, n, nodeid):
3451 def checkexact(repo, n, nodeid):
3448 if opts.get('exact') and hex(n) != nodeid:
3452 if opts.get('exact') and hex(n) != nodeid:
3449 repo.rollback()
3453 repo.rollback()
3450 raise util.Abort(_('patch is damaged or loses information'))
3454 raise util.Abort(_('patch is damaged or loses information'))
3451
3455
3452 def tryone(ui, hunk, parents):
3456 def tryone(ui, hunk, parents):
3453 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3457 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3454 patch.extract(ui, hunk)
3458 patch.extract(ui, hunk)
3455
3459
3456 if not tmpname:
3460 if not tmpname:
3457 return (None, None)
3461 return (None, None)
3458 msg = _('applied to working directory')
3462 msg = _('applied to working directory')
3459
3463
3460 try:
3464 try:
3461 cmdline_message = cmdutil.logmessage(ui, opts)
3465 cmdline_message = cmdutil.logmessage(ui, opts)
3462 if cmdline_message:
3466 if cmdline_message:
3463 # pickup the cmdline msg
3467 # pickup the cmdline msg
3464 message = cmdline_message
3468 message = cmdline_message
3465 elif message:
3469 elif message:
3466 # pickup the patch msg
3470 # pickup the patch msg
3467 message = message.strip()
3471 message = message.strip()
3468 else:
3472 else:
3469 # launch the editor
3473 # launch the editor
3470 message = None
3474 message = None
3471 ui.debug('message:\n%s\n' % message)
3475 ui.debug('message:\n%s\n' % message)
3472
3476
3473 if len(parents) == 1:
3477 if len(parents) == 1:
3474 parents.append(repo[nullid])
3478 parents.append(repo[nullid])
3475 if opts.get('exact'):
3479 if opts.get('exact'):
3476 if not nodeid or not p1:
3480 if not nodeid or not p1:
3477 raise util.Abort(_('not a Mercurial patch'))
3481 raise util.Abort(_('not a Mercurial patch'))
3478 p1 = repo[p1]
3482 p1 = repo[p1]
3479 p2 = repo[p2 or nullid]
3483 p2 = repo[p2 or nullid]
3480 elif p2:
3484 elif p2:
3481 try:
3485 try:
3482 p1 = repo[p1]
3486 p1 = repo[p1]
3483 p2 = repo[p2]
3487 p2 = repo[p2]
3484 except error.RepoError:
3488 except error.RepoError:
3485 p1, p2 = parents
3489 p1, p2 = parents
3486 else:
3490 else:
3487 p1, p2 = parents
3491 p1, p2 = parents
3488
3492
3489 n = None
3493 n = None
3490 if update:
3494 if update:
3491 if opts.get('exact') and p1 != parents[0]:
3495 if opts.get('exact') and p1 != parents[0]:
3492 hg.clean(repo, p1.node())
3496 hg.clean(repo, p1.node())
3493 if p1 != parents[0] and p2 != parents[1]:
3497 if p1 != parents[0] and p2 != parents[1]:
3494 repo.dirstate.setparents(p1.node(), p2.node())
3498 repo.dirstate.setparents(p1.node(), p2.node())
3495
3499
3496 if opts.get('exact') or opts.get('import_branch'):
3500 if opts.get('exact') or opts.get('import_branch'):
3497 repo.dirstate.setbranch(branch or 'default')
3501 repo.dirstate.setbranch(branch or 'default')
3498
3502
3499 files = set()
3503 files = set()
3500 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3504 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3501 eolmode=None, similarity=sim / 100.0)
3505 eolmode=None, similarity=sim / 100.0)
3502 files = list(files)
3506 files = list(files)
3503 if opts.get('no_commit'):
3507 if opts.get('no_commit'):
3504 if message:
3508 if message:
3505 msgs.append(message)
3509 msgs.append(message)
3506 else:
3510 else:
3507 if opts.get('exact'):
3511 if opts.get('exact'):
3508 m = None
3512 m = None
3509 else:
3513 else:
3510 m = scmutil.matchfiles(repo, files or [])
3514 m = scmutil.matchfiles(repo, files or [])
3511 n = repo.commit(message, opts.get('user') or user,
3515 n = repo.commit(message, opts.get('user') or user,
3512 opts.get('date') or date, match=m,
3516 opts.get('date') or date, match=m,
3513 editor=editor)
3517 editor=editor)
3514 checkexact(repo, n, nodeid)
3518 checkexact(repo, n, nodeid)
3515 else:
3519 else:
3516 if opts.get('exact') or opts.get('import_branch'):
3520 if opts.get('exact') or opts.get('import_branch'):
3517 branch = branch or 'default'
3521 branch = branch or 'default'
3518 else:
3522 else:
3519 branch = p1.branch()
3523 branch = p1.branch()
3520 store = patch.filestore()
3524 store = patch.filestore()
3521 try:
3525 try:
3522 files = set()
3526 files = set()
3523 try:
3527 try:
3524 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3528 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3525 files, eolmode=None)
3529 files, eolmode=None)
3526 except patch.PatchError, e:
3530 except patch.PatchError, e:
3527 raise util.Abort(str(e))
3531 raise util.Abort(str(e))
3528 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3532 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3529 message,
3533 message,
3530 opts.get('user') or user,
3534 opts.get('user') or user,
3531 opts.get('date') or date,
3535 opts.get('date') or date,
3532 branch, files, store,
3536 branch, files, store,
3533 editor=cmdutil.commiteditor)
3537 editor=cmdutil.commiteditor)
3534 repo.savecommitmessage(memctx.description())
3538 repo.savecommitmessage(memctx.description())
3535 n = memctx.commit()
3539 n = memctx.commit()
3536 checkexact(repo, n, nodeid)
3540 checkexact(repo, n, nodeid)
3537 finally:
3541 finally:
3538 store.close()
3542 store.close()
3539 if n:
3543 if n:
3540 # i18n: refers to a short changeset id
3544 # i18n: refers to a short changeset id
3541 msg = _('created %s') % short(n)
3545 msg = _('created %s') % short(n)
3542 return (msg, n)
3546 return (msg, n)
3543 finally:
3547 finally:
3544 os.unlink(tmpname)
3548 os.unlink(tmpname)
3545
3549
3546 try:
3550 try:
3547 try:
3551 try:
3548 wlock = repo.wlock()
3552 wlock = repo.wlock()
3549 lock = repo.lock()
3553 lock = repo.lock()
3550 tr = repo.transaction('import')
3554 tr = repo.transaction('import')
3551 parents = repo.parents()
3555 parents = repo.parents()
3552 for patchurl in patches:
3556 for patchurl in patches:
3553 if patchurl == '-':
3557 if patchurl == '-':
3554 ui.status(_('applying patch from stdin\n'))
3558 ui.status(_('applying patch from stdin\n'))
3555 patchfile = ui.fin
3559 patchfile = ui.fin
3556 patchurl = 'stdin' # for error message
3560 patchurl = 'stdin' # for error message
3557 else:
3561 else:
3558 patchurl = os.path.join(base, patchurl)
3562 patchurl = os.path.join(base, patchurl)
3559 ui.status(_('applying %s\n') % patchurl)
3563 ui.status(_('applying %s\n') % patchurl)
3560 patchfile = url.open(ui, patchurl)
3564 patchfile = url.open(ui, patchurl)
3561
3565
3562 haspatch = False
3566 haspatch = False
3563 for hunk in patch.split(patchfile):
3567 for hunk in patch.split(patchfile):
3564 (msg, node) = tryone(ui, hunk, parents)
3568 (msg, node) = tryone(ui, hunk, parents)
3565 if msg:
3569 if msg:
3566 haspatch = True
3570 haspatch = True
3567 ui.note(msg + '\n')
3571 ui.note(msg + '\n')
3568 if update or opts.get('exact'):
3572 if update or opts.get('exact'):
3569 parents = repo.parents()
3573 parents = repo.parents()
3570 else:
3574 else:
3571 parents = [repo[node]]
3575 parents = [repo[node]]
3572
3576
3573 if not haspatch:
3577 if not haspatch:
3574 raise util.Abort(_('%s: no diffs found') % patchurl)
3578 raise util.Abort(_('%s: no diffs found') % patchurl)
3575
3579
3576 tr.close()
3580 tr.close()
3577 if msgs:
3581 if msgs:
3578 repo.savecommitmessage('\n* * *\n'.join(msgs))
3582 repo.savecommitmessage('\n* * *\n'.join(msgs))
3579 except:
3583 except:
3580 # wlock.release() indirectly calls dirstate.write(): since
3584 # wlock.release() indirectly calls dirstate.write(): since
3581 # we're crashing, we do not want to change the working dir
3585 # we're crashing, we do not want to change the working dir
3582 # parent after all, so make sure it writes nothing
3586 # parent after all, so make sure it writes nothing
3583 repo.dirstate.invalidate()
3587 repo.dirstate.invalidate()
3584 raise
3588 raise
3585 finally:
3589 finally:
3586 if tr:
3590 if tr:
3587 tr.release()
3591 tr.release()
3588 release(lock, wlock)
3592 release(lock, wlock)
3589
3593
3590 @command('incoming|in',
3594 @command('incoming|in',
3591 [('f', 'force', None,
3595 [('f', 'force', None,
3592 _('run even if remote repository is unrelated')),
3596 _('run even if remote repository is unrelated')),
3593 ('n', 'newest-first', None, _('show newest record first')),
3597 ('n', 'newest-first', None, _('show newest record first')),
3594 ('', 'bundle', '',
3598 ('', 'bundle', '',
3595 _('file to store the bundles into'), _('FILE')),
3599 _('file to store the bundles into'), _('FILE')),
3596 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3600 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3597 ('B', 'bookmarks', False, _("compare bookmarks")),
3601 ('B', 'bookmarks', False, _("compare bookmarks")),
3598 ('b', 'branch', [],
3602 ('b', 'branch', [],
3599 _('a specific branch you would like to pull'), _('BRANCH')),
3603 _('a specific branch you would like to pull'), _('BRANCH')),
3600 ] + logopts + remoteopts + subrepoopts,
3604 ] + logopts + remoteopts + subrepoopts,
3601 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3605 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3602 def incoming(ui, repo, source="default", **opts):
3606 def incoming(ui, repo, source="default", **opts):
3603 """show new changesets found in source
3607 """show new changesets found in source
3604
3608
3605 Show new changesets found in the specified path/URL or the default
3609 Show new changesets found in the specified path/URL or the default
3606 pull location. These are the changesets that would have been pulled
3610 pull location. These are the changesets that would have been pulled
3607 if a pull at the time you issued this command.
3611 if a pull at the time you issued this command.
3608
3612
3609 For remote repository, using --bundle avoids downloading the
3613 For remote repository, using --bundle avoids downloading the
3610 changesets twice if the incoming is followed by a pull.
3614 changesets twice if the incoming is followed by a pull.
3611
3615
3612 See pull for valid source format details.
3616 See pull for valid source format details.
3613
3617
3614 Returns 0 if there are incoming changes, 1 otherwise.
3618 Returns 0 if there are incoming changes, 1 otherwise.
3615 """
3619 """
3616 if opts.get('bundle') and opts.get('subrepos'):
3620 if opts.get('bundle') and opts.get('subrepos'):
3617 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3621 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3618
3622
3619 if opts.get('bookmarks'):
3623 if opts.get('bookmarks'):
3620 source, branches = hg.parseurl(ui.expandpath(source),
3624 source, branches = hg.parseurl(ui.expandpath(source),
3621 opts.get('branch'))
3625 opts.get('branch'))
3622 other = hg.peer(repo, opts, source)
3626 other = hg.peer(repo, opts, source)
3623 if 'bookmarks' not in other.listkeys('namespaces'):
3627 if 'bookmarks' not in other.listkeys('namespaces'):
3624 ui.warn(_("remote doesn't support bookmarks\n"))
3628 ui.warn(_("remote doesn't support bookmarks\n"))
3625 return 0
3629 return 0
3626 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3630 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3627 return bookmarks.diff(ui, repo, other)
3631 return bookmarks.diff(ui, repo, other)
3628
3632
3629 repo._subtoppath = ui.expandpath(source)
3633 repo._subtoppath = ui.expandpath(source)
3630 try:
3634 try:
3631 return hg.incoming(ui, repo, source, opts)
3635 return hg.incoming(ui, repo, source, opts)
3632 finally:
3636 finally:
3633 del repo._subtoppath
3637 del repo._subtoppath
3634
3638
3635
3639
3636 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3640 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3637 def init(ui, dest=".", **opts):
3641 def init(ui, dest=".", **opts):
3638 """create a new repository in the given directory
3642 """create a new repository in the given directory
3639
3643
3640 Initialize a new repository in the given directory. If the given
3644 Initialize a new repository in the given directory. If the given
3641 directory does not exist, it will be created.
3645 directory does not exist, it will be created.
3642
3646
3643 If no directory is given, the current directory is used.
3647 If no directory is given, the current directory is used.
3644
3648
3645 It is possible to specify an ``ssh://`` URL as the destination.
3649 It is possible to specify an ``ssh://`` URL as the destination.
3646 See :hg:`help urls` for more information.
3650 See :hg:`help urls` for more information.
3647
3651
3648 Returns 0 on success.
3652 Returns 0 on success.
3649 """
3653 """
3650 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3654 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3651
3655
3652 @command('locate',
3656 @command('locate',
3653 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3657 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3654 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3658 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3655 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3659 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3656 ] + walkopts,
3660 ] + walkopts,
3657 _('[OPTION]... [PATTERN]...'))
3661 _('[OPTION]... [PATTERN]...'))
3658 def locate(ui, repo, *pats, **opts):
3662 def locate(ui, repo, *pats, **opts):
3659 """locate files matching specific patterns
3663 """locate files matching specific patterns
3660
3664
3661 Print files under Mercurial control in the working directory whose
3665 Print files under Mercurial control in the working directory whose
3662 names match the given patterns.
3666 names match the given patterns.
3663
3667
3664 By default, this command searches all directories in the working
3668 By default, this command searches all directories in the working
3665 directory. To search just the current directory and its
3669 directory. To search just the current directory and its
3666 subdirectories, use "--include .".
3670 subdirectories, use "--include .".
3667
3671
3668 If no patterns are given to match, this command prints the names
3672 If no patterns are given to match, this command prints the names
3669 of all files under Mercurial control in the working directory.
3673 of all files under Mercurial control in the working directory.
3670
3674
3671 If you want to feed the output of this command into the "xargs"
3675 If you want to feed the output of this command into the "xargs"
3672 command, use the -0 option to both this command and "xargs". This
3676 command, use the -0 option to both this command and "xargs". This
3673 will avoid the problem of "xargs" treating single filenames that
3677 will avoid the problem of "xargs" treating single filenames that
3674 contain whitespace as multiple filenames.
3678 contain whitespace as multiple filenames.
3675
3679
3676 Returns 0 if a match is found, 1 otherwise.
3680 Returns 0 if a match is found, 1 otherwise.
3677 """
3681 """
3678 end = opts.get('print0') and '\0' or '\n'
3682 end = opts.get('print0') and '\0' or '\n'
3679 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3683 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3680
3684
3681 ret = 1
3685 ret = 1
3682 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3686 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3683 m.bad = lambda x, y: False
3687 m.bad = lambda x, y: False
3684 for abs in repo[rev].walk(m):
3688 for abs in repo[rev].walk(m):
3685 if not rev and abs not in repo.dirstate:
3689 if not rev and abs not in repo.dirstate:
3686 continue
3690 continue
3687 if opts.get('fullpath'):
3691 if opts.get('fullpath'):
3688 ui.write(repo.wjoin(abs), end)
3692 ui.write(repo.wjoin(abs), end)
3689 else:
3693 else:
3690 ui.write(((pats and m.rel(abs)) or abs), end)
3694 ui.write(((pats and m.rel(abs)) or abs), end)
3691 ret = 0
3695 ret = 0
3692
3696
3693 return ret
3697 return ret
3694
3698
3695 @command('^log|history',
3699 @command('^log|history',
3696 [('f', 'follow', None,
3700 [('f', 'follow', None,
3697 _('follow changeset history, or file history across copies and renames')),
3701 _('follow changeset history, or file history across copies and renames')),
3698 ('', 'follow-first', None,
3702 ('', 'follow-first', None,
3699 _('only follow the first parent of merge changesets')),
3703 _('only follow the first parent of merge changesets')),
3700 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3704 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3701 ('C', 'copies', None, _('show copied files')),
3705 ('C', 'copies', None, _('show copied files')),
3702 ('k', 'keyword', [],
3706 ('k', 'keyword', [],
3703 _('do case-insensitive search for a given text'), _('TEXT')),
3707 _('do case-insensitive search for a given text'), _('TEXT')),
3704 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3708 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3705 ('', 'removed', None, _('include revisions where files were removed')),
3709 ('', 'removed', None, _('include revisions where files were removed')),
3706 ('m', 'only-merges', None, _('show only merges')),
3710 ('m', 'only-merges', None, _('show only merges')),
3707 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3711 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3708 ('', 'only-branch', [],
3712 ('', 'only-branch', [],
3709 _('show only changesets within the given named branch (DEPRECATED)'),
3713 _('show only changesets within the given named branch (DEPRECATED)'),
3710 _('BRANCH')),
3714 _('BRANCH')),
3711 ('b', 'branch', [],
3715 ('b', 'branch', [],
3712 _('show changesets within the given named branch'), _('BRANCH')),
3716 _('show changesets within the given named branch'), _('BRANCH')),
3713 ('P', 'prune', [],
3717 ('P', 'prune', [],
3714 _('do not display revision or any of its ancestors'), _('REV')),
3718 _('do not display revision or any of its ancestors'), _('REV')),
3715 ('', 'hidden', False, _('show hidden changesets')),
3719 ('', 'hidden', False, _('show hidden changesets')),
3716 ] + logopts + walkopts,
3720 ] + logopts + walkopts,
3717 _('[OPTION]... [FILE]'))
3721 _('[OPTION]... [FILE]'))
3718 def log(ui, repo, *pats, **opts):
3722 def log(ui, repo, *pats, **opts):
3719 """show revision history of entire repository or files
3723 """show revision history of entire repository or files
3720
3724
3721 Print the revision history of the specified files or the entire
3725 Print the revision history of the specified files or the entire
3722 project.
3726 project.
3723
3727
3724 If no revision range is specified, the default is ``tip:0`` unless
3728 If no revision range is specified, the default is ``tip:0`` unless
3725 --follow is set, in which case the working directory parent is
3729 --follow is set, in which case the working directory parent is
3726 used as the starting revision.
3730 used as the starting revision.
3727
3731
3728 File history is shown without following rename or copy history of
3732 File history is shown without following rename or copy history of
3729 files. Use -f/--follow with a filename to follow history across
3733 files. Use -f/--follow with a filename to follow history across
3730 renames and copies. --follow without a filename will only show
3734 renames and copies. --follow without a filename will only show
3731 ancestors or descendants of the starting revision.
3735 ancestors or descendants of the starting revision.
3732
3736
3733 By default this command prints revision number and changeset id,
3737 By default this command prints revision number and changeset id,
3734 tags, non-trivial parents, user, date and time, and a summary for
3738 tags, non-trivial parents, user, date and time, and a summary for
3735 each commit. When the -v/--verbose switch is used, the list of
3739 each commit. When the -v/--verbose switch is used, the list of
3736 changed files and full commit message are shown.
3740 changed files and full commit message are shown.
3737
3741
3738 .. note::
3742 .. note::
3739 log -p/--patch may generate unexpected diff output for merge
3743 log -p/--patch may generate unexpected diff output for merge
3740 changesets, as it will only compare the merge changeset against
3744 changesets, as it will only compare the merge changeset against
3741 its first parent. Also, only files different from BOTH parents
3745 its first parent. Also, only files different from BOTH parents
3742 will appear in files:.
3746 will appear in files:.
3743
3747
3744 .. note::
3748 .. note::
3745 for performance reasons, log FILE may omit duplicate changes
3749 for performance reasons, log FILE may omit duplicate changes
3746 made on branches and will not show deletions. To see all
3750 made on branches and will not show deletions. To see all
3747 changes including duplicates and deletions, use the --removed
3751 changes including duplicates and deletions, use the --removed
3748 switch.
3752 switch.
3749
3753
3750 .. container:: verbose
3754 .. container:: verbose
3751
3755
3752 Some examples:
3756 Some examples:
3753
3757
3754 - changesets with full descriptions and file lists::
3758 - changesets with full descriptions and file lists::
3755
3759
3756 hg log -v
3760 hg log -v
3757
3761
3758 - changesets ancestral to the working directory::
3762 - changesets ancestral to the working directory::
3759
3763
3760 hg log -f
3764 hg log -f
3761
3765
3762 - last 10 commits on the current branch::
3766 - last 10 commits on the current branch::
3763
3767
3764 hg log -l 10 -b .
3768 hg log -l 10 -b .
3765
3769
3766 - changesets showing all modifications of a file, including removals::
3770 - changesets showing all modifications of a file, including removals::
3767
3771
3768 hg log --removed file.c
3772 hg log --removed file.c
3769
3773
3770 - all changesets that touch a directory, with diffs, excluding merges::
3774 - all changesets that touch a directory, with diffs, excluding merges::
3771
3775
3772 hg log -Mp lib/
3776 hg log -Mp lib/
3773
3777
3774 - all revision numbers that match a keyword::
3778 - all revision numbers that match a keyword::
3775
3779
3776 hg log -k bug --template "{rev}\\n"
3780 hg log -k bug --template "{rev}\\n"
3777
3781
3778 - check if a given changeset is included is a tagged release::
3782 - check if a given changeset is included is a tagged release::
3779
3783
3780 hg log -r "a21ccf and ancestor(1.9)"
3784 hg log -r "a21ccf and ancestor(1.9)"
3781
3785
3782 - find all changesets by some user in a date range::
3786 - find all changesets by some user in a date range::
3783
3787
3784 hg log -k alice -d "may 2008 to jul 2008"
3788 hg log -k alice -d "may 2008 to jul 2008"
3785
3789
3786 - summary of all changesets after the last tag::
3790 - summary of all changesets after the last tag::
3787
3791
3788 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3792 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3789
3793
3790 See :hg:`help dates` for a list of formats valid for -d/--date.
3794 See :hg:`help dates` for a list of formats valid for -d/--date.
3791
3795
3792 See :hg:`help revisions` and :hg:`help revsets` for more about
3796 See :hg:`help revisions` and :hg:`help revsets` for more about
3793 specifying revisions.
3797 specifying revisions.
3794
3798
3795 Returns 0 on success.
3799 Returns 0 on success.
3796 """
3800 """
3797
3801
3798 matchfn = scmutil.match(repo[None], pats, opts)
3802 matchfn = scmutil.match(repo[None], pats, opts)
3799 limit = cmdutil.loglimit(opts)
3803 limit = cmdutil.loglimit(opts)
3800 count = 0
3804 count = 0
3801
3805
3802 endrev = None
3806 endrev = None
3803 if opts.get('copies') and opts.get('rev'):
3807 if opts.get('copies') and opts.get('rev'):
3804 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
3808 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
3805
3809
3806 df = False
3810 df = False
3807 if opts["date"]:
3811 if opts["date"]:
3808 df = util.matchdate(opts["date"])
3812 df = util.matchdate(opts["date"])
3809
3813
3810 branches = opts.get('branch', []) + opts.get('only_branch', [])
3814 branches = opts.get('branch', []) + opts.get('only_branch', [])
3811 opts['branch'] = [repo.lookupbranch(b) for b in branches]
3815 opts['branch'] = [repo.lookupbranch(b) for b in branches]
3812
3816
3813 displayer = cmdutil.show_changeset(ui, repo, opts, True)
3817 displayer = cmdutil.show_changeset(ui, repo, opts, True)
3814 def prep(ctx, fns):
3818 def prep(ctx, fns):
3815 rev = ctx.rev()
3819 rev = ctx.rev()
3816 parents = [p for p in repo.changelog.parentrevs(rev)
3820 parents = [p for p in repo.changelog.parentrevs(rev)
3817 if p != nullrev]
3821 if p != nullrev]
3818 if opts.get('no_merges') and len(parents) == 2:
3822 if opts.get('no_merges') and len(parents) == 2:
3819 return
3823 return
3820 if opts.get('only_merges') and len(parents) != 2:
3824 if opts.get('only_merges') and len(parents) != 2:
3821 return
3825 return
3822 if opts.get('branch') and ctx.branch() not in opts['branch']:
3826 if opts.get('branch') and ctx.branch() not in opts['branch']:
3823 return
3827 return
3824 if not opts.get('hidden') and ctx.hidden():
3828 if not opts.get('hidden') and ctx.hidden():
3825 return
3829 return
3826 if df and not df(ctx.date()[0]):
3830 if df and not df(ctx.date()[0]):
3827 return
3831 return
3828 if opts['user'] and not [k for k in opts['user']
3832 if opts['user'] and not [k for k in opts['user']
3829 if k.lower() in ctx.user().lower()]:
3833 if k.lower() in ctx.user().lower()]:
3830 return
3834 return
3831 if opts.get('keyword'):
3835 if opts.get('keyword'):
3832 for k in [kw.lower() for kw in opts['keyword']]:
3836 for k in [kw.lower() for kw in opts['keyword']]:
3833 if (k in ctx.user().lower() or
3837 if (k in ctx.user().lower() or
3834 k in ctx.description().lower() or
3838 k in ctx.description().lower() or
3835 k in " ".join(ctx.files()).lower()):
3839 k in " ".join(ctx.files()).lower()):
3836 break
3840 break
3837 else:
3841 else:
3838 return
3842 return
3839
3843
3840 copies = None
3844 copies = None
3841 if opts.get('copies') and rev:
3845 if opts.get('copies') and rev:
3842 copies = []
3846 copies = []
3843 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3847 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3844 for fn in ctx.files():
3848 for fn in ctx.files():
3845 rename = getrenamed(fn, rev)
3849 rename = getrenamed(fn, rev)
3846 if rename:
3850 if rename:
3847 copies.append((fn, rename[0]))
3851 copies.append((fn, rename[0]))
3848
3852
3849 revmatchfn = None
3853 revmatchfn = None
3850 if opts.get('patch') or opts.get('stat'):
3854 if opts.get('patch') or opts.get('stat'):
3851 if opts.get('follow') or opts.get('follow_first'):
3855 if opts.get('follow') or opts.get('follow_first'):
3852 # note: this might be wrong when following through merges
3856 # note: this might be wrong when following through merges
3853 revmatchfn = scmutil.match(repo[None], fns, default='path')
3857 revmatchfn = scmutil.match(repo[None], fns, default='path')
3854 else:
3858 else:
3855 revmatchfn = matchfn
3859 revmatchfn = matchfn
3856
3860
3857 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3861 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3858
3862
3859 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3863 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3860 if count == limit:
3864 if count == limit:
3861 break
3865 break
3862 if displayer.flush(ctx.rev()):
3866 if displayer.flush(ctx.rev()):
3863 count += 1
3867 count += 1
3864 displayer.close()
3868 displayer.close()
3865
3869
3866 @command('manifest',
3870 @command('manifest',
3867 [('r', 'rev', '', _('revision to display'), _('REV')),
3871 [('r', 'rev', '', _('revision to display'), _('REV')),
3868 ('', 'all', False, _("list files from all revisions"))],
3872 ('', 'all', False, _("list files from all revisions"))],
3869 _('[-r REV]'))
3873 _('[-r REV]'))
3870 def manifest(ui, repo, node=None, rev=None, **opts):
3874 def manifest(ui, repo, node=None, rev=None, **opts):
3871 """output the current or given revision of the project manifest
3875 """output the current or given revision of the project manifest
3872
3876
3873 Print a list of version controlled files for the given revision.
3877 Print a list of version controlled files for the given revision.
3874 If no revision is given, the first parent of the working directory
3878 If no revision is given, the first parent of the working directory
3875 is used, or the null revision if no revision is checked out.
3879 is used, or the null revision if no revision is checked out.
3876
3880
3877 With -v, print file permissions, symlink and executable bits.
3881 With -v, print file permissions, symlink and executable bits.
3878 With --debug, print file revision hashes.
3882 With --debug, print file revision hashes.
3879
3883
3880 If option --all is specified, the list of all files from all revisions
3884 If option --all is specified, the list of all files from all revisions
3881 is printed. This includes deleted and renamed files.
3885 is printed. This includes deleted and renamed files.
3882
3886
3883 Returns 0 on success.
3887 Returns 0 on success.
3884 """
3888 """
3885 if opts.get('all'):
3889 if opts.get('all'):
3886 if rev or node:
3890 if rev or node:
3887 raise util.Abort(_("can't specify a revision with --all"))
3891 raise util.Abort(_("can't specify a revision with --all"))
3888
3892
3889 res = []
3893 res = []
3890 prefix = "data/"
3894 prefix = "data/"
3891 suffix = ".i"
3895 suffix = ".i"
3892 plen = len(prefix)
3896 plen = len(prefix)
3893 slen = len(suffix)
3897 slen = len(suffix)
3894 lock = repo.lock()
3898 lock = repo.lock()
3895 try:
3899 try:
3896 for fn, b, size in repo.store.datafiles():
3900 for fn, b, size in repo.store.datafiles():
3897 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3901 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3898 res.append(fn[plen:-slen])
3902 res.append(fn[plen:-slen])
3899 finally:
3903 finally:
3900 lock.release()
3904 lock.release()
3901 for f in sorted(res):
3905 for f in sorted(res):
3902 ui.write("%s\n" % f)
3906 ui.write("%s\n" % f)
3903 return
3907 return
3904
3908
3905 if rev and node:
3909 if rev and node:
3906 raise util.Abort(_("please specify just one revision"))
3910 raise util.Abort(_("please specify just one revision"))
3907
3911
3908 if not node:
3912 if not node:
3909 node = rev
3913 node = rev
3910
3914
3911 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
3915 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
3912 ctx = scmutil.revsingle(repo, node)
3916 ctx = scmutil.revsingle(repo, node)
3913 for f in ctx:
3917 for f in ctx:
3914 if ui.debugflag:
3918 if ui.debugflag:
3915 ui.write("%40s " % hex(ctx.manifest()[f]))
3919 ui.write("%40s " % hex(ctx.manifest()[f]))
3916 if ui.verbose:
3920 if ui.verbose:
3917 ui.write(decor[ctx.flags(f)])
3921 ui.write(decor[ctx.flags(f)])
3918 ui.write("%s\n" % f)
3922 ui.write("%s\n" % f)
3919
3923
3920 @command('^merge',
3924 @command('^merge',
3921 [('f', 'force', None, _('force a merge with outstanding changes')),
3925 [('f', 'force', None, _('force a merge with outstanding changes')),
3922 ('r', 'rev', '', _('revision to merge'), _('REV')),
3926 ('r', 'rev', '', _('revision to merge'), _('REV')),
3923 ('P', 'preview', None,
3927 ('P', 'preview', None,
3924 _('review revisions to merge (no merge is performed)'))
3928 _('review revisions to merge (no merge is performed)'))
3925 ] + mergetoolopts,
3929 ] + mergetoolopts,
3926 _('[-P] [-f] [[-r] REV]'))
3930 _('[-P] [-f] [[-r] REV]'))
3927 def merge(ui, repo, node=None, **opts):
3931 def merge(ui, repo, node=None, **opts):
3928 """merge working directory with another revision
3932 """merge working directory with another revision
3929
3933
3930 The current working directory is updated with all changes made in
3934 The current working directory is updated with all changes made in
3931 the requested revision since the last common predecessor revision.
3935 the requested revision since the last common predecessor revision.
3932
3936
3933 Files that changed between either parent are marked as changed for
3937 Files that changed between either parent are marked as changed for
3934 the next commit and a commit must be performed before any further
3938 the next commit and a commit must be performed before any further
3935 updates to the repository are allowed. The next commit will have
3939 updates to the repository are allowed. The next commit will have
3936 two parents.
3940 two parents.
3937
3941
3938 ``--tool`` can be used to specify the merge tool used for file
3942 ``--tool`` can be used to specify the merge tool used for file
3939 merges. It overrides the HGMERGE environment variable and your
3943 merges. It overrides the HGMERGE environment variable and your
3940 configuration files. See :hg:`help merge-tools` for options.
3944 configuration files. See :hg:`help merge-tools` for options.
3941
3945
3942 If no revision is specified, the working directory's parent is a
3946 If no revision is specified, the working directory's parent is a
3943 head revision, and the current branch contains exactly one other
3947 head revision, and the current branch contains exactly one other
3944 head, the other head is merged with by default. Otherwise, an
3948 head, the other head is merged with by default. Otherwise, an
3945 explicit revision with which to merge with must be provided.
3949 explicit revision with which to merge with must be provided.
3946
3950
3947 :hg:`resolve` must be used to resolve unresolved files.
3951 :hg:`resolve` must be used to resolve unresolved files.
3948
3952
3949 To undo an uncommitted merge, use :hg:`update --clean .` which
3953 To undo an uncommitted merge, use :hg:`update --clean .` which
3950 will check out a clean copy of the original merge parent, losing
3954 will check out a clean copy of the original merge parent, losing
3951 all changes.
3955 all changes.
3952
3956
3953 Returns 0 on success, 1 if there are unresolved files.
3957 Returns 0 on success, 1 if there are unresolved files.
3954 """
3958 """
3955
3959
3956 if opts.get('rev') and node:
3960 if opts.get('rev') and node:
3957 raise util.Abort(_("please specify just one revision"))
3961 raise util.Abort(_("please specify just one revision"))
3958 if not node:
3962 if not node:
3959 node = opts.get('rev')
3963 node = opts.get('rev')
3960
3964
3961 if not node:
3965 if not node:
3962 branch = repo[None].branch()
3966 branch = repo[None].branch()
3963 bheads = repo.branchheads(branch)
3967 bheads = repo.branchheads(branch)
3964 if len(bheads) > 2:
3968 if len(bheads) > 2:
3965 raise util.Abort(_("branch '%s' has %d heads - "
3969 raise util.Abort(_("branch '%s' has %d heads - "
3966 "please merge with an explicit rev")
3970 "please merge with an explicit rev")
3967 % (branch, len(bheads)),
3971 % (branch, len(bheads)),
3968 hint=_("run 'hg heads .' to see heads"))
3972 hint=_("run 'hg heads .' to see heads"))
3969
3973
3970 parent = repo.dirstate.p1()
3974 parent = repo.dirstate.p1()
3971 if len(bheads) == 1:
3975 if len(bheads) == 1:
3972 if len(repo.heads()) > 1:
3976 if len(repo.heads()) > 1:
3973 raise util.Abort(_("branch '%s' has one head - "
3977 raise util.Abort(_("branch '%s' has one head - "
3974 "please merge with an explicit rev")
3978 "please merge with an explicit rev")
3975 % branch,
3979 % branch,
3976 hint=_("run 'hg heads' to see all heads"))
3980 hint=_("run 'hg heads' to see all heads"))
3977 msg = _('there is nothing to merge')
3981 msg = _('there is nothing to merge')
3978 if parent != repo.lookup(repo[None].branch()):
3982 if parent != repo.lookup(repo[None].branch()):
3979 msg = _('%s - use "hg update" instead') % msg
3983 msg = _('%s - use "hg update" instead') % msg
3980 raise util.Abort(msg)
3984 raise util.Abort(msg)
3981
3985
3982 if parent not in bheads:
3986 if parent not in bheads:
3983 raise util.Abort(_('working directory not at a head revision'),
3987 raise util.Abort(_('working directory not at a head revision'),
3984 hint=_("use 'hg update' or merge with an "
3988 hint=_("use 'hg update' or merge with an "
3985 "explicit revision"))
3989 "explicit revision"))
3986 node = parent == bheads[0] and bheads[-1] or bheads[0]
3990 node = parent == bheads[0] and bheads[-1] or bheads[0]
3987 else:
3991 else:
3988 node = scmutil.revsingle(repo, node).node()
3992 node = scmutil.revsingle(repo, node).node()
3989
3993
3990 if opts.get('preview'):
3994 if opts.get('preview'):
3991 # find nodes that are ancestors of p2 but not of p1
3995 # find nodes that are ancestors of p2 but not of p1
3992 p1 = repo.lookup('.')
3996 p1 = repo.lookup('.')
3993 p2 = repo.lookup(node)
3997 p2 = repo.lookup(node)
3994 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3998 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3995
3999
3996 displayer = cmdutil.show_changeset(ui, repo, opts)
4000 displayer = cmdutil.show_changeset(ui, repo, opts)
3997 for node in nodes:
4001 for node in nodes:
3998 displayer.show(repo[node])
4002 displayer.show(repo[node])
3999 displayer.close()
4003 displayer.close()
4000 return 0
4004 return 0
4001
4005
4002 try:
4006 try:
4003 # ui.forcemerge is an internal variable, do not document
4007 # ui.forcemerge is an internal variable, do not document
4004 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4008 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4005 return hg.merge(repo, node, force=opts.get('force'))
4009 return hg.merge(repo, node, force=opts.get('force'))
4006 finally:
4010 finally:
4007 ui.setconfig('ui', 'forcemerge', '')
4011 ui.setconfig('ui', 'forcemerge', '')
4008
4012
4009 @command('outgoing|out',
4013 @command('outgoing|out',
4010 [('f', 'force', None, _('run even when the destination is unrelated')),
4014 [('f', 'force', None, _('run even when the destination is unrelated')),
4011 ('r', 'rev', [],
4015 ('r', 'rev', [],
4012 _('a changeset intended to be included in the destination'), _('REV')),
4016 _('a changeset intended to be included in the destination'), _('REV')),
4013 ('n', 'newest-first', None, _('show newest record first')),
4017 ('n', 'newest-first', None, _('show newest record first')),
4014 ('B', 'bookmarks', False, _('compare bookmarks')),
4018 ('B', 'bookmarks', False, _('compare bookmarks')),
4015 ('b', 'branch', [], _('a specific branch you would like to push'),
4019 ('b', 'branch', [], _('a specific branch you would like to push'),
4016 _('BRANCH')),
4020 _('BRANCH')),
4017 ] + logopts + remoteopts + subrepoopts,
4021 ] + logopts + remoteopts + subrepoopts,
4018 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4022 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4019 def outgoing(ui, repo, dest=None, **opts):
4023 def outgoing(ui, repo, dest=None, **opts):
4020 """show changesets not found in the destination
4024 """show changesets not found in the destination
4021
4025
4022 Show changesets not found in the specified destination repository
4026 Show changesets not found in the specified destination repository
4023 or the default push location. These are the changesets that would
4027 or the default push location. These are the changesets that would
4024 be pushed if a push was requested.
4028 be pushed if a push was requested.
4025
4029
4026 See pull for details of valid destination formats.
4030 See pull for details of valid destination formats.
4027
4031
4028 Returns 0 if there are outgoing changes, 1 otherwise.
4032 Returns 0 if there are outgoing changes, 1 otherwise.
4029 """
4033 """
4030
4034
4031 if opts.get('bookmarks'):
4035 if opts.get('bookmarks'):
4032 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4036 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4033 dest, branches = hg.parseurl(dest, opts.get('branch'))
4037 dest, branches = hg.parseurl(dest, opts.get('branch'))
4034 other = hg.peer(repo, opts, dest)
4038 other = hg.peer(repo, opts, dest)
4035 if 'bookmarks' not in other.listkeys('namespaces'):
4039 if 'bookmarks' not in other.listkeys('namespaces'):
4036 ui.warn(_("remote doesn't support bookmarks\n"))
4040 ui.warn(_("remote doesn't support bookmarks\n"))
4037 return 0
4041 return 0
4038 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4042 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4039 return bookmarks.diff(ui, other, repo)
4043 return bookmarks.diff(ui, other, repo)
4040
4044
4041 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4045 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4042 try:
4046 try:
4043 return hg.outgoing(ui, repo, dest, opts)
4047 return hg.outgoing(ui, repo, dest, opts)
4044 finally:
4048 finally:
4045 del repo._subtoppath
4049 del repo._subtoppath
4046
4050
4047 @command('parents',
4051 @command('parents',
4048 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4052 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4049 ] + templateopts,
4053 ] + templateopts,
4050 _('[-r REV] [FILE]'))
4054 _('[-r REV] [FILE]'))
4051 def parents(ui, repo, file_=None, **opts):
4055 def parents(ui, repo, file_=None, **opts):
4052 """show the parents of the working directory or revision
4056 """show the parents of the working directory or revision
4053
4057
4054 Print the working directory's parent revisions. If a revision is
4058 Print the working directory's parent revisions. If a revision is
4055 given via -r/--rev, the parent of that revision will be printed.
4059 given via -r/--rev, the parent of that revision will be printed.
4056 If a file argument is given, the revision in which the file was
4060 If a file argument is given, the revision in which the file was
4057 last changed (before the working directory revision or the
4061 last changed (before the working directory revision or the
4058 argument to --rev if given) is printed.
4062 argument to --rev if given) is printed.
4059
4063
4060 Returns 0 on success.
4064 Returns 0 on success.
4061 """
4065 """
4062
4066
4063 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4067 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4064
4068
4065 if file_:
4069 if file_:
4066 m = scmutil.match(ctx, (file_,), opts)
4070 m = scmutil.match(ctx, (file_,), opts)
4067 if m.anypats() or len(m.files()) != 1:
4071 if m.anypats() or len(m.files()) != 1:
4068 raise util.Abort(_('can only specify an explicit filename'))
4072 raise util.Abort(_('can only specify an explicit filename'))
4069 file_ = m.files()[0]
4073 file_ = m.files()[0]
4070 filenodes = []
4074 filenodes = []
4071 for cp in ctx.parents():
4075 for cp in ctx.parents():
4072 if not cp:
4076 if not cp:
4073 continue
4077 continue
4074 try:
4078 try:
4075 filenodes.append(cp.filenode(file_))
4079 filenodes.append(cp.filenode(file_))
4076 except error.LookupError:
4080 except error.LookupError:
4077 pass
4081 pass
4078 if not filenodes:
4082 if not filenodes:
4079 raise util.Abort(_("'%s' not found in manifest!") % file_)
4083 raise util.Abort(_("'%s' not found in manifest!") % file_)
4080 fl = repo.file(file_)
4084 fl = repo.file(file_)
4081 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
4085 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
4082 else:
4086 else:
4083 p = [cp.node() for cp in ctx.parents()]
4087 p = [cp.node() for cp in ctx.parents()]
4084
4088
4085 displayer = cmdutil.show_changeset(ui, repo, opts)
4089 displayer = cmdutil.show_changeset(ui, repo, opts)
4086 for n in p:
4090 for n in p:
4087 if n != nullid:
4091 if n != nullid:
4088 displayer.show(repo[n])
4092 displayer.show(repo[n])
4089 displayer.close()
4093 displayer.close()
4090
4094
4091 @command('paths', [], _('[NAME]'))
4095 @command('paths', [], _('[NAME]'))
4092 def paths(ui, repo, search=None):
4096 def paths(ui, repo, search=None):
4093 """show aliases for remote repositories
4097 """show aliases for remote repositories
4094
4098
4095 Show definition of symbolic path name NAME. If no name is given,
4099 Show definition of symbolic path name NAME. If no name is given,
4096 show definition of all available names.
4100 show definition of all available names.
4097
4101
4098 Option -q/--quiet suppresses all output when searching for NAME
4102 Option -q/--quiet suppresses all output when searching for NAME
4099 and shows only the path names when listing all definitions.
4103 and shows only the path names when listing all definitions.
4100
4104
4101 Path names are defined in the [paths] section of your
4105 Path names are defined in the [paths] section of your
4102 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4106 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4103 repository, ``.hg/hgrc`` is used, too.
4107 repository, ``.hg/hgrc`` is used, too.
4104
4108
4105 The path names ``default`` and ``default-push`` have a special
4109 The path names ``default`` and ``default-push`` have a special
4106 meaning. When performing a push or pull operation, they are used
4110 meaning. When performing a push or pull operation, they are used
4107 as fallbacks if no location is specified on the command-line.
4111 as fallbacks if no location is specified on the command-line.
4108 When ``default-push`` is set, it will be used for push and
4112 When ``default-push`` is set, it will be used for push and
4109 ``default`` will be used for pull; otherwise ``default`` is used
4113 ``default`` will be used for pull; otherwise ``default`` is used
4110 as the fallback for both. When cloning a repository, the clone
4114 as the fallback for both. When cloning a repository, the clone
4111 source is written as ``default`` in ``.hg/hgrc``. Note that
4115 source is written as ``default`` in ``.hg/hgrc``. Note that
4112 ``default`` and ``default-push`` apply to all inbound (e.g.
4116 ``default`` and ``default-push`` apply to all inbound (e.g.
4113 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4117 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4114 :hg:`bundle`) operations.
4118 :hg:`bundle`) operations.
4115
4119
4116 See :hg:`help urls` for more information.
4120 See :hg:`help urls` for more information.
4117
4121
4118 Returns 0 on success.
4122 Returns 0 on success.
4119 """
4123 """
4120 if search:
4124 if search:
4121 for name, path in ui.configitems("paths"):
4125 for name, path in ui.configitems("paths"):
4122 if name == search:
4126 if name == search:
4123 ui.status("%s\n" % util.hidepassword(path))
4127 ui.status("%s\n" % util.hidepassword(path))
4124 return
4128 return
4125 if not ui.quiet:
4129 if not ui.quiet:
4126 ui.warn(_("not found!\n"))
4130 ui.warn(_("not found!\n"))
4127 return 1
4131 return 1
4128 else:
4132 else:
4129 for name, path in ui.configitems("paths"):
4133 for name, path in ui.configitems("paths"):
4130 if ui.quiet:
4134 if ui.quiet:
4131 ui.write("%s\n" % name)
4135 ui.write("%s\n" % name)
4132 else:
4136 else:
4133 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4137 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4134
4138
4135 def postincoming(ui, repo, modheads, optupdate, checkout):
4139 def postincoming(ui, repo, modheads, optupdate, checkout):
4136 if modheads == 0:
4140 if modheads == 0:
4137 return
4141 return
4138 if optupdate:
4142 if optupdate:
4139 try:
4143 try:
4140 return hg.update(repo, checkout)
4144 return hg.update(repo, checkout)
4141 except util.Abort, inst:
4145 except util.Abort, inst:
4142 ui.warn(_("not updating: %s\n" % str(inst)))
4146 ui.warn(_("not updating: %s\n" % str(inst)))
4143 return 0
4147 return 0
4144 if modheads > 1:
4148 if modheads > 1:
4145 currentbranchheads = len(repo.branchheads())
4149 currentbranchheads = len(repo.branchheads())
4146 if currentbranchheads == modheads:
4150 if currentbranchheads == modheads:
4147 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4151 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4148 elif currentbranchheads > 1:
4152 elif currentbranchheads > 1:
4149 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to merge)\n"))
4153 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to merge)\n"))
4150 else:
4154 else:
4151 ui.status(_("(run 'hg heads' to see heads)\n"))
4155 ui.status(_("(run 'hg heads' to see heads)\n"))
4152 else:
4156 else:
4153 ui.status(_("(run 'hg update' to get a working copy)\n"))
4157 ui.status(_("(run 'hg update' to get a working copy)\n"))
4154
4158
4155 @command('^pull',
4159 @command('^pull',
4156 [('u', 'update', None,
4160 [('u', 'update', None,
4157 _('update to new branch head if changesets were pulled')),
4161 _('update to new branch head if changesets were pulled')),
4158 ('f', 'force', None, _('run even when remote repository is unrelated')),
4162 ('f', 'force', None, _('run even when remote repository is unrelated')),
4159 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4163 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4160 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4164 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4161 ('b', 'branch', [], _('a specific branch you would like to pull'),
4165 ('b', 'branch', [], _('a specific branch you would like to pull'),
4162 _('BRANCH')),
4166 _('BRANCH')),
4163 ] + remoteopts,
4167 ] + remoteopts,
4164 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4168 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4165 def pull(ui, repo, source="default", **opts):
4169 def pull(ui, repo, source="default", **opts):
4166 """pull changes from the specified source
4170 """pull changes from the specified source
4167
4171
4168 Pull changes from a remote repository to a local one.
4172 Pull changes from a remote repository to a local one.
4169
4173
4170 This finds all changes from the repository at the specified path
4174 This finds all changes from the repository at the specified path
4171 or URL and adds them to a local repository (the current one unless
4175 or URL and adds them to a local repository (the current one unless
4172 -R is specified). By default, this does not update the copy of the
4176 -R is specified). By default, this does not update the copy of the
4173 project in the working directory.
4177 project in the working directory.
4174
4178
4175 Use :hg:`incoming` if you want to see what would have been added
4179 Use :hg:`incoming` if you want to see what would have been added
4176 by a pull at the time you issued this command. If you then decide
4180 by a pull at the time you issued this command. If you then decide
4177 to add those changes to the repository, you should use :hg:`pull
4181 to add those changes to the repository, you should use :hg:`pull
4178 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4182 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4179
4183
4180 If SOURCE is omitted, the 'default' path will be used.
4184 If SOURCE is omitted, the 'default' path will be used.
4181 See :hg:`help urls` for more information.
4185 See :hg:`help urls` for more information.
4182
4186
4183 Returns 0 on success, 1 if an update had unresolved files.
4187 Returns 0 on success, 1 if an update had unresolved files.
4184 """
4188 """
4185 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4189 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4186 other = hg.peer(repo, opts, source)
4190 other = hg.peer(repo, opts, source)
4187 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4191 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4188 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4192 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4189
4193
4190 if opts.get('bookmark'):
4194 if opts.get('bookmark'):
4191 if not revs:
4195 if not revs:
4192 revs = []
4196 revs = []
4193 rb = other.listkeys('bookmarks')
4197 rb = other.listkeys('bookmarks')
4194 for b in opts['bookmark']:
4198 for b in opts['bookmark']:
4195 if b not in rb:
4199 if b not in rb:
4196 raise util.Abort(_('remote bookmark %s not found!') % b)
4200 raise util.Abort(_('remote bookmark %s not found!') % b)
4197 revs.append(rb[b])
4201 revs.append(rb[b])
4198
4202
4199 if revs:
4203 if revs:
4200 try:
4204 try:
4201 revs = [other.lookup(rev) for rev in revs]
4205 revs = [other.lookup(rev) for rev in revs]
4202 except error.CapabilityError:
4206 except error.CapabilityError:
4203 err = _("other repository doesn't support revision lookup, "
4207 err = _("other repository doesn't support revision lookup, "
4204 "so a rev cannot be specified.")
4208 "so a rev cannot be specified.")
4205 raise util.Abort(err)
4209 raise util.Abort(err)
4206
4210
4207 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4211 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4208 bookmarks.updatefromremote(ui, repo, other)
4212 bookmarks.updatefromremote(ui, repo, other)
4209 if checkout:
4213 if checkout:
4210 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4214 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4211 repo._subtoppath = source
4215 repo._subtoppath = source
4212 try:
4216 try:
4213 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4217 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4214
4218
4215 finally:
4219 finally:
4216 del repo._subtoppath
4220 del repo._subtoppath
4217
4221
4218 # update specified bookmarks
4222 # update specified bookmarks
4219 if opts.get('bookmark'):
4223 if opts.get('bookmark'):
4220 for b in opts['bookmark']:
4224 for b in opts['bookmark']:
4221 # explicit pull overrides local bookmark if any
4225 # explicit pull overrides local bookmark if any
4222 ui.status(_("importing bookmark %s\n") % b)
4226 ui.status(_("importing bookmark %s\n") % b)
4223 repo._bookmarks[b] = repo[rb[b]].node()
4227 repo._bookmarks[b] = repo[rb[b]].node()
4224 bookmarks.write(repo)
4228 bookmarks.write(repo)
4225
4229
4226 return ret
4230 return ret
4227
4231
4228 @command('^push',
4232 @command('^push',
4229 [('f', 'force', None, _('force push')),
4233 [('f', 'force', None, _('force push')),
4230 ('r', 'rev', [],
4234 ('r', 'rev', [],
4231 _('a changeset intended to be included in the destination'),
4235 _('a changeset intended to be included in the destination'),
4232 _('REV')),
4236 _('REV')),
4233 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4237 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4234 ('b', 'branch', [],
4238 ('b', 'branch', [],
4235 _('a specific branch you would like to push'), _('BRANCH')),
4239 _('a specific branch you would like to push'), _('BRANCH')),
4236 ('', 'new-branch', False, _('allow pushing a new branch')),
4240 ('', 'new-branch', False, _('allow pushing a new branch')),
4237 ] + remoteopts,
4241 ] + remoteopts,
4238 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4242 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4239 def push(ui, repo, dest=None, **opts):
4243 def push(ui, repo, dest=None, **opts):
4240 """push changes to the specified destination
4244 """push changes to the specified destination
4241
4245
4242 Push changesets from the local repository to the specified
4246 Push changesets from the local repository to the specified
4243 destination.
4247 destination.
4244
4248
4245 This operation is symmetrical to pull: it is identical to a pull
4249 This operation is symmetrical to pull: it is identical to a pull
4246 in the destination repository from the current one.
4250 in the destination repository from the current one.
4247
4251
4248 By default, push will not allow creation of new heads at the
4252 By default, push will not allow creation of new heads at the
4249 destination, since multiple heads would make it unclear which head
4253 destination, since multiple heads would make it unclear which head
4250 to use. In this situation, it is recommended to pull and merge
4254 to use. In this situation, it is recommended to pull and merge
4251 before pushing.
4255 before pushing.
4252
4256
4253 Use --new-branch if you want to allow push to create a new named
4257 Use --new-branch if you want to allow push to create a new named
4254 branch that is not present at the destination. This allows you to
4258 branch that is not present at the destination. This allows you to
4255 only create a new branch without forcing other changes.
4259 only create a new branch without forcing other changes.
4256
4260
4257 Use -f/--force to override the default behavior and push all
4261 Use -f/--force to override the default behavior and push all
4258 changesets on all branches.
4262 changesets on all branches.
4259
4263
4260 If -r/--rev is used, the specified revision and all its ancestors
4264 If -r/--rev is used, the specified revision and all its ancestors
4261 will be pushed to the remote repository.
4265 will be pushed to the remote repository.
4262
4266
4263 Please see :hg:`help urls` for important details about ``ssh://``
4267 Please see :hg:`help urls` for important details about ``ssh://``
4264 URLs. If DESTINATION is omitted, a default path will be used.
4268 URLs. If DESTINATION is omitted, a default path will be used.
4265
4269
4266 Returns 0 if push was successful, 1 if nothing to push.
4270 Returns 0 if push was successful, 1 if nothing to push.
4267 """
4271 """
4268
4272
4269 if opts.get('bookmark'):
4273 if opts.get('bookmark'):
4270 for b in opts['bookmark']:
4274 for b in opts['bookmark']:
4271 # translate -B options to -r so changesets get pushed
4275 # translate -B options to -r so changesets get pushed
4272 if b in repo._bookmarks:
4276 if b in repo._bookmarks:
4273 opts.setdefault('rev', []).append(b)
4277 opts.setdefault('rev', []).append(b)
4274 else:
4278 else:
4275 # if we try to push a deleted bookmark, translate it to null
4279 # if we try to push a deleted bookmark, translate it to null
4276 # this lets simultaneous -r, -b options continue working
4280 # this lets simultaneous -r, -b options continue working
4277 opts.setdefault('rev', []).append("null")
4281 opts.setdefault('rev', []).append("null")
4278
4282
4279 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4283 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4280 dest, branches = hg.parseurl(dest, opts.get('branch'))
4284 dest, branches = hg.parseurl(dest, opts.get('branch'))
4281 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4285 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4282 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4286 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4283 other = hg.peer(repo, opts, dest)
4287 other = hg.peer(repo, opts, dest)
4284 if revs:
4288 if revs:
4285 revs = [repo.lookup(rev) for rev in revs]
4289 revs = [repo.lookup(rev) for rev in revs]
4286
4290
4287 repo._subtoppath = dest
4291 repo._subtoppath = dest
4288 try:
4292 try:
4289 # push subrepos depth-first for coherent ordering
4293 # push subrepos depth-first for coherent ordering
4290 c = repo['']
4294 c = repo['']
4291 subs = c.substate # only repos that are committed
4295 subs = c.substate # only repos that are committed
4292 for s in sorted(subs):
4296 for s in sorted(subs):
4293 if not c.sub(s).push(opts.get('force')):
4297 if not c.sub(s).push(opts.get('force')):
4294 return False
4298 return False
4295 finally:
4299 finally:
4296 del repo._subtoppath
4300 del repo._subtoppath
4297 result = repo.push(other, opts.get('force'), revs=revs,
4301 result = repo.push(other, opts.get('force'), revs=revs,
4298 newbranch=opts.get('new_branch'))
4302 newbranch=opts.get('new_branch'))
4299
4303
4300 result = (result == 0)
4304 result = (result == 0)
4301
4305
4302 if opts.get('bookmark'):
4306 if opts.get('bookmark'):
4303 rb = other.listkeys('bookmarks')
4307 rb = other.listkeys('bookmarks')
4304 for b in opts['bookmark']:
4308 for b in opts['bookmark']:
4305 # explicit push overrides remote bookmark if any
4309 # explicit push overrides remote bookmark if any
4306 if b in repo._bookmarks:
4310 if b in repo._bookmarks:
4307 ui.status(_("exporting bookmark %s\n") % b)
4311 ui.status(_("exporting bookmark %s\n") % b)
4308 new = repo[b].hex()
4312 new = repo[b].hex()
4309 elif b in rb:
4313 elif b in rb:
4310 ui.status(_("deleting remote bookmark %s\n") % b)
4314 ui.status(_("deleting remote bookmark %s\n") % b)
4311 new = '' # delete
4315 new = '' # delete
4312 else:
4316 else:
4313 ui.warn(_('bookmark %s does not exist on the local '
4317 ui.warn(_('bookmark %s does not exist on the local '
4314 'or remote repository!\n') % b)
4318 'or remote repository!\n') % b)
4315 return 2
4319 return 2
4316 old = rb.get(b, '')
4320 old = rb.get(b, '')
4317 r = other.pushkey('bookmarks', b, old, new)
4321 r = other.pushkey('bookmarks', b, old, new)
4318 if not r:
4322 if not r:
4319 ui.warn(_('updating bookmark %s failed!\n') % b)
4323 ui.warn(_('updating bookmark %s failed!\n') % b)
4320 if not result:
4324 if not result:
4321 result = 2
4325 result = 2
4322
4326
4323 return result
4327 return result
4324
4328
4325 @command('recover', [])
4329 @command('recover', [])
4326 def recover(ui, repo):
4330 def recover(ui, repo):
4327 """roll back an interrupted transaction
4331 """roll back an interrupted transaction
4328
4332
4329 Recover from an interrupted commit or pull.
4333 Recover from an interrupted commit or pull.
4330
4334
4331 This command tries to fix the repository status after an
4335 This command tries to fix the repository status after an
4332 interrupted operation. It should only be necessary when Mercurial
4336 interrupted operation. It should only be necessary when Mercurial
4333 suggests it.
4337 suggests it.
4334
4338
4335 Returns 0 if successful, 1 if nothing to recover or verify fails.
4339 Returns 0 if successful, 1 if nothing to recover or verify fails.
4336 """
4340 """
4337 if repo.recover():
4341 if repo.recover():
4338 return hg.verify(repo)
4342 return hg.verify(repo)
4339 return 1
4343 return 1
4340
4344
4341 @command('^remove|rm',
4345 @command('^remove|rm',
4342 [('A', 'after', None, _('record delete for missing files')),
4346 [('A', 'after', None, _('record delete for missing files')),
4343 ('f', 'force', None,
4347 ('f', 'force', None,
4344 _('remove (and delete) file even if added or modified')),
4348 _('remove (and delete) file even if added or modified')),
4345 ] + walkopts,
4349 ] + walkopts,
4346 _('[OPTION]... FILE...'))
4350 _('[OPTION]... FILE...'))
4347 def remove(ui, repo, *pats, **opts):
4351 def remove(ui, repo, *pats, **opts):
4348 """remove the specified files on the next commit
4352 """remove the specified files on the next commit
4349
4353
4350 Schedule the indicated files for removal from the current branch.
4354 Schedule the indicated files for removal from the current branch.
4351
4355
4352 This command schedules the files to be removed at the next commit.
4356 This command schedules the files to be removed at the next commit.
4353 To undo a remove before that, see :hg:`revert`. To undo added
4357 To undo a remove before that, see :hg:`revert`. To undo added
4354 files, see :hg:`forget`.
4358 files, see :hg:`forget`.
4355
4359
4356 .. container:: verbose
4360 .. container:: verbose
4357
4361
4358 -A/--after can be used to remove only files that have already
4362 -A/--after can be used to remove only files that have already
4359 been deleted, -f/--force can be used to force deletion, and -Af
4363 been deleted, -f/--force can be used to force deletion, and -Af
4360 can be used to remove files from the next revision without
4364 can be used to remove files from the next revision without
4361 deleting them from the working directory.
4365 deleting them from the working directory.
4362
4366
4363 The following table details the behavior of remove for different
4367 The following table details the behavior of remove for different
4364 file states (columns) and option combinations (rows). The file
4368 file states (columns) and option combinations (rows). The file
4365 states are Added [A], Clean [C], Modified [M] and Missing [!]
4369 states are Added [A], Clean [C], Modified [M] and Missing [!]
4366 (as reported by :hg:`status`). The actions are Warn, Remove
4370 (as reported by :hg:`status`). The actions are Warn, Remove
4367 (from branch) and Delete (from disk):
4371 (from branch) and Delete (from disk):
4368
4372
4369 ======= == == == ==
4373 ======= == == == ==
4370 A C M !
4374 A C M !
4371 ======= == == == ==
4375 ======= == == == ==
4372 none W RD W R
4376 none W RD W R
4373 -f R RD RD R
4377 -f R RD RD R
4374 -A W W W R
4378 -A W W W R
4375 -Af R R R R
4379 -Af R R R R
4376 ======= == == == ==
4380 ======= == == == ==
4377
4381
4378 Note that remove never deletes files in Added [A] state from the
4382 Note that remove never deletes files in Added [A] state from the
4379 working directory, not even if option --force is specified.
4383 working directory, not even if option --force is specified.
4380
4384
4381 Returns 0 on success, 1 if any warnings encountered.
4385 Returns 0 on success, 1 if any warnings encountered.
4382 """
4386 """
4383
4387
4384 ret = 0
4388 ret = 0
4385 after, force = opts.get('after'), opts.get('force')
4389 after, force = opts.get('after'), opts.get('force')
4386 if not pats and not after:
4390 if not pats and not after:
4387 raise util.Abort(_('no files specified'))
4391 raise util.Abort(_('no files specified'))
4388
4392
4389 m = scmutil.match(repo[None], pats, opts)
4393 m = scmutil.match(repo[None], pats, opts)
4390 s = repo.status(match=m, clean=True)
4394 s = repo.status(match=m, clean=True)
4391 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4395 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4392
4396
4393 for f in m.files():
4397 for f in m.files():
4394 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
4398 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
4395 if os.path.exists(m.rel(f)):
4399 if os.path.exists(m.rel(f)):
4396 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4400 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4397 ret = 1
4401 ret = 1
4398
4402
4399 if force:
4403 if force:
4400 list = modified + deleted + clean + added
4404 list = modified + deleted + clean + added
4401 elif after:
4405 elif after:
4402 list = deleted
4406 list = deleted
4403 for f in modified + added + clean:
4407 for f in modified + added + clean:
4404 ui.warn(_('not removing %s: file still exists (use -f'
4408 ui.warn(_('not removing %s: file still exists (use -f'
4405 ' to force removal)\n') % m.rel(f))
4409 ' to force removal)\n') % m.rel(f))
4406 ret = 1
4410 ret = 1
4407 else:
4411 else:
4408 list = deleted + clean
4412 list = deleted + clean
4409 for f in modified:
4413 for f in modified:
4410 ui.warn(_('not removing %s: file is modified (use -f'
4414 ui.warn(_('not removing %s: file is modified (use -f'
4411 ' to force removal)\n') % m.rel(f))
4415 ' to force removal)\n') % m.rel(f))
4412 ret = 1
4416 ret = 1
4413 for f in added:
4417 for f in added:
4414 ui.warn(_('not removing %s: file has been marked for add'
4418 ui.warn(_('not removing %s: file has been marked for add'
4415 ' (use forget to undo)\n') % m.rel(f))
4419 ' (use forget to undo)\n') % m.rel(f))
4416 ret = 1
4420 ret = 1
4417
4421
4418 for f in sorted(list):
4422 for f in sorted(list):
4419 if ui.verbose or not m.exact(f):
4423 if ui.verbose or not m.exact(f):
4420 ui.status(_('removing %s\n') % m.rel(f))
4424 ui.status(_('removing %s\n') % m.rel(f))
4421
4425
4422 wlock = repo.wlock()
4426 wlock = repo.wlock()
4423 try:
4427 try:
4424 if not after:
4428 if not after:
4425 for f in list:
4429 for f in list:
4426 if f in added:
4430 if f in added:
4427 continue # we never unlink added files on remove
4431 continue # we never unlink added files on remove
4428 try:
4432 try:
4429 util.unlinkpath(repo.wjoin(f))
4433 util.unlinkpath(repo.wjoin(f))
4430 except OSError, inst:
4434 except OSError, inst:
4431 if inst.errno != errno.ENOENT:
4435 if inst.errno != errno.ENOENT:
4432 raise
4436 raise
4433 repo[None].forget(list)
4437 repo[None].forget(list)
4434 finally:
4438 finally:
4435 wlock.release()
4439 wlock.release()
4436
4440
4437 return ret
4441 return ret
4438
4442
4439 @command('rename|move|mv',
4443 @command('rename|move|mv',
4440 [('A', 'after', None, _('record a rename that has already occurred')),
4444 [('A', 'after', None, _('record a rename that has already occurred')),
4441 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4445 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4442 ] + walkopts + dryrunopts,
4446 ] + walkopts + dryrunopts,
4443 _('[OPTION]... SOURCE... DEST'))
4447 _('[OPTION]... SOURCE... DEST'))
4444 def rename(ui, repo, *pats, **opts):
4448 def rename(ui, repo, *pats, **opts):
4445 """rename files; equivalent of copy + remove
4449 """rename files; equivalent of copy + remove
4446
4450
4447 Mark dest as copies of sources; mark sources for deletion. If dest
4451 Mark dest as copies of sources; mark sources for deletion. If dest
4448 is a directory, copies are put in that directory. If dest is a
4452 is a directory, copies are put in that directory. If dest is a
4449 file, there can only be one source.
4453 file, there can only be one source.
4450
4454
4451 By default, this command copies the contents of files as they
4455 By default, this command copies the contents of files as they
4452 exist in the working directory. If invoked with -A/--after, the
4456 exist in the working directory. If invoked with -A/--after, the
4453 operation is recorded, but no copying is performed.
4457 operation is recorded, but no copying is performed.
4454
4458
4455 This command takes effect at the next commit. To undo a rename
4459 This command takes effect at the next commit. To undo a rename
4456 before that, see :hg:`revert`.
4460 before that, see :hg:`revert`.
4457
4461
4458 Returns 0 on success, 1 if errors are encountered.
4462 Returns 0 on success, 1 if errors are encountered.
4459 """
4463 """
4460 wlock = repo.wlock(False)
4464 wlock = repo.wlock(False)
4461 try:
4465 try:
4462 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4466 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4463 finally:
4467 finally:
4464 wlock.release()
4468 wlock.release()
4465
4469
4466 @command('resolve',
4470 @command('resolve',
4467 [('a', 'all', None, _('select all unresolved files')),
4471 [('a', 'all', None, _('select all unresolved files')),
4468 ('l', 'list', None, _('list state of files needing merge')),
4472 ('l', 'list', None, _('list state of files needing merge')),
4469 ('m', 'mark', None, _('mark files as resolved')),
4473 ('m', 'mark', None, _('mark files as resolved')),
4470 ('u', 'unmark', None, _('mark files as unresolved')),
4474 ('u', 'unmark', None, _('mark files as unresolved')),
4471 ('n', 'no-status', None, _('hide status prefix'))]
4475 ('n', 'no-status', None, _('hide status prefix'))]
4472 + mergetoolopts + walkopts,
4476 + mergetoolopts + walkopts,
4473 _('[OPTION]... [FILE]...'))
4477 _('[OPTION]... [FILE]...'))
4474 def resolve(ui, repo, *pats, **opts):
4478 def resolve(ui, repo, *pats, **opts):
4475 """redo merges or set/view the merge status of files
4479 """redo merges or set/view the merge status of files
4476
4480
4477 Merges with unresolved conflicts are often the result of
4481 Merges with unresolved conflicts are often the result of
4478 non-interactive merging using the ``internal:merge`` configuration
4482 non-interactive merging using the ``internal:merge`` configuration
4479 setting, or a command-line merge tool like ``diff3``. The resolve
4483 setting, or a command-line merge tool like ``diff3``. The resolve
4480 command is used to manage the files involved in a merge, after
4484 command is used to manage the files involved in a merge, after
4481 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4485 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4482 working directory must have two parents).
4486 working directory must have two parents).
4483
4487
4484 The resolve command can be used in the following ways:
4488 The resolve command can be used in the following ways:
4485
4489
4486 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4490 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4487 files, discarding any previous merge attempts. Re-merging is not
4491 files, discarding any previous merge attempts. Re-merging is not
4488 performed for files already marked as resolved. Use ``--all/-a``
4492 performed for files already marked as resolved. Use ``--all/-a``
4489 to select all unresolved files. ``--tool`` can be used to specify
4493 to select all unresolved files. ``--tool`` can be used to specify
4490 the merge tool used for the given files. It overrides the HGMERGE
4494 the merge tool used for the given files. It overrides the HGMERGE
4491 environment variable and your configuration files. Previous file
4495 environment variable and your configuration files. Previous file
4492 contents are saved with a ``.orig`` suffix.
4496 contents are saved with a ``.orig`` suffix.
4493
4497
4494 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4498 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4495 (e.g. after having manually fixed-up the files). The default is
4499 (e.g. after having manually fixed-up the files). The default is
4496 to mark all unresolved files.
4500 to mark all unresolved files.
4497
4501
4498 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4502 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4499 default is to mark all resolved files.
4503 default is to mark all resolved files.
4500
4504
4501 - :hg:`resolve -l`: list files which had or still have conflicts.
4505 - :hg:`resolve -l`: list files which had or still have conflicts.
4502 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4506 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4503
4507
4504 Note that Mercurial will not let you commit files with unresolved
4508 Note that Mercurial will not let you commit files with unresolved
4505 merge conflicts. You must use :hg:`resolve -m ...` before you can
4509 merge conflicts. You must use :hg:`resolve -m ...` before you can
4506 commit after a conflicting merge.
4510 commit after a conflicting merge.
4507
4511
4508 Returns 0 on success, 1 if any files fail a resolve attempt.
4512 Returns 0 on success, 1 if any files fail a resolve attempt.
4509 """
4513 """
4510
4514
4511 all, mark, unmark, show, nostatus = \
4515 all, mark, unmark, show, nostatus = \
4512 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4516 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4513
4517
4514 if (show and (mark or unmark)) or (mark and unmark):
4518 if (show and (mark or unmark)) or (mark and unmark):
4515 raise util.Abort(_("too many options specified"))
4519 raise util.Abort(_("too many options specified"))
4516 if pats and all:
4520 if pats and all:
4517 raise util.Abort(_("can't specify --all and patterns"))
4521 raise util.Abort(_("can't specify --all and patterns"))
4518 if not (all or pats or show or mark or unmark):
4522 if not (all or pats or show or mark or unmark):
4519 raise util.Abort(_('no files or directories specified; '
4523 raise util.Abort(_('no files or directories specified; '
4520 'use --all to remerge all files'))
4524 'use --all to remerge all files'))
4521
4525
4522 ms = mergemod.mergestate(repo)
4526 ms = mergemod.mergestate(repo)
4523 m = scmutil.match(repo[None], pats, opts)
4527 m = scmutil.match(repo[None], pats, opts)
4524 ret = 0
4528 ret = 0
4525
4529
4526 for f in ms:
4530 for f in ms:
4527 if m(f):
4531 if m(f):
4528 if show:
4532 if show:
4529 if nostatus:
4533 if nostatus:
4530 ui.write("%s\n" % f)
4534 ui.write("%s\n" % f)
4531 else:
4535 else:
4532 ui.write("%s %s\n" % (ms[f].upper(), f),
4536 ui.write("%s %s\n" % (ms[f].upper(), f),
4533 label='resolve.' +
4537 label='resolve.' +
4534 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4538 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4535 elif mark:
4539 elif mark:
4536 ms.mark(f, "r")
4540 ms.mark(f, "r")
4537 elif unmark:
4541 elif unmark:
4538 ms.mark(f, "u")
4542 ms.mark(f, "u")
4539 else:
4543 else:
4540 wctx = repo[None]
4544 wctx = repo[None]
4541 mctx = wctx.parents()[-1]
4545 mctx = wctx.parents()[-1]
4542
4546
4543 # backup pre-resolve (merge uses .orig for its own purposes)
4547 # backup pre-resolve (merge uses .orig for its own purposes)
4544 a = repo.wjoin(f)
4548 a = repo.wjoin(f)
4545 util.copyfile(a, a + ".resolve")
4549 util.copyfile(a, a + ".resolve")
4546
4550
4547 try:
4551 try:
4548 # resolve file
4552 # resolve file
4549 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4553 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4550 if ms.resolve(f, wctx, mctx):
4554 if ms.resolve(f, wctx, mctx):
4551 ret = 1
4555 ret = 1
4552 finally:
4556 finally:
4553 ui.setconfig('ui', 'forcemerge', '')
4557 ui.setconfig('ui', 'forcemerge', '')
4554
4558
4555 # replace filemerge's .orig file with our resolve file
4559 # replace filemerge's .orig file with our resolve file
4556 util.rename(a + ".resolve", a + ".orig")
4560 util.rename(a + ".resolve", a + ".orig")
4557
4561
4558 ms.commit()
4562 ms.commit()
4559 return ret
4563 return ret
4560
4564
4561 @command('revert',
4565 @command('revert',
4562 [('a', 'all', None, _('revert all changes when no arguments given')),
4566 [('a', 'all', None, _('revert all changes when no arguments given')),
4563 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4567 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4564 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4568 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4565 ('C', 'no-backup', None, _('do not save backup copies of files')),
4569 ('C', 'no-backup', None, _('do not save backup copies of files')),
4566 ] + walkopts + dryrunopts,
4570 ] + walkopts + dryrunopts,
4567 _('[OPTION]... [-r REV] [NAME]...'))
4571 _('[OPTION]... [-r REV] [NAME]...'))
4568 def revert(ui, repo, *pats, **opts):
4572 def revert(ui, repo, *pats, **opts):
4569 """restore files to their checkout state
4573 """restore files to their checkout state
4570
4574
4571 .. note::
4575 .. note::
4572 To check out earlier revisions, you should use :hg:`update REV`.
4576 To check out earlier revisions, you should use :hg:`update REV`.
4573 To cancel a merge (and lose your changes), use :hg:`update --clean .`.
4577 To cancel a merge (and lose your changes), use :hg:`update --clean .`.
4574
4578
4575 With no revision specified, revert the specified files or directories
4579 With no revision specified, revert the specified files or directories
4576 to the contents they had in the parent of the working directory.
4580 to the contents they had in the parent of the working directory.
4577 This restores the contents of files to an unmodified
4581 This restores the contents of files to an unmodified
4578 state and unschedules adds, removes, copies, and renames. If the
4582 state and unschedules adds, removes, copies, and renames. If the
4579 working directory has two parents, you must explicitly specify a
4583 working directory has two parents, you must explicitly specify a
4580 revision.
4584 revision.
4581
4585
4582 Using the -r/--rev or -d/--date options, revert the given files or
4586 Using the -r/--rev or -d/--date options, revert the given files or
4583 directories to their states as of a specific revision. Because
4587 directories to their states as of a specific revision. Because
4584 revert does not change the working directory parents, this will
4588 revert does not change the working directory parents, this will
4585 cause these files to appear modified. This can be helpful to "back
4589 cause these files to appear modified. This can be helpful to "back
4586 out" some or all of an earlier change. See :hg:`backout` for a
4590 out" some or all of an earlier change. See :hg:`backout` for a
4587 related method.
4591 related method.
4588
4592
4589 Modified files are saved with a .orig suffix before reverting.
4593 Modified files are saved with a .orig suffix before reverting.
4590 To disable these backups, use --no-backup.
4594 To disable these backups, use --no-backup.
4591
4595
4592 See :hg:`help dates` for a list of formats valid for -d/--date.
4596 See :hg:`help dates` for a list of formats valid for -d/--date.
4593
4597
4594 Returns 0 on success.
4598 Returns 0 on success.
4595 """
4599 """
4596
4600
4597 if opts.get("date"):
4601 if opts.get("date"):
4598 if opts.get("rev"):
4602 if opts.get("rev"):
4599 raise util.Abort(_("you can't specify a revision and a date"))
4603 raise util.Abort(_("you can't specify a revision and a date"))
4600 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4604 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4601
4605
4602 parent, p2 = repo.dirstate.parents()
4606 parent, p2 = repo.dirstate.parents()
4603 if not opts.get('rev') and p2 != nullid:
4607 if not opts.get('rev') and p2 != nullid:
4604 # revert after merge is a trap for new users (issue2915)
4608 # revert after merge is a trap for new users (issue2915)
4605 raise util.Abort(_('uncommitted merge with no revision specified'),
4609 raise util.Abort(_('uncommitted merge with no revision specified'),
4606 hint=_('use "hg update" or see "hg help revert"'))
4610 hint=_('use "hg update" or see "hg help revert"'))
4607
4611
4608 ctx = scmutil.revsingle(repo, opts.get('rev'))
4612 ctx = scmutil.revsingle(repo, opts.get('rev'))
4609 node = ctx.node()
4613 node = ctx.node()
4610
4614
4611 if not pats and not opts.get('all'):
4615 if not pats and not opts.get('all'):
4612 msg = _("no files or directories specified")
4616 msg = _("no files or directories specified")
4613 if p2 != nullid:
4617 if p2 != nullid:
4614 hint = _("uncommitted merge, use --all to discard all changes,"
4618 hint = _("uncommitted merge, use --all to discard all changes,"
4615 " or 'hg update -C .' to abort the merge")
4619 " or 'hg update -C .' to abort the merge")
4616 raise util.Abort(msg, hint=hint)
4620 raise util.Abort(msg, hint=hint)
4617 dirty = util.any(repo.status())
4621 dirty = util.any(repo.status())
4618 if node != parent:
4622 if node != parent:
4619 if dirty:
4623 if dirty:
4620 hint = _("uncommitted changes, use --all to discard all"
4624 hint = _("uncommitted changes, use --all to discard all"
4621 " changes, or 'hg update %s' to update") % ctx.rev()
4625 " changes, or 'hg update %s' to update") % ctx.rev()
4622 else:
4626 else:
4623 hint = _("use --all to revert all files,"
4627 hint = _("use --all to revert all files,"
4624 " or 'hg update %s' to update") % ctx.rev()
4628 " or 'hg update %s' to update") % ctx.rev()
4625 elif dirty:
4629 elif dirty:
4626 hint = _("uncommitted changes, use --all to discard all changes")
4630 hint = _("uncommitted changes, use --all to discard all changes")
4627 else:
4631 else:
4628 hint = _("use --all to revert all files")
4632 hint = _("use --all to revert all files")
4629 raise util.Abort(msg, hint=hint)
4633 raise util.Abort(msg, hint=hint)
4630
4634
4631 mf = ctx.manifest()
4635 mf = ctx.manifest()
4632 if node == parent:
4636 if node == parent:
4633 pmf = mf
4637 pmf = mf
4634 else:
4638 else:
4635 pmf = None
4639 pmf = None
4636
4640
4637 # need all matching names in dirstate and manifest of target rev,
4641 # need all matching names in dirstate and manifest of target rev,
4638 # so have to walk both. do not print errors if files exist in one
4642 # so have to walk both. do not print errors if files exist in one
4639 # but not other.
4643 # but not other.
4640
4644
4641 names = {}
4645 names = {}
4642
4646
4643 wlock = repo.wlock()
4647 wlock = repo.wlock()
4644 try:
4648 try:
4645 # walk dirstate.
4649 # walk dirstate.
4646
4650
4647 m = scmutil.match(repo[None], pats, opts)
4651 m = scmutil.match(repo[None], pats, opts)
4648 m.bad = lambda x, y: False
4652 m.bad = lambda x, y: False
4649 for abs in repo.walk(m):
4653 for abs in repo.walk(m):
4650 names[abs] = m.rel(abs), m.exact(abs)
4654 names[abs] = m.rel(abs), m.exact(abs)
4651
4655
4652 # walk target manifest.
4656 # walk target manifest.
4653
4657
4654 def badfn(path, msg):
4658 def badfn(path, msg):
4655 if path in names:
4659 if path in names:
4656 return
4660 return
4657 if path in repo[node].substate:
4661 if path in repo[node].substate:
4658 ui.warn("%s: %s\n" % (m.rel(path),
4662 ui.warn("%s: %s\n" % (m.rel(path),
4659 'reverting subrepos is unsupported'))
4663 'reverting subrepos is unsupported'))
4660 return
4664 return
4661 path_ = path + '/'
4665 path_ = path + '/'
4662 for f in names:
4666 for f in names:
4663 if f.startswith(path_):
4667 if f.startswith(path_):
4664 return
4668 return
4665 ui.warn("%s: %s\n" % (m.rel(path), msg))
4669 ui.warn("%s: %s\n" % (m.rel(path), msg))
4666
4670
4667 m = scmutil.match(repo[node], pats, opts)
4671 m = scmutil.match(repo[node], pats, opts)
4668 m.bad = badfn
4672 m.bad = badfn
4669 for abs in repo[node].walk(m):
4673 for abs in repo[node].walk(m):
4670 if abs not in names:
4674 if abs not in names:
4671 names[abs] = m.rel(abs), m.exact(abs)
4675 names[abs] = m.rel(abs), m.exact(abs)
4672
4676
4673 m = scmutil.matchfiles(repo, names)
4677 m = scmutil.matchfiles(repo, names)
4674 changes = repo.status(match=m)[:4]
4678 changes = repo.status(match=m)[:4]
4675 modified, added, removed, deleted = map(set, changes)
4679 modified, added, removed, deleted = map(set, changes)
4676
4680
4677 # if f is a rename, also revert the source
4681 # if f is a rename, also revert the source
4678 cwd = repo.getcwd()
4682 cwd = repo.getcwd()
4679 for f in added:
4683 for f in added:
4680 src = repo.dirstate.copied(f)
4684 src = repo.dirstate.copied(f)
4681 if src and src not in names and repo.dirstate[src] == 'r':
4685 if src and src not in names and repo.dirstate[src] == 'r':
4682 removed.add(src)
4686 removed.add(src)
4683 names[src] = (repo.pathto(src, cwd), True)
4687 names[src] = (repo.pathto(src, cwd), True)
4684
4688
4685 def removeforget(abs):
4689 def removeforget(abs):
4686 if repo.dirstate[abs] == 'a':
4690 if repo.dirstate[abs] == 'a':
4687 return _('forgetting %s\n')
4691 return _('forgetting %s\n')
4688 return _('removing %s\n')
4692 return _('removing %s\n')
4689
4693
4690 revert = ([], _('reverting %s\n'))
4694 revert = ([], _('reverting %s\n'))
4691 add = ([], _('adding %s\n'))
4695 add = ([], _('adding %s\n'))
4692 remove = ([], removeforget)
4696 remove = ([], removeforget)
4693 undelete = ([], _('undeleting %s\n'))
4697 undelete = ([], _('undeleting %s\n'))
4694
4698
4695 disptable = (
4699 disptable = (
4696 # dispatch table:
4700 # dispatch table:
4697 # file state
4701 # file state
4698 # action if in target manifest
4702 # action if in target manifest
4699 # action if not in target manifest
4703 # action if not in target manifest
4700 # make backup if in target manifest
4704 # make backup if in target manifest
4701 # make backup if not in target manifest
4705 # make backup if not in target manifest
4702 (modified, revert, remove, True, True),
4706 (modified, revert, remove, True, True),
4703 (added, revert, remove, True, False),
4707 (added, revert, remove, True, False),
4704 (removed, undelete, None, False, False),
4708 (removed, undelete, None, False, False),
4705 (deleted, revert, remove, False, False),
4709 (deleted, revert, remove, False, False),
4706 )
4710 )
4707
4711
4708 for abs, (rel, exact) in sorted(names.items()):
4712 for abs, (rel, exact) in sorted(names.items()):
4709 mfentry = mf.get(abs)
4713 mfentry = mf.get(abs)
4710 target = repo.wjoin(abs)
4714 target = repo.wjoin(abs)
4711 def handle(xlist, dobackup):
4715 def handle(xlist, dobackup):
4712 xlist[0].append(abs)
4716 xlist[0].append(abs)
4713 if (dobackup and not opts.get('no_backup') and
4717 if (dobackup and not opts.get('no_backup') and
4714 os.path.lexists(target)):
4718 os.path.lexists(target)):
4715 bakname = "%s.orig" % rel
4719 bakname = "%s.orig" % rel
4716 ui.note(_('saving current version of %s as %s\n') %
4720 ui.note(_('saving current version of %s as %s\n') %
4717 (rel, bakname))
4721 (rel, bakname))
4718 if not opts.get('dry_run'):
4722 if not opts.get('dry_run'):
4719 util.rename(target, bakname)
4723 util.rename(target, bakname)
4720 if ui.verbose or not exact:
4724 if ui.verbose or not exact:
4721 msg = xlist[1]
4725 msg = xlist[1]
4722 if not isinstance(msg, basestring):
4726 if not isinstance(msg, basestring):
4723 msg = msg(abs)
4727 msg = msg(abs)
4724 ui.status(msg % rel)
4728 ui.status(msg % rel)
4725 for table, hitlist, misslist, backuphit, backupmiss in disptable:
4729 for table, hitlist, misslist, backuphit, backupmiss in disptable:
4726 if abs not in table:
4730 if abs not in table:
4727 continue
4731 continue
4728 # file has changed in dirstate
4732 # file has changed in dirstate
4729 if mfentry:
4733 if mfentry:
4730 handle(hitlist, backuphit)
4734 handle(hitlist, backuphit)
4731 elif misslist is not None:
4735 elif misslist is not None:
4732 handle(misslist, backupmiss)
4736 handle(misslist, backupmiss)
4733 break
4737 break
4734 else:
4738 else:
4735 if abs not in repo.dirstate:
4739 if abs not in repo.dirstate:
4736 if mfentry:
4740 if mfentry:
4737 handle(add, True)
4741 handle(add, True)
4738 elif exact:
4742 elif exact:
4739 ui.warn(_('file not managed: %s\n') % rel)
4743 ui.warn(_('file not managed: %s\n') % rel)
4740 continue
4744 continue
4741 # file has not changed in dirstate
4745 # file has not changed in dirstate
4742 if node == parent:
4746 if node == parent:
4743 if exact:
4747 if exact:
4744 ui.warn(_('no changes needed to %s\n') % rel)
4748 ui.warn(_('no changes needed to %s\n') % rel)
4745 continue
4749 continue
4746 if pmf is None:
4750 if pmf is None:
4747 # only need parent manifest in this unlikely case,
4751 # only need parent manifest in this unlikely case,
4748 # so do not read by default
4752 # so do not read by default
4749 pmf = repo[parent].manifest()
4753 pmf = repo[parent].manifest()
4750 if abs in pmf:
4754 if abs in pmf:
4751 if mfentry:
4755 if mfentry:
4752 # if version of file is same in parent and target
4756 # if version of file is same in parent and target
4753 # manifests, do nothing
4757 # manifests, do nothing
4754 if (pmf[abs] != mfentry or
4758 if (pmf[abs] != mfentry or
4755 pmf.flags(abs) != mf.flags(abs)):
4759 pmf.flags(abs) != mf.flags(abs)):
4756 handle(revert, False)
4760 handle(revert, False)
4757 else:
4761 else:
4758 handle(remove, False)
4762 handle(remove, False)
4759
4763
4760 if not opts.get('dry_run'):
4764 if not opts.get('dry_run'):
4761 def checkout(f):
4765 def checkout(f):
4762 fc = ctx[f]
4766 fc = ctx[f]
4763 repo.wwrite(f, fc.data(), fc.flags())
4767 repo.wwrite(f, fc.data(), fc.flags())
4764
4768
4765 audit_path = scmutil.pathauditor(repo.root)
4769 audit_path = scmutil.pathauditor(repo.root)
4766 for f in remove[0]:
4770 for f in remove[0]:
4767 if repo.dirstate[f] == 'a':
4771 if repo.dirstate[f] == 'a':
4768 repo.dirstate.drop(f)
4772 repo.dirstate.drop(f)
4769 continue
4773 continue
4770 audit_path(f)
4774 audit_path(f)
4771 try:
4775 try:
4772 util.unlinkpath(repo.wjoin(f))
4776 util.unlinkpath(repo.wjoin(f))
4773 except OSError:
4777 except OSError:
4774 pass
4778 pass
4775 repo.dirstate.remove(f)
4779 repo.dirstate.remove(f)
4776
4780
4777 normal = None
4781 normal = None
4778 if node == parent:
4782 if node == parent:
4779 # We're reverting to our parent. If possible, we'd like status
4783 # We're reverting to our parent. If possible, we'd like status
4780 # to report the file as clean. We have to use normallookup for
4784 # to report the file as clean. We have to use normallookup for
4781 # merges to avoid losing information about merged/dirty files.
4785 # merges to avoid losing information about merged/dirty files.
4782 if p2 != nullid:
4786 if p2 != nullid:
4783 normal = repo.dirstate.normallookup
4787 normal = repo.dirstate.normallookup
4784 else:
4788 else:
4785 normal = repo.dirstate.normal
4789 normal = repo.dirstate.normal
4786 for f in revert[0]:
4790 for f in revert[0]:
4787 checkout(f)
4791 checkout(f)
4788 if normal:
4792 if normal:
4789 normal(f)
4793 normal(f)
4790
4794
4791 for f in add[0]:
4795 for f in add[0]:
4792 checkout(f)
4796 checkout(f)
4793 repo.dirstate.add(f)
4797 repo.dirstate.add(f)
4794
4798
4795 normal = repo.dirstate.normallookup
4799 normal = repo.dirstate.normallookup
4796 if node == parent and p2 == nullid:
4800 if node == parent and p2 == nullid:
4797 normal = repo.dirstate.normal
4801 normal = repo.dirstate.normal
4798 for f in undelete[0]:
4802 for f in undelete[0]:
4799 checkout(f)
4803 checkout(f)
4800 normal(f)
4804 normal(f)
4801
4805
4802 finally:
4806 finally:
4803 wlock.release()
4807 wlock.release()
4804
4808
4805 @command('rollback', dryrunopts +
4809 @command('rollback', dryrunopts +
4806 [('f', 'force', False, _('ignore safety measures'))])
4810 [('f', 'force', False, _('ignore safety measures'))])
4807 def rollback(ui, repo, **opts):
4811 def rollback(ui, repo, **opts):
4808 """roll back the last transaction (dangerous)
4812 """roll back the last transaction (dangerous)
4809
4813
4810 This command should be used with care. There is only one level of
4814 This command should be used with care. There is only one level of
4811 rollback, and there is no way to undo a rollback. It will also
4815 rollback, and there is no way to undo a rollback. It will also
4812 restore the dirstate at the time of the last transaction, losing
4816 restore the dirstate at the time of the last transaction, losing
4813 any dirstate changes since that time. This command does not alter
4817 any dirstate changes since that time. This command does not alter
4814 the working directory.
4818 the working directory.
4815
4819
4816 Transactions are used to encapsulate the effects of all commands
4820 Transactions are used to encapsulate the effects of all commands
4817 that create new changesets or propagate existing changesets into a
4821 that create new changesets or propagate existing changesets into a
4818 repository. For example, the following commands are transactional,
4822 repository. For example, the following commands are transactional,
4819 and their effects can be rolled back:
4823 and their effects can be rolled back:
4820
4824
4821 - commit
4825 - commit
4822 - import
4826 - import
4823 - pull
4827 - pull
4824 - push (with this repository as the destination)
4828 - push (with this repository as the destination)
4825 - unbundle
4829 - unbundle
4826
4830
4827 It's possible to lose data with rollback: commit, update back to
4831 It's possible to lose data with rollback: commit, update back to
4828 an older changeset, and then rollback. The update removes the
4832 an older changeset, and then rollback. The update removes the
4829 changes you committed from the working directory, and rollback
4833 changes you committed from the working directory, and rollback
4830 removes them from history. To avoid data loss, you must pass
4834 removes them from history. To avoid data loss, you must pass
4831 --force in this case.
4835 --force in this case.
4832
4836
4833 This command is not intended for use on public repositories. Once
4837 This command is not intended for use on public repositories. Once
4834 changes are visible for pull by other users, rolling a transaction
4838 changes are visible for pull by other users, rolling a transaction
4835 back locally is ineffective (someone else may already have pulled
4839 back locally is ineffective (someone else may already have pulled
4836 the changes). Furthermore, a race is possible with readers of the
4840 the changes). Furthermore, a race is possible with readers of the
4837 repository; for example an in-progress pull from the repository
4841 repository; for example an in-progress pull from the repository
4838 may fail if a rollback is performed.
4842 may fail if a rollback is performed.
4839
4843
4840 Returns 0 on success, 1 if no rollback data is available.
4844 Returns 0 on success, 1 if no rollback data is available.
4841 """
4845 """
4842 return repo.rollback(dryrun=opts.get('dry_run'),
4846 return repo.rollback(dryrun=opts.get('dry_run'),
4843 force=opts.get('force'))
4847 force=opts.get('force'))
4844
4848
4845 @command('root', [])
4849 @command('root', [])
4846 def root(ui, repo):
4850 def root(ui, repo):
4847 """print the root (top) of the current working directory
4851 """print the root (top) of the current working directory
4848
4852
4849 Print the root directory of the current repository.
4853 Print the root directory of the current repository.
4850
4854
4851 Returns 0 on success.
4855 Returns 0 on success.
4852 """
4856 """
4853 ui.write(repo.root + "\n")
4857 ui.write(repo.root + "\n")
4854
4858
4855 @command('^serve',
4859 @command('^serve',
4856 [('A', 'accesslog', '', _('name of access log file to write to'),
4860 [('A', 'accesslog', '', _('name of access log file to write to'),
4857 _('FILE')),
4861 _('FILE')),
4858 ('d', 'daemon', None, _('run server in background')),
4862 ('d', 'daemon', None, _('run server in background')),
4859 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
4863 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
4860 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4864 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4861 # use string type, then we can check if something was passed
4865 # use string type, then we can check if something was passed
4862 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4866 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4863 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4867 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4864 _('ADDR')),
4868 _('ADDR')),
4865 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4869 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4866 _('PREFIX')),
4870 _('PREFIX')),
4867 ('n', 'name', '',
4871 ('n', 'name', '',
4868 _('name to show in web pages (default: working directory)'), _('NAME')),
4872 _('name to show in web pages (default: working directory)'), _('NAME')),
4869 ('', 'web-conf', '',
4873 ('', 'web-conf', '',
4870 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
4874 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
4871 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4875 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4872 _('FILE')),
4876 _('FILE')),
4873 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4877 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4874 ('', 'stdio', None, _('for remote clients')),
4878 ('', 'stdio', None, _('for remote clients')),
4875 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
4879 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
4876 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4880 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4877 ('', 'style', '', _('template style to use'), _('STYLE')),
4881 ('', 'style', '', _('template style to use'), _('STYLE')),
4878 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4882 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4879 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
4883 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
4880 _('[OPTION]...'))
4884 _('[OPTION]...'))
4881 def serve(ui, repo, **opts):
4885 def serve(ui, repo, **opts):
4882 """start stand-alone webserver
4886 """start stand-alone webserver
4883
4887
4884 Start a local HTTP repository browser and pull server. You can use
4888 Start a local HTTP repository browser and pull server. You can use
4885 this for ad-hoc sharing and browsing of repositories. It is
4889 this for ad-hoc sharing and browsing of repositories. It is
4886 recommended to use a real web server to serve a repository for
4890 recommended to use a real web server to serve a repository for
4887 longer periods of time.
4891 longer periods of time.
4888
4892
4889 Please note that the server does not implement access control.
4893 Please note that the server does not implement access control.
4890 This means that, by default, anybody can read from the server and
4894 This means that, by default, anybody can read from the server and
4891 nobody can write to it by default. Set the ``web.allow_push``
4895 nobody can write to it by default. Set the ``web.allow_push``
4892 option to ``*`` to allow everybody to push to the server. You
4896 option to ``*`` to allow everybody to push to the server. You
4893 should use a real web server if you need to authenticate users.
4897 should use a real web server if you need to authenticate users.
4894
4898
4895 By default, the server logs accesses to stdout and errors to
4899 By default, the server logs accesses to stdout and errors to
4896 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4900 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4897 files.
4901 files.
4898
4902
4899 To have the server choose a free port number to listen on, specify
4903 To have the server choose a free port number to listen on, specify
4900 a port number of 0; in this case, the server will print the port
4904 a port number of 0; in this case, the server will print the port
4901 number it uses.
4905 number it uses.
4902
4906
4903 Returns 0 on success.
4907 Returns 0 on success.
4904 """
4908 """
4905
4909
4906 if opts["stdio"] and opts["cmdserver"]:
4910 if opts["stdio"] and opts["cmdserver"]:
4907 raise util.Abort(_("cannot use --stdio with --cmdserver"))
4911 raise util.Abort(_("cannot use --stdio with --cmdserver"))
4908
4912
4909 def checkrepo():
4913 def checkrepo():
4910 if repo is None:
4914 if repo is None:
4911 raise error.RepoError(_("There is no Mercurial repository here"
4915 raise error.RepoError(_("There is no Mercurial repository here"
4912 " (.hg not found)"))
4916 " (.hg not found)"))
4913
4917
4914 if opts["stdio"]:
4918 if opts["stdio"]:
4915 checkrepo()
4919 checkrepo()
4916 s = sshserver.sshserver(ui, repo)
4920 s = sshserver.sshserver(ui, repo)
4917 s.serve_forever()
4921 s.serve_forever()
4918
4922
4919 if opts["cmdserver"]:
4923 if opts["cmdserver"]:
4920 checkrepo()
4924 checkrepo()
4921 s = commandserver.server(ui, repo, opts["cmdserver"])
4925 s = commandserver.server(ui, repo, opts["cmdserver"])
4922 return s.serve()
4926 return s.serve()
4923
4927
4924 # this way we can check if something was given in the command-line
4928 # this way we can check if something was given in the command-line
4925 if opts.get('port'):
4929 if opts.get('port'):
4926 opts['port'] = util.getport(opts.get('port'))
4930 opts['port'] = util.getport(opts.get('port'))
4927
4931
4928 baseui = repo and repo.baseui or ui
4932 baseui = repo and repo.baseui or ui
4929 optlist = ("name templates style address port prefix ipv6"
4933 optlist = ("name templates style address port prefix ipv6"
4930 " accesslog errorlog certificate encoding")
4934 " accesslog errorlog certificate encoding")
4931 for o in optlist.split():
4935 for o in optlist.split():
4932 val = opts.get(o, '')
4936 val = opts.get(o, '')
4933 if val in (None, ''): # should check against default options instead
4937 if val in (None, ''): # should check against default options instead
4934 continue
4938 continue
4935 baseui.setconfig("web", o, val)
4939 baseui.setconfig("web", o, val)
4936 if repo and repo.ui != baseui:
4940 if repo and repo.ui != baseui:
4937 repo.ui.setconfig("web", o, val)
4941 repo.ui.setconfig("web", o, val)
4938
4942
4939 o = opts.get('web_conf') or opts.get('webdir_conf')
4943 o = opts.get('web_conf') or opts.get('webdir_conf')
4940 if not o:
4944 if not o:
4941 if not repo:
4945 if not repo:
4942 raise error.RepoError(_("There is no Mercurial repository"
4946 raise error.RepoError(_("There is no Mercurial repository"
4943 " here (.hg not found)"))
4947 " here (.hg not found)"))
4944 o = repo.root
4948 o = repo.root
4945
4949
4946 app = hgweb.hgweb(o, baseui=ui)
4950 app = hgweb.hgweb(o, baseui=ui)
4947
4951
4948 class service(object):
4952 class service(object):
4949 def init(self):
4953 def init(self):
4950 util.setsignalhandler()
4954 util.setsignalhandler()
4951 self.httpd = hgweb.server.create_server(ui, app)
4955 self.httpd = hgweb.server.create_server(ui, app)
4952
4956
4953 if opts['port'] and not ui.verbose:
4957 if opts['port'] and not ui.verbose:
4954 return
4958 return
4955
4959
4956 if self.httpd.prefix:
4960 if self.httpd.prefix:
4957 prefix = self.httpd.prefix.strip('/') + '/'
4961 prefix = self.httpd.prefix.strip('/') + '/'
4958 else:
4962 else:
4959 prefix = ''
4963 prefix = ''
4960
4964
4961 port = ':%d' % self.httpd.port
4965 port = ':%d' % self.httpd.port
4962 if port == ':80':
4966 if port == ':80':
4963 port = ''
4967 port = ''
4964
4968
4965 bindaddr = self.httpd.addr
4969 bindaddr = self.httpd.addr
4966 if bindaddr == '0.0.0.0':
4970 if bindaddr == '0.0.0.0':
4967 bindaddr = '*'
4971 bindaddr = '*'
4968 elif ':' in bindaddr: # IPv6
4972 elif ':' in bindaddr: # IPv6
4969 bindaddr = '[%s]' % bindaddr
4973 bindaddr = '[%s]' % bindaddr
4970
4974
4971 fqaddr = self.httpd.fqaddr
4975 fqaddr = self.httpd.fqaddr
4972 if ':' in fqaddr:
4976 if ':' in fqaddr:
4973 fqaddr = '[%s]' % fqaddr
4977 fqaddr = '[%s]' % fqaddr
4974 if opts['port']:
4978 if opts['port']:
4975 write = ui.status
4979 write = ui.status
4976 else:
4980 else:
4977 write = ui.write
4981 write = ui.write
4978 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
4982 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
4979 (fqaddr, port, prefix, bindaddr, self.httpd.port))
4983 (fqaddr, port, prefix, bindaddr, self.httpd.port))
4980
4984
4981 def run(self):
4985 def run(self):
4982 self.httpd.serve_forever()
4986 self.httpd.serve_forever()
4983
4987
4984 service = service()
4988 service = service()
4985
4989
4986 cmdutil.service(opts, initfn=service.init, runfn=service.run)
4990 cmdutil.service(opts, initfn=service.init, runfn=service.run)
4987
4991
4988 @command('showconfig|debugconfig',
4992 @command('showconfig|debugconfig',
4989 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4993 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4990 _('[-u] [NAME]...'))
4994 _('[-u] [NAME]...'))
4991 def showconfig(ui, repo, *values, **opts):
4995 def showconfig(ui, repo, *values, **opts):
4992 """show combined config settings from all hgrc files
4996 """show combined config settings from all hgrc files
4993
4997
4994 With no arguments, print names and values of all config items.
4998 With no arguments, print names and values of all config items.
4995
4999
4996 With one argument of the form section.name, print just the value
5000 With one argument of the form section.name, print just the value
4997 of that config item.
5001 of that config item.
4998
5002
4999 With multiple arguments, print names and values of all config
5003 With multiple arguments, print names and values of all config
5000 items with matching section names.
5004 items with matching section names.
5001
5005
5002 With --debug, the source (filename and line number) is printed
5006 With --debug, the source (filename and line number) is printed
5003 for each config item.
5007 for each config item.
5004
5008
5005 Returns 0 on success.
5009 Returns 0 on success.
5006 """
5010 """
5007
5011
5008 for f in scmutil.rcpath():
5012 for f in scmutil.rcpath():
5009 ui.debug('read config from: %s\n' % f)
5013 ui.debug('read config from: %s\n' % f)
5010 untrusted = bool(opts.get('untrusted'))
5014 untrusted = bool(opts.get('untrusted'))
5011 if values:
5015 if values:
5012 sections = [v for v in values if '.' not in v]
5016 sections = [v for v in values if '.' not in v]
5013 items = [v for v in values if '.' in v]
5017 items = [v for v in values if '.' in v]
5014 if len(items) > 1 or items and sections:
5018 if len(items) > 1 or items and sections:
5015 raise util.Abort(_('only one config item permitted'))
5019 raise util.Abort(_('only one config item permitted'))
5016 for section, name, value in ui.walkconfig(untrusted=untrusted):
5020 for section, name, value in ui.walkconfig(untrusted=untrusted):
5017 value = str(value).replace('\n', '\\n')
5021 value = str(value).replace('\n', '\\n')
5018 sectname = section + '.' + name
5022 sectname = section + '.' + name
5019 if values:
5023 if values:
5020 for v in values:
5024 for v in values:
5021 if v == section:
5025 if v == section:
5022 ui.debug('%s: ' %
5026 ui.debug('%s: ' %
5023 ui.configsource(section, name, untrusted))
5027 ui.configsource(section, name, untrusted))
5024 ui.write('%s=%s\n' % (sectname, value))
5028 ui.write('%s=%s\n' % (sectname, value))
5025 elif v == sectname:
5029 elif v == sectname:
5026 ui.debug('%s: ' %
5030 ui.debug('%s: ' %
5027 ui.configsource(section, name, untrusted))
5031 ui.configsource(section, name, untrusted))
5028 ui.write(value, '\n')
5032 ui.write(value, '\n')
5029 else:
5033 else:
5030 ui.debug('%s: ' %
5034 ui.debug('%s: ' %
5031 ui.configsource(section, name, untrusted))
5035 ui.configsource(section, name, untrusted))
5032 ui.write('%s=%s\n' % (sectname, value))
5036 ui.write('%s=%s\n' % (sectname, value))
5033
5037
5034 @command('^status|st',
5038 @command('^status|st',
5035 [('A', 'all', None, _('show status of all files')),
5039 [('A', 'all', None, _('show status of all files')),
5036 ('m', 'modified', None, _('show only modified files')),
5040 ('m', 'modified', None, _('show only modified files')),
5037 ('a', 'added', None, _('show only added files')),
5041 ('a', 'added', None, _('show only added files')),
5038 ('r', 'removed', None, _('show only removed files')),
5042 ('r', 'removed', None, _('show only removed files')),
5039 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5043 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5040 ('c', 'clean', None, _('show only files without changes')),
5044 ('c', 'clean', None, _('show only files without changes')),
5041 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5045 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5042 ('i', 'ignored', None, _('show only ignored files')),
5046 ('i', 'ignored', None, _('show only ignored files')),
5043 ('n', 'no-status', None, _('hide status prefix')),
5047 ('n', 'no-status', None, _('hide status prefix')),
5044 ('C', 'copies', None, _('show source of copied files')),
5048 ('C', 'copies', None, _('show source of copied files')),
5045 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5049 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5046 ('', 'rev', [], _('show difference from revision'), _('REV')),
5050 ('', 'rev', [], _('show difference from revision'), _('REV')),
5047 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5051 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5048 ] + walkopts + subrepoopts,
5052 ] + walkopts + subrepoopts,
5049 _('[OPTION]... [FILE]...'))
5053 _('[OPTION]... [FILE]...'))
5050 def status(ui, repo, *pats, **opts):
5054 def status(ui, repo, *pats, **opts):
5051 """show changed files in the working directory
5055 """show changed files in the working directory
5052
5056
5053 Show status of files in the repository. If names are given, only
5057 Show status of files in the repository. If names are given, only
5054 files that match are shown. Files that are clean or ignored or
5058 files that match are shown. Files that are clean or ignored or
5055 the source of a copy/move operation, are not listed unless
5059 the source of a copy/move operation, are not listed unless
5056 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5060 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5057 Unless options described with "show only ..." are given, the
5061 Unless options described with "show only ..." are given, the
5058 options -mardu are used.
5062 options -mardu are used.
5059
5063
5060 Option -q/--quiet hides untracked (unknown and ignored) files
5064 Option -q/--quiet hides untracked (unknown and ignored) files
5061 unless explicitly requested with -u/--unknown or -i/--ignored.
5065 unless explicitly requested with -u/--unknown or -i/--ignored.
5062
5066
5063 .. note::
5067 .. note::
5064 status may appear to disagree with diff if permissions have
5068 status may appear to disagree with diff if permissions have
5065 changed or a merge has occurred. The standard diff format does
5069 changed or a merge has occurred. The standard diff format does
5066 not report permission changes and diff only reports changes
5070 not report permission changes and diff only reports changes
5067 relative to one merge parent.
5071 relative to one merge parent.
5068
5072
5069 If one revision is given, it is used as the base revision.
5073 If one revision is given, it is used as the base revision.
5070 If two revisions are given, the differences between them are
5074 If two revisions are given, the differences between them are
5071 shown. The --change option can also be used as a shortcut to list
5075 shown. The --change option can also be used as a shortcut to list
5072 the changed files of a revision from its first parent.
5076 the changed files of a revision from its first parent.
5073
5077
5074 The codes used to show the status of files are::
5078 The codes used to show the status of files are::
5075
5079
5076 M = modified
5080 M = modified
5077 A = added
5081 A = added
5078 R = removed
5082 R = removed
5079 C = clean
5083 C = clean
5080 ! = missing (deleted by non-hg command, but still tracked)
5084 ! = missing (deleted by non-hg command, but still tracked)
5081 ? = not tracked
5085 ? = not tracked
5082 I = ignored
5086 I = ignored
5083 = origin of the previous file listed as A (added)
5087 = origin of the previous file listed as A (added)
5084
5088
5085 .. container:: verbose
5089 .. container:: verbose
5086
5090
5087 Examples:
5091 Examples:
5088
5092
5089 - show changes in the working directory relative to a changeset:
5093 - show changes in the working directory relative to a changeset:
5090
5094
5091 hg status --rev 9353
5095 hg status --rev 9353
5092
5096
5093 - show all changes including copies in an existing changeset::
5097 - show all changes including copies in an existing changeset::
5094
5098
5095 hg status --copies --change 9353
5099 hg status --copies --change 9353
5096
5100
5097 - get a NUL separated list of added files, suitable for xargs::
5101 - get a NUL separated list of added files, suitable for xargs::
5098
5102
5099 hg status -an0
5103 hg status -an0
5100
5104
5101 Returns 0 on success.
5105 Returns 0 on success.
5102 """
5106 """
5103
5107
5104 revs = opts.get('rev')
5108 revs = opts.get('rev')
5105 change = opts.get('change')
5109 change = opts.get('change')
5106
5110
5107 if revs and change:
5111 if revs and change:
5108 msg = _('cannot specify --rev and --change at the same time')
5112 msg = _('cannot specify --rev and --change at the same time')
5109 raise util.Abort(msg)
5113 raise util.Abort(msg)
5110 elif change:
5114 elif change:
5111 node2 = repo.lookup(change)
5115 node2 = repo.lookup(change)
5112 node1 = repo[node2].p1().node()
5116 node1 = repo[node2].p1().node()
5113 else:
5117 else:
5114 node1, node2 = scmutil.revpair(repo, revs)
5118 node1, node2 = scmutil.revpair(repo, revs)
5115
5119
5116 cwd = (pats and repo.getcwd()) or ''
5120 cwd = (pats and repo.getcwd()) or ''
5117 end = opts.get('print0') and '\0' or '\n'
5121 end = opts.get('print0') and '\0' or '\n'
5118 copy = {}
5122 copy = {}
5119 states = 'modified added removed deleted unknown ignored clean'.split()
5123 states = 'modified added removed deleted unknown ignored clean'.split()
5120 show = [k for k in states if opts.get(k)]
5124 show = [k for k in states if opts.get(k)]
5121 if opts.get('all'):
5125 if opts.get('all'):
5122 show += ui.quiet and (states[:4] + ['clean']) or states
5126 show += ui.quiet and (states[:4] + ['clean']) or states
5123 if not show:
5127 if not show:
5124 show = ui.quiet and states[:4] or states[:5]
5128 show = ui.quiet and states[:4] or states[:5]
5125
5129
5126 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5130 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5127 'ignored' in show, 'clean' in show, 'unknown' in show,
5131 'ignored' in show, 'clean' in show, 'unknown' in show,
5128 opts.get('subrepos'))
5132 opts.get('subrepos'))
5129 changestates = zip(states, 'MAR!?IC', stat)
5133 changestates = zip(states, 'MAR!?IC', stat)
5130
5134
5131 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5135 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5132 ctxn = repo[nullid]
5136 ctxn = repo[nullid]
5133 ctx1 = repo[node1]
5137 ctx1 = repo[node1]
5134 ctx2 = repo[node2]
5138 ctx2 = repo[node2]
5135 added = stat[1]
5139 added = stat[1]
5136 if node2 is None:
5140 if node2 is None:
5137 added = stat[0] + stat[1] # merged?
5141 added = stat[0] + stat[1] # merged?
5138
5142
5139 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
5143 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
5140 if k in added:
5144 if k in added:
5141 copy[k] = v
5145 copy[k] = v
5142 elif v in added:
5146 elif v in added:
5143 copy[v] = k
5147 copy[v] = k
5144
5148
5145 for state, char, files in changestates:
5149 for state, char, files in changestates:
5146 if state in show:
5150 if state in show:
5147 format = "%s %%s%s" % (char, end)
5151 format = "%s %%s%s" % (char, end)
5148 if opts.get('no_status'):
5152 if opts.get('no_status'):
5149 format = "%%s%s" % end
5153 format = "%%s%s" % end
5150
5154
5151 for f in files:
5155 for f in files:
5152 ui.write(format % repo.pathto(f, cwd),
5156 ui.write(format % repo.pathto(f, cwd),
5153 label='status.' + state)
5157 label='status.' + state)
5154 if f in copy:
5158 if f in copy:
5155 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
5159 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
5156 label='status.copied')
5160 label='status.copied')
5157
5161
5158 @command('^summary|sum',
5162 @command('^summary|sum',
5159 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5163 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5160 def summary(ui, repo, **opts):
5164 def summary(ui, repo, **opts):
5161 """summarize working directory state
5165 """summarize working directory state
5162
5166
5163 This generates a brief summary of the working directory state,
5167 This generates a brief summary of the working directory state,
5164 including parents, branch, commit status, and available updates.
5168 including parents, branch, commit status, and available updates.
5165
5169
5166 With the --remote option, this will check the default paths for
5170 With the --remote option, this will check the default paths for
5167 incoming and outgoing changes. This can be time-consuming.
5171 incoming and outgoing changes. This can be time-consuming.
5168
5172
5169 Returns 0 on success.
5173 Returns 0 on success.
5170 """
5174 """
5171
5175
5172 ctx = repo[None]
5176 ctx = repo[None]
5173 parents = ctx.parents()
5177 parents = ctx.parents()
5174 pnode = parents[0].node()
5178 pnode = parents[0].node()
5175 marks = []
5179 marks = []
5176
5180
5177 for p in parents:
5181 for p in parents:
5178 # label with log.changeset (instead of log.parent) since this
5182 # label with log.changeset (instead of log.parent) since this
5179 # shows a working directory parent *changeset*:
5183 # shows a working directory parent *changeset*:
5180 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5184 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5181 label='log.changeset')
5185 label='log.changeset')
5182 ui.write(' '.join(p.tags()), label='log.tag')
5186 ui.write(' '.join(p.tags()), label='log.tag')
5183 if p.bookmarks():
5187 if p.bookmarks():
5184 marks.extend(p.bookmarks())
5188 marks.extend(p.bookmarks())
5185 if p.rev() == -1:
5189 if p.rev() == -1:
5186 if not len(repo):
5190 if not len(repo):
5187 ui.write(_(' (empty repository)'))
5191 ui.write(_(' (empty repository)'))
5188 else:
5192 else:
5189 ui.write(_(' (no revision checked out)'))
5193 ui.write(_(' (no revision checked out)'))
5190 ui.write('\n')
5194 ui.write('\n')
5191 if p.description():
5195 if p.description():
5192 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5196 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5193 label='log.summary')
5197 label='log.summary')
5194
5198
5195 branch = ctx.branch()
5199 branch = ctx.branch()
5196 bheads = repo.branchheads(branch)
5200 bheads = repo.branchheads(branch)
5197 m = _('branch: %s\n') % branch
5201 m = _('branch: %s\n') % branch
5198 if branch != 'default':
5202 if branch != 'default':
5199 ui.write(m, label='log.branch')
5203 ui.write(m, label='log.branch')
5200 else:
5204 else:
5201 ui.status(m, label='log.branch')
5205 ui.status(m, label='log.branch')
5202
5206
5203 if marks:
5207 if marks:
5204 current = repo._bookmarkcurrent
5208 current = repo._bookmarkcurrent
5205 ui.write(_('bookmarks:'), label='log.bookmark')
5209 ui.write(_('bookmarks:'), label='log.bookmark')
5206 if current is not None:
5210 if current is not None:
5207 try:
5211 try:
5208 marks.remove(current)
5212 marks.remove(current)
5209 ui.write(' *' + current, label='bookmarks.current')
5213 ui.write(' *' + current, label='bookmarks.current')
5210 except ValueError:
5214 except ValueError:
5211 # current bookmark not in parent ctx marks
5215 # current bookmark not in parent ctx marks
5212 pass
5216 pass
5213 for m in marks:
5217 for m in marks:
5214 ui.write(' ' + m, label='log.bookmark')
5218 ui.write(' ' + m, label='log.bookmark')
5215 ui.write('\n', label='log.bookmark')
5219 ui.write('\n', label='log.bookmark')
5216
5220
5217 st = list(repo.status(unknown=True))[:6]
5221 st = list(repo.status(unknown=True))[:6]
5218
5222
5219 c = repo.dirstate.copies()
5223 c = repo.dirstate.copies()
5220 copied, renamed = [], []
5224 copied, renamed = [], []
5221 for d, s in c.iteritems():
5225 for d, s in c.iteritems():
5222 if s in st[2]:
5226 if s in st[2]:
5223 st[2].remove(s)
5227 st[2].remove(s)
5224 renamed.append(d)
5228 renamed.append(d)
5225 else:
5229 else:
5226 copied.append(d)
5230 copied.append(d)
5227 if d in st[1]:
5231 if d in st[1]:
5228 st[1].remove(d)
5232 st[1].remove(d)
5229 st.insert(3, renamed)
5233 st.insert(3, renamed)
5230 st.insert(4, copied)
5234 st.insert(4, copied)
5231
5235
5232 ms = mergemod.mergestate(repo)
5236 ms = mergemod.mergestate(repo)
5233 st.append([f for f in ms if ms[f] == 'u'])
5237 st.append([f for f in ms if ms[f] == 'u'])
5234
5238
5235 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5239 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5236 st.append(subs)
5240 st.append(subs)
5237
5241
5238 labels = [ui.label(_('%d modified'), 'status.modified'),
5242 labels = [ui.label(_('%d modified'), 'status.modified'),
5239 ui.label(_('%d added'), 'status.added'),
5243 ui.label(_('%d added'), 'status.added'),
5240 ui.label(_('%d removed'), 'status.removed'),
5244 ui.label(_('%d removed'), 'status.removed'),
5241 ui.label(_('%d renamed'), 'status.copied'),
5245 ui.label(_('%d renamed'), 'status.copied'),
5242 ui.label(_('%d copied'), 'status.copied'),
5246 ui.label(_('%d copied'), 'status.copied'),
5243 ui.label(_('%d deleted'), 'status.deleted'),
5247 ui.label(_('%d deleted'), 'status.deleted'),
5244 ui.label(_('%d unknown'), 'status.unknown'),
5248 ui.label(_('%d unknown'), 'status.unknown'),
5245 ui.label(_('%d ignored'), 'status.ignored'),
5249 ui.label(_('%d ignored'), 'status.ignored'),
5246 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5250 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5247 ui.label(_('%d subrepos'), 'status.modified')]
5251 ui.label(_('%d subrepos'), 'status.modified')]
5248 t = []
5252 t = []
5249 for s, l in zip(st, labels):
5253 for s, l in zip(st, labels):
5250 if s:
5254 if s:
5251 t.append(l % len(s))
5255 t.append(l % len(s))
5252
5256
5253 t = ', '.join(t)
5257 t = ', '.join(t)
5254 cleanworkdir = False
5258 cleanworkdir = False
5255
5259
5256 if len(parents) > 1:
5260 if len(parents) > 1:
5257 t += _(' (merge)')
5261 t += _(' (merge)')
5258 elif branch != parents[0].branch():
5262 elif branch != parents[0].branch():
5259 t += _(' (new branch)')
5263 t += _(' (new branch)')
5260 elif (parents[0].extra().get('close') and
5264 elif (parents[0].extra().get('close') and
5261 pnode in repo.branchheads(branch, closed=True)):
5265 pnode in repo.branchheads(branch, closed=True)):
5262 t += _(' (head closed)')
5266 t += _(' (head closed)')
5263 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5267 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5264 t += _(' (clean)')
5268 t += _(' (clean)')
5265 cleanworkdir = True
5269 cleanworkdir = True
5266 elif pnode not in bheads:
5270 elif pnode not in bheads:
5267 t += _(' (new branch head)')
5271 t += _(' (new branch head)')
5268
5272
5269 if cleanworkdir:
5273 if cleanworkdir:
5270 ui.status(_('commit: %s\n') % t.strip())
5274 ui.status(_('commit: %s\n') % t.strip())
5271 else:
5275 else:
5272 ui.write(_('commit: %s\n') % t.strip())
5276 ui.write(_('commit: %s\n') % t.strip())
5273
5277
5274 # all ancestors of branch heads - all ancestors of parent = new csets
5278 # all ancestors of branch heads - all ancestors of parent = new csets
5275 new = [0] * len(repo)
5279 new = [0] * len(repo)
5276 cl = repo.changelog
5280 cl = repo.changelog
5277 for a in [cl.rev(n) for n in bheads]:
5281 for a in [cl.rev(n) for n in bheads]:
5278 new[a] = 1
5282 new[a] = 1
5279 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
5283 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
5280 new[a] = 1
5284 new[a] = 1
5281 for a in [p.rev() for p in parents]:
5285 for a in [p.rev() for p in parents]:
5282 if a >= 0:
5286 if a >= 0:
5283 new[a] = 0
5287 new[a] = 0
5284 for a in cl.ancestors(*[p.rev() for p in parents]):
5288 for a in cl.ancestors(*[p.rev() for p in parents]):
5285 new[a] = 0
5289 new[a] = 0
5286 new = sum(new)
5290 new = sum(new)
5287
5291
5288 if new == 0:
5292 if new == 0:
5289 ui.status(_('update: (current)\n'))
5293 ui.status(_('update: (current)\n'))
5290 elif pnode not in bheads:
5294 elif pnode not in bheads:
5291 ui.write(_('update: %d new changesets (update)\n') % new)
5295 ui.write(_('update: %d new changesets (update)\n') % new)
5292 else:
5296 else:
5293 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5297 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5294 (new, len(bheads)))
5298 (new, len(bheads)))
5295
5299
5296 if opts.get('remote'):
5300 if opts.get('remote'):
5297 t = []
5301 t = []
5298 source, branches = hg.parseurl(ui.expandpath('default'))
5302 source, branches = hg.parseurl(ui.expandpath('default'))
5299 other = hg.peer(repo, {}, source)
5303 other = hg.peer(repo, {}, source)
5300 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
5304 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
5301 ui.debug('comparing with %s\n' % util.hidepassword(source))
5305 ui.debug('comparing with %s\n' % util.hidepassword(source))
5302 repo.ui.pushbuffer()
5306 repo.ui.pushbuffer()
5303 commoninc = discovery.findcommonincoming(repo, other)
5307 commoninc = discovery.findcommonincoming(repo, other)
5304 _common, incoming, _rheads = commoninc
5308 _common, incoming, _rheads = commoninc
5305 repo.ui.popbuffer()
5309 repo.ui.popbuffer()
5306 if incoming:
5310 if incoming:
5307 t.append(_('1 or more incoming'))
5311 t.append(_('1 or more incoming'))
5308
5312
5309 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5313 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5310 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5314 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5311 if source != dest:
5315 if source != dest:
5312 other = hg.peer(repo, {}, dest)
5316 other = hg.peer(repo, {}, dest)
5313 commoninc = None
5317 commoninc = None
5314 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5318 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5315 repo.ui.pushbuffer()
5319 repo.ui.pushbuffer()
5316 common, outheads = discovery.findcommonoutgoing(repo, other,
5320 common, outheads = discovery.findcommonoutgoing(repo, other,
5317 commoninc=commoninc)
5321 commoninc=commoninc)
5318 repo.ui.popbuffer()
5322 repo.ui.popbuffer()
5319 o = repo.changelog.findmissing(common=common, heads=outheads)
5323 o = repo.changelog.findmissing(common=common, heads=outheads)
5320 if o:
5324 if o:
5321 t.append(_('%d outgoing') % len(o))
5325 t.append(_('%d outgoing') % len(o))
5322 if 'bookmarks' in other.listkeys('namespaces'):
5326 if 'bookmarks' in other.listkeys('namespaces'):
5323 lmarks = repo.listkeys('bookmarks')
5327 lmarks = repo.listkeys('bookmarks')
5324 rmarks = other.listkeys('bookmarks')
5328 rmarks = other.listkeys('bookmarks')
5325 diff = set(rmarks) - set(lmarks)
5329 diff = set(rmarks) - set(lmarks)
5326 if len(diff) > 0:
5330 if len(diff) > 0:
5327 t.append(_('%d incoming bookmarks') % len(diff))
5331 t.append(_('%d incoming bookmarks') % len(diff))
5328 diff = set(lmarks) - set(rmarks)
5332 diff = set(lmarks) - set(rmarks)
5329 if len(diff) > 0:
5333 if len(diff) > 0:
5330 t.append(_('%d outgoing bookmarks') % len(diff))
5334 t.append(_('%d outgoing bookmarks') % len(diff))
5331
5335
5332 if t:
5336 if t:
5333 ui.write(_('remote: %s\n') % (', '.join(t)))
5337 ui.write(_('remote: %s\n') % (', '.join(t)))
5334 else:
5338 else:
5335 ui.status(_('remote: (synced)\n'))
5339 ui.status(_('remote: (synced)\n'))
5336
5340
5337 @command('tag',
5341 @command('tag',
5338 [('f', 'force', None, _('force tag')),
5342 [('f', 'force', None, _('force tag')),
5339 ('l', 'local', None, _('make the tag local')),
5343 ('l', 'local', None, _('make the tag local')),
5340 ('r', 'rev', '', _('revision to tag'), _('REV')),
5344 ('r', 'rev', '', _('revision to tag'), _('REV')),
5341 ('', 'remove', None, _('remove a tag')),
5345 ('', 'remove', None, _('remove a tag')),
5342 # -l/--local is already there, commitopts cannot be used
5346 # -l/--local is already there, commitopts cannot be used
5343 ('e', 'edit', None, _('edit commit message')),
5347 ('e', 'edit', None, _('edit commit message')),
5344 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5348 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5345 ] + commitopts2,
5349 ] + commitopts2,
5346 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5350 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5347 def tag(ui, repo, name1, *names, **opts):
5351 def tag(ui, repo, name1, *names, **opts):
5348 """add one or more tags for the current or given revision
5352 """add one or more tags for the current or given revision
5349
5353
5350 Name a particular revision using <name>.
5354 Name a particular revision using <name>.
5351
5355
5352 Tags are used to name particular revisions of the repository and are
5356 Tags are used to name particular revisions of the repository and are
5353 very useful to compare different revisions, to go back to significant
5357 very useful to compare different revisions, to go back to significant
5354 earlier versions or to mark branch points as releases, etc. Changing
5358 earlier versions or to mark branch points as releases, etc. Changing
5355 an existing tag is normally disallowed; use -f/--force to override.
5359 an existing tag is normally disallowed; use -f/--force to override.
5356
5360
5357 If no revision is given, the parent of the working directory is
5361 If no revision is given, the parent of the working directory is
5358 used, or tip if no revision is checked out.
5362 used, or tip if no revision is checked out.
5359
5363
5360 To facilitate version control, distribution, and merging of tags,
5364 To facilitate version control, distribution, and merging of tags,
5361 they are stored as a file named ".hgtags" which is managed similarly
5365 they are stored as a file named ".hgtags" which is managed similarly
5362 to other project files and can be hand-edited if necessary. This
5366 to other project files and can be hand-edited if necessary. This
5363 also means that tagging creates a new commit. The file
5367 also means that tagging creates a new commit. The file
5364 ".hg/localtags" is used for local tags (not shared among
5368 ".hg/localtags" is used for local tags (not shared among
5365 repositories).
5369 repositories).
5366
5370
5367 Tag commits are usually made at the head of a branch. If the parent
5371 Tag commits are usually made at the head of a branch. If the parent
5368 of the working directory is not a branch head, :hg:`tag` aborts; use
5372 of the working directory is not a branch head, :hg:`tag` aborts; use
5369 -f/--force to force the tag commit to be based on a non-head
5373 -f/--force to force the tag commit to be based on a non-head
5370 changeset.
5374 changeset.
5371
5375
5372 See :hg:`help dates` for a list of formats valid for -d/--date.
5376 See :hg:`help dates` for a list of formats valid for -d/--date.
5373
5377
5374 Since tag names have priority over branch names during revision
5378 Since tag names have priority over branch names during revision
5375 lookup, using an existing branch name as a tag name is discouraged.
5379 lookup, using an existing branch name as a tag name is discouraged.
5376
5380
5377 Returns 0 on success.
5381 Returns 0 on success.
5378 """
5382 """
5379
5383
5380 rev_ = "."
5384 rev_ = "."
5381 names = [t.strip() for t in (name1,) + names]
5385 names = [t.strip() for t in (name1,) + names]
5382 if len(names) != len(set(names)):
5386 if len(names) != len(set(names)):
5383 raise util.Abort(_('tag names must be unique'))
5387 raise util.Abort(_('tag names must be unique'))
5384 for n in names:
5388 for n in names:
5385 if n in ['tip', '.', 'null']:
5389 if n in ['tip', '.', 'null']:
5386 raise util.Abort(_("the name '%s' is reserved") % n)
5390 raise util.Abort(_("the name '%s' is reserved") % n)
5387 if not n:
5391 if not n:
5388 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
5392 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
5389 if opts.get('rev') and opts.get('remove'):
5393 if opts.get('rev') and opts.get('remove'):
5390 raise util.Abort(_("--rev and --remove are incompatible"))
5394 raise util.Abort(_("--rev and --remove are incompatible"))
5391 if opts.get('rev'):
5395 if opts.get('rev'):
5392 rev_ = opts['rev']
5396 rev_ = opts['rev']
5393 message = opts.get('message')
5397 message = opts.get('message')
5394 if opts.get('remove'):
5398 if opts.get('remove'):
5395 expectedtype = opts.get('local') and 'local' or 'global'
5399 expectedtype = opts.get('local') and 'local' or 'global'
5396 for n in names:
5400 for n in names:
5397 if not repo.tagtype(n):
5401 if not repo.tagtype(n):
5398 raise util.Abort(_("tag '%s' does not exist") % n)
5402 raise util.Abort(_("tag '%s' does not exist") % n)
5399 if repo.tagtype(n) != expectedtype:
5403 if repo.tagtype(n) != expectedtype:
5400 if expectedtype == 'global':
5404 if expectedtype == 'global':
5401 raise util.Abort(_("tag '%s' is not a global tag") % n)
5405 raise util.Abort(_("tag '%s' is not a global tag") % n)
5402 else:
5406 else:
5403 raise util.Abort(_("tag '%s' is not a local tag") % n)
5407 raise util.Abort(_("tag '%s' is not a local tag") % n)
5404 rev_ = nullid
5408 rev_ = nullid
5405 if not message:
5409 if not message:
5406 # we don't translate commit messages
5410 # we don't translate commit messages
5407 message = 'Removed tag %s' % ', '.join(names)
5411 message = 'Removed tag %s' % ', '.join(names)
5408 elif not opts.get('force'):
5412 elif not opts.get('force'):
5409 for n in names:
5413 for n in names:
5410 if n in repo.tags():
5414 if n in repo.tags():
5411 raise util.Abort(_("tag '%s' already exists "
5415 raise util.Abort(_("tag '%s' already exists "
5412 "(use -f to force)") % n)
5416 "(use -f to force)") % n)
5413 if not opts.get('local'):
5417 if not opts.get('local'):
5414 p1, p2 = repo.dirstate.parents()
5418 p1, p2 = repo.dirstate.parents()
5415 if p2 != nullid:
5419 if p2 != nullid:
5416 raise util.Abort(_('uncommitted merge'))
5420 raise util.Abort(_('uncommitted merge'))
5417 bheads = repo.branchheads()
5421 bheads = repo.branchheads()
5418 if not opts.get('force') and bheads and p1 not in bheads:
5422 if not opts.get('force') and bheads and p1 not in bheads:
5419 raise util.Abort(_('not at a branch head (use -f to force)'))
5423 raise util.Abort(_('not at a branch head (use -f to force)'))
5420 r = scmutil.revsingle(repo, rev_).node()
5424 r = scmutil.revsingle(repo, rev_).node()
5421
5425
5422 if not message:
5426 if not message:
5423 # we don't translate commit messages
5427 # we don't translate commit messages
5424 message = ('Added tag %s for changeset %s' %
5428 message = ('Added tag %s for changeset %s' %
5425 (', '.join(names), short(r)))
5429 (', '.join(names), short(r)))
5426
5430
5427 date = opts.get('date')
5431 date = opts.get('date')
5428 if date:
5432 if date:
5429 date = util.parsedate(date)
5433 date = util.parsedate(date)
5430
5434
5431 if opts.get('edit'):
5435 if opts.get('edit'):
5432 message = ui.edit(message, ui.username())
5436 message = ui.edit(message, ui.username())
5433
5437
5434 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5438 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5435
5439
5436 @command('tags', [], '')
5440 @command('tags', [], '')
5437 def tags(ui, repo):
5441 def tags(ui, repo):
5438 """list repository tags
5442 """list repository tags
5439
5443
5440 This lists both regular and local tags. When the -v/--verbose
5444 This lists both regular and local tags. When the -v/--verbose
5441 switch is used, a third column "local" is printed for local tags.
5445 switch is used, a third column "local" is printed for local tags.
5442
5446
5443 Returns 0 on success.
5447 Returns 0 on success.
5444 """
5448 """
5445
5449
5446 hexfunc = ui.debugflag and hex or short
5450 hexfunc = ui.debugflag and hex or short
5447 tagtype = ""
5451 tagtype = ""
5448
5452
5449 for t, n in reversed(repo.tagslist()):
5453 for t, n in reversed(repo.tagslist()):
5450 if ui.quiet:
5454 if ui.quiet:
5451 ui.write("%s\n" % t, label='tags.normal')
5455 ui.write("%s\n" % t, label='tags.normal')
5452 continue
5456 continue
5453
5457
5454 hn = hexfunc(n)
5458 hn = hexfunc(n)
5455 r = "%5d:%s" % (repo.changelog.rev(n), hn)
5459 r = "%5d:%s" % (repo.changelog.rev(n), hn)
5456 rev = ui.label(r, 'log.changeset')
5460 rev = ui.label(r, 'log.changeset')
5457 spaces = " " * (30 - encoding.colwidth(t))
5461 spaces = " " * (30 - encoding.colwidth(t))
5458
5462
5459 tag = ui.label(t, 'tags.normal')
5463 tag = ui.label(t, 'tags.normal')
5460 if ui.verbose:
5464 if ui.verbose:
5461 if repo.tagtype(t) == 'local':
5465 if repo.tagtype(t) == 'local':
5462 tagtype = " local"
5466 tagtype = " local"
5463 tag = ui.label(t, 'tags.local')
5467 tag = ui.label(t, 'tags.local')
5464 else:
5468 else:
5465 tagtype = ""
5469 tagtype = ""
5466 ui.write("%s%s %s%s\n" % (tag, spaces, rev, tagtype))
5470 ui.write("%s%s %s%s\n" % (tag, spaces, rev, tagtype))
5467
5471
5468 @command('tip',
5472 @command('tip',
5469 [('p', 'patch', None, _('show patch')),
5473 [('p', 'patch', None, _('show patch')),
5470 ('g', 'git', None, _('use git extended diff format')),
5474 ('g', 'git', None, _('use git extended diff format')),
5471 ] + templateopts,
5475 ] + templateopts,
5472 _('[-p] [-g]'))
5476 _('[-p] [-g]'))
5473 def tip(ui, repo, **opts):
5477 def tip(ui, repo, **opts):
5474 """show the tip revision
5478 """show the tip revision
5475
5479
5476 The tip revision (usually just called the tip) is the changeset
5480 The tip revision (usually just called the tip) is the changeset
5477 most recently added to the repository (and therefore the most
5481 most recently added to the repository (and therefore the most
5478 recently changed head).
5482 recently changed head).
5479
5483
5480 If you have just made a commit, that commit will be the tip. If
5484 If you have just made a commit, that commit will be the tip. If
5481 you have just pulled changes from another repository, the tip of
5485 you have just pulled changes from another repository, the tip of
5482 that repository becomes the current tip. The "tip" tag is special
5486 that repository becomes the current tip. The "tip" tag is special
5483 and cannot be renamed or assigned to a different changeset.
5487 and cannot be renamed or assigned to a different changeset.
5484
5488
5485 Returns 0 on success.
5489 Returns 0 on success.
5486 """
5490 """
5487 displayer = cmdutil.show_changeset(ui, repo, opts)
5491 displayer = cmdutil.show_changeset(ui, repo, opts)
5488 displayer.show(repo[len(repo) - 1])
5492 displayer.show(repo[len(repo) - 1])
5489 displayer.close()
5493 displayer.close()
5490
5494
5491 @command('unbundle',
5495 @command('unbundle',
5492 [('u', 'update', None,
5496 [('u', 'update', None,
5493 _('update to new branch head if changesets were unbundled'))],
5497 _('update to new branch head if changesets were unbundled'))],
5494 _('[-u] FILE...'))
5498 _('[-u] FILE...'))
5495 def unbundle(ui, repo, fname1, *fnames, **opts):
5499 def unbundle(ui, repo, fname1, *fnames, **opts):
5496 """apply one or more changegroup files
5500 """apply one or more changegroup files
5497
5501
5498 Apply one or more compressed changegroup files generated by the
5502 Apply one or more compressed changegroup files generated by the
5499 bundle command.
5503 bundle command.
5500
5504
5501 Returns 0 on success, 1 if an update has unresolved files.
5505 Returns 0 on success, 1 if an update has unresolved files.
5502 """
5506 """
5503 fnames = (fname1,) + fnames
5507 fnames = (fname1,) + fnames
5504
5508
5505 lock = repo.lock()
5509 lock = repo.lock()
5506 wc = repo['.']
5510 wc = repo['.']
5507 try:
5511 try:
5508 for fname in fnames:
5512 for fname in fnames:
5509 f = url.open(ui, fname)
5513 f = url.open(ui, fname)
5510 gen = changegroup.readbundle(f, fname)
5514 gen = changegroup.readbundle(f, fname)
5511 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
5515 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
5512 lock=lock)
5516 lock=lock)
5513 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5517 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5514 finally:
5518 finally:
5515 lock.release()
5519 lock.release()
5516 return postincoming(ui, repo, modheads, opts.get('update'), None)
5520 return postincoming(ui, repo, modheads, opts.get('update'), None)
5517
5521
5518 @command('^update|up|checkout|co',
5522 @command('^update|up|checkout|co',
5519 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5523 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5520 ('c', 'check', None,
5524 ('c', 'check', None,
5521 _('update across branches if no uncommitted changes')),
5525 _('update across branches if no uncommitted changes')),
5522 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5526 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5523 ('r', 'rev', '', _('revision'), _('REV'))],
5527 ('r', 'rev', '', _('revision'), _('REV'))],
5524 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5528 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5525 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5529 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5526 """update working directory (or switch revisions)
5530 """update working directory (or switch revisions)
5527
5531
5528 Update the repository's working directory to the specified
5532 Update the repository's working directory to the specified
5529 changeset. If no changeset is specified, update to the tip of the
5533 changeset. If no changeset is specified, update to the tip of the
5530 current named branch.
5534 current named branch.
5531
5535
5532 If the changeset is not a descendant of the working directory's
5536 If the changeset is not a descendant of the working directory's
5533 parent, the update is aborted. With the -c/--check option, the
5537 parent, the update is aborted. With the -c/--check option, the
5534 working directory is checked for uncommitted changes; if none are
5538 working directory is checked for uncommitted changes; if none are
5535 found, the working directory is updated to the specified
5539 found, the working directory is updated to the specified
5536 changeset.
5540 changeset.
5537
5541
5538 Update sets the working directory's parent revison to the specified
5542 Update sets the working directory's parent revison to the specified
5539 changeset (see :hg:`help parents`).
5543 changeset (see :hg:`help parents`).
5540
5544
5541 The following rules apply when the working directory contains
5545 The following rules apply when the working directory contains
5542 uncommitted changes:
5546 uncommitted changes:
5543
5547
5544 1. If neither -c/--check nor -C/--clean is specified, and if
5548 1. If neither -c/--check nor -C/--clean is specified, and if
5545 the requested changeset is an ancestor or descendant of
5549 the requested changeset is an ancestor or descendant of
5546 the working directory's parent, the uncommitted changes
5550 the working directory's parent, the uncommitted changes
5547 are merged into the requested changeset and the merged
5551 are merged into the requested changeset and the merged
5548 result is left uncommitted. If the requested changeset is
5552 result is left uncommitted. If the requested changeset is
5549 not an ancestor or descendant (that is, it is on another
5553 not an ancestor or descendant (that is, it is on another
5550 branch), the update is aborted and the uncommitted changes
5554 branch), the update is aborted and the uncommitted changes
5551 are preserved.
5555 are preserved.
5552
5556
5553 2. With the -c/--check option, the update is aborted and the
5557 2. With the -c/--check option, the update is aborted and the
5554 uncommitted changes are preserved.
5558 uncommitted changes are preserved.
5555
5559
5556 3. With the -C/--clean option, uncommitted changes are discarded and
5560 3. With the -C/--clean option, uncommitted changes are discarded and
5557 the working directory is updated to the requested changeset.
5561 the working directory is updated to the requested changeset.
5558
5562
5559 Use null as the changeset to remove the working directory (like
5563 Use null as the changeset to remove the working directory (like
5560 :hg:`clone -U`).
5564 :hg:`clone -U`).
5561
5565
5562 If you want to revert just one file to an older revision, use
5566 If you want to revert just one file to an older revision, use
5563 :hg:`revert [-r REV] NAME`.
5567 :hg:`revert [-r REV] NAME`.
5564
5568
5565 See :hg:`help dates` for a list of formats valid for -d/--date.
5569 See :hg:`help dates` for a list of formats valid for -d/--date.
5566
5570
5567 Returns 0 on success, 1 if there are unresolved files.
5571 Returns 0 on success, 1 if there are unresolved files.
5568 """
5572 """
5569 if rev and node:
5573 if rev and node:
5570 raise util.Abort(_("please specify just one revision"))
5574 raise util.Abort(_("please specify just one revision"))
5571
5575
5572 if rev is None or rev == '':
5576 if rev is None or rev == '':
5573 rev = node
5577 rev = node
5574
5578
5575 # if we defined a bookmark, we have to remember the original bookmark name
5579 # if we defined a bookmark, we have to remember the original bookmark name
5576 brev = rev
5580 brev = rev
5577 rev = scmutil.revsingle(repo, rev, rev).rev()
5581 rev = scmutil.revsingle(repo, rev, rev).rev()
5578
5582
5579 if check and clean:
5583 if check and clean:
5580 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5584 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5581
5585
5582 if check:
5586 if check:
5583 # we could use dirty() but we can ignore merge and branch trivia
5587 # we could use dirty() but we can ignore merge and branch trivia
5584 c = repo[None]
5588 c = repo[None]
5585 if c.modified() or c.added() or c.removed():
5589 if c.modified() or c.added() or c.removed():
5586 raise util.Abort(_("uncommitted local changes"))
5590 raise util.Abort(_("uncommitted local changes"))
5587
5591
5588 if date:
5592 if date:
5589 if rev is not None:
5593 if rev is not None:
5590 raise util.Abort(_("you can't specify a revision and a date"))
5594 raise util.Abort(_("you can't specify a revision and a date"))
5591 rev = cmdutil.finddate(ui, repo, date)
5595 rev = cmdutil.finddate(ui, repo, date)
5592
5596
5593 if clean or check:
5597 if clean or check:
5594 ret = hg.clean(repo, rev)
5598 ret = hg.clean(repo, rev)
5595 else:
5599 else:
5596 ret = hg.update(repo, rev)
5600 ret = hg.update(repo, rev)
5597
5601
5598 if brev in repo._bookmarks:
5602 if brev in repo._bookmarks:
5599 bookmarks.setcurrent(repo, brev)
5603 bookmarks.setcurrent(repo, brev)
5600
5604
5601 return ret
5605 return ret
5602
5606
5603 @command('verify', [])
5607 @command('verify', [])
5604 def verify(ui, repo):
5608 def verify(ui, repo):
5605 """verify the integrity of the repository
5609 """verify the integrity of the repository
5606
5610
5607 Verify the integrity of the current repository.
5611 Verify the integrity of the current repository.
5608
5612
5609 This will perform an extensive check of the repository's
5613 This will perform an extensive check of the repository's
5610 integrity, validating the hashes and checksums of each entry in
5614 integrity, validating the hashes and checksums of each entry in
5611 the changelog, manifest, and tracked files, as well as the
5615 the changelog, manifest, and tracked files, as well as the
5612 integrity of their crosslinks and indices.
5616 integrity of their crosslinks and indices.
5613
5617
5614 Returns 0 on success, 1 if errors are encountered.
5618 Returns 0 on success, 1 if errors are encountered.
5615 """
5619 """
5616 return hg.verify(repo)
5620 return hg.verify(repo)
5617
5621
5618 @command('version', [])
5622 @command('version', [])
5619 def version_(ui):
5623 def version_(ui):
5620 """output version and copyright information"""
5624 """output version and copyright information"""
5621 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5625 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5622 % util.version())
5626 % util.version())
5623 ui.status(_(
5627 ui.status(_(
5624 "(see http://mercurial.selenic.com for more information)\n"
5628 "(see http://mercurial.selenic.com for more information)\n"
5625 "\nCopyright (C) 2005-2011 Matt Mackall and others\n"
5629 "\nCopyright (C) 2005-2011 Matt Mackall and others\n"
5626 "This is free software; see the source for copying conditions. "
5630 "This is free software; see the source for copying conditions. "
5627 "There is NO\nwarranty; "
5631 "There is NO\nwarranty; "
5628 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5632 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5629 ))
5633 ))
5630
5634
5631 norepo = ("clone init version help debugcommands debugcomplete"
5635 norepo = ("clone init version help debugcommands debugcomplete"
5632 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5636 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5633 " debugknown debuggetbundle debugbundle")
5637 " debugknown debuggetbundle debugbundle")
5634 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5638 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5635 " debugdata debugindex debugindexdot debugrevlog")
5639 " debugdata debugindex debugindexdot debugrevlog")
@@ -1,1312 +1,1312 b''
1 The Mercurial system uses a set of configuration files to control
1 The Mercurial system uses a set of configuration files to control
2 aspects of its behavior.
2 aspects of its behavior.
3
3
4 The configuration files use a simple ini-file format. A configuration
4 The configuration files use a simple ini-file format. A configuration
5 file consists of sections, led by a ``[section]`` header and followed
5 file consists of sections, led by a ``[section]`` header and followed
6 by ``name = value`` entries::
6 by ``name = value`` entries::
7
7
8 [ui]
8 [ui]
9 username = Firstname Lastname <firstname.lastname@example.net>
9 username = Firstname Lastname <firstname.lastname@example.net>
10 verbose = True
10 verbose = True
11
11
12 The above entries will be referred to as ``ui.username`` and
12 The above entries will be referred to as ``ui.username`` and
13 ``ui.verbose``, respectively. See the Syntax section below.
13 ``ui.verbose``, respectively. See the Syntax section below.
14
14
15 Files
15 Files
16 -----
16 -----
17
17
18 Mercurial reads configuration data from several files, if they exist.
18 Mercurial reads configuration data from several files, if they exist.
19 These files do not exist by default and you will have to create the
19 These files do not exist by default and you will have to create the
20 appropriate configuration files yourself: global configuration like
20 appropriate configuration files yourself: global configuration like
21 the username setting is typically put into
21 the username setting is typically put into
22 ``%USERPROFILE%\mercurial.ini`` or ``$HOME/.hgrc`` and local
22 ``%USERPROFILE%\mercurial.ini`` or ``$HOME/.hgrc`` and local
23 configuration is put into the per-repository ``<repo>/.hg/hgrc`` file.
23 configuration is put into the per-repository ``<repo>/.hg/hgrc`` file.
24
24
25 The names of these files depend on the system on which Mercurial is
25 The names of these files depend on the system on which Mercurial is
26 installed. ``*.rc`` files from a single directory are read in
26 installed. ``*.rc`` files from a single directory are read in
27 alphabetical order, later ones overriding earlier ones. Where multiple
27 alphabetical order, later ones overriding earlier ones. Where multiple
28 paths are given below, settings from earlier paths override later
28 paths are given below, settings from earlier paths override later
29 ones.
29 ones.
30
30
31 | (Unix, Windows) ``<repo>/.hg/hgrc``
31 | (Unix, Windows) ``<repo>/.hg/hgrc``
32
32
33 Per-repository configuration options that only apply in a
33 Per-repository configuration options that only apply in a
34 particular repository. This file is not version-controlled, and
34 particular repository. This file is not version-controlled, and
35 will not get transferred during a "clone" operation. Options in
35 will not get transferred during a "clone" operation. Options in
36 this file override options in all other configuration files. On
36 this file override options in all other configuration files. On
37 Unix, most of this file will be ignored if it doesn't belong to a
37 Unix, most of this file will be ignored if it doesn't belong to a
38 trusted user or to a trusted group. See the documentation for the
38 trusted user or to a trusted group. See the documentation for the
39 ``[trusted]`` section below for more details.
39 ``[trusted]`` section below for more details.
40
40
41 | (Unix) ``$HOME/.hgrc``
41 | (Unix) ``$HOME/.hgrc``
42 | (Windows) ``%USERPROFILE%\.hgrc``
42 | (Windows) ``%USERPROFILE%\.hgrc``
43 | (Windows) ``%USERPROFILE%\Mercurial.ini``
43 | (Windows) ``%USERPROFILE%\Mercurial.ini``
44 | (Windows) ``%HOME%\.hgrc``
44 | (Windows) ``%HOME%\.hgrc``
45 | (Windows) ``%HOME%\Mercurial.ini``
45 | (Windows) ``%HOME%\Mercurial.ini``
46
46
47 Per-user configuration file(s), for the user running Mercurial. On
47 Per-user configuration file(s), for the user running Mercurial. On
48 Windows 9x, ``%HOME%`` is replaced by ``%APPDATA%``. Options in these
48 Windows 9x, ``%HOME%`` is replaced by ``%APPDATA%``. Options in these
49 files apply to all Mercurial commands executed by this user in any
49 files apply to all Mercurial commands executed by this user in any
50 directory. Options in these files override per-system and per-installation
50 directory. Options in these files override per-system and per-installation
51 options.
51 options.
52
52
53 | (Unix) ``/etc/mercurial/hgrc``
53 | (Unix) ``/etc/mercurial/hgrc``
54 | (Unix) ``/etc/mercurial/hgrc.d/*.rc``
54 | (Unix) ``/etc/mercurial/hgrc.d/*.rc``
55
55
56 Per-system configuration files, for the system on which Mercurial
56 Per-system configuration files, for the system on which Mercurial
57 is running. Options in these files apply to all Mercurial commands
57 is running. Options in these files apply to all Mercurial commands
58 executed by any user in any directory. Options in these files
58 executed by any user in any directory. Options in these files
59 override per-installation options.
59 override per-installation options.
60
60
61 | (Unix) ``<install-root>/etc/mercurial/hgrc``
61 | (Unix) ``<install-root>/etc/mercurial/hgrc``
62 | (Unix) ``<install-root>/etc/mercurial/hgrc.d/*.rc``
62 | (Unix) ``<install-root>/etc/mercurial/hgrc.d/*.rc``
63
63
64 Per-installation configuration files, searched for in the
64 Per-installation configuration files, searched for in the
65 directory where Mercurial is installed. ``<install-root>`` is the
65 directory where Mercurial is installed. ``<install-root>`` is the
66 parent directory of the **hg** executable (or symlink) being run. For
66 parent directory of the **hg** executable (or symlink) being run. For
67 example, if installed in ``/shared/tools/bin/hg``, Mercurial will look
67 example, if installed in ``/shared/tools/bin/hg``, Mercurial will look
68 in ``/shared/tools/etc/mercurial/hgrc``. Options in these files apply
68 in ``/shared/tools/etc/mercurial/hgrc``. Options in these files apply
69 to all Mercurial commands executed by any user in any directory.
69 to all Mercurial commands executed by any user in any directory.
70
70
71 | (Windows) ``<install-dir>\Mercurial.ini`` **or**
71 | (Windows) ``<install-dir>\Mercurial.ini`` **or**
72 | (Windows) ``<install-dir>\hgrc.d\*.rc`` **or**
72 | (Windows) ``<install-dir>\hgrc.d\*.rc`` **or**
73 | (Windows) ``HKEY_LOCAL_MACHINE\SOFTWARE\Mercurial``
73 | (Windows) ``HKEY_LOCAL_MACHINE\SOFTWARE\Mercurial``
74
74
75 Per-installation/system configuration files, for the system on
75 Per-installation/system configuration files, for the system on
76 which Mercurial is running. Options in these files apply to all
76 which Mercurial is running. Options in these files apply to all
77 Mercurial commands executed by any user in any directory. Registry
77 Mercurial commands executed by any user in any directory. Registry
78 keys contain PATH-like strings, every part of which must reference
78 keys contain PATH-like strings, every part of which must reference
79 a ``Mercurial.ini`` file or be a directory where ``*.rc`` files will
79 a ``Mercurial.ini`` file or be a directory where ``*.rc`` files will
80 be read. Mercurial checks each of these locations in the specified
80 be read. Mercurial checks each of these locations in the specified
81 order until one or more configuration files are detected. If the
81 order until one or more configuration files are detected. If the
82 pywin32 extensions are not installed, Mercurial will only look for
82 pywin32 extensions are not installed, Mercurial will only look for
83 site-wide configuration in ``C:\Mercurial\Mercurial.ini``.
83 site-wide configuration in ``C:\Mercurial\Mercurial.ini``.
84
84
85 Syntax
85 Syntax
86 ------
86 ------
87
87
88 A configuration file consists of sections, led by a ``[section]`` header
88 A configuration file consists of sections, led by a ``[section]`` header
89 and followed by ``name = value`` entries (sometimes called
89 and followed by ``name = value`` entries (sometimes called
90 ``configuration keys``)::
90 ``configuration keys``)::
91
91
92 [spam]
92 [spam]
93 eggs=ham
93 eggs=ham
94 green=
94 green=
95 eggs
95 eggs
96
96
97 Each line contains one entry. If the lines that follow are indented,
97 Each line contains one entry. If the lines that follow are indented,
98 they are treated as continuations of that entry. Leading whitespace is
98 they are treated as continuations of that entry. Leading whitespace is
99 removed from values. Empty lines are skipped. Lines beginning with
99 removed from values. Empty lines are skipped. Lines beginning with
100 ``#`` or ``;`` are ignored and may be used to provide comments.
100 ``#`` or ``;`` are ignored and may be used to provide comments.
101
101
102 Configuration keys can be set multiple times, in which case Mercurial
102 Configuration keys can be set multiple times, in which case Mercurial
103 will use the value that was configured last. As an example::
103 will use the value that was configured last. As an example::
104
104
105 [spam]
105 [spam]
106 eggs=large
106 eggs=large
107 ham=serrano
107 ham=serrano
108 eggs=small
108 eggs=small
109
109
110 This would set the configuration key named ``eggs`` to ``small``.
110 This would set the configuration key named ``eggs`` to ``small``.
111
111
112 It is also possible to define a section multiple times. A section can
112 It is also possible to define a section multiple times. A section can
113 be redefined on the same and/or on different configuration files. For
113 be redefined on the same and/or on different configuration files. For
114 example::
114 example::
115
115
116 [foo]
116 [foo]
117 eggs=large
117 eggs=large
118 ham=serrano
118 ham=serrano
119 eggs=small
119 eggs=small
120
120
121 [bar]
121 [bar]
122 eggs=ham
122 eggs=ham
123 green=
123 green=
124 eggs
124 eggs
125
125
126 [foo]
126 [foo]
127 ham=prosciutto
127 ham=prosciutto
128 eggs=medium
128 eggs=medium
129 bread=toasted
129 bread=toasted
130
130
131 This would set the ``eggs``, ``ham``, and ``bread`` configuration keys
131 This would set the ``eggs``, ``ham``, and ``bread`` configuration keys
132 of the ``foo`` section to ``medium``, ``prosciutto``, and ``toasted``,
132 of the ``foo`` section to ``medium``, ``prosciutto``, and ``toasted``,
133 respectively. As you can see there only thing that matters is the last
133 respectively. As you can see there only thing that matters is the last
134 value that was set for each of the configuration keys.
134 value that was set for each of the configuration keys.
135
135
136 If a configuration key is set multiple times in different
136 If a configuration key is set multiple times in different
137 configuration files the final value will depend on the order in which
137 configuration files the final value will depend on the order in which
138 the different configuration files are read, with settings from earlier
138 the different configuration files are read, with settings from earlier
139 paths overriding later ones as described on the ``Files`` section
139 paths overriding later ones as described on the ``Files`` section
140 above.
140 above.
141
141
142 A line of the form ``%include file`` will include ``file`` into the
142 A line of the form ``%include file`` will include ``file`` into the
143 current configuration file. The inclusion is recursive, which means
143 current configuration file. The inclusion is recursive, which means
144 that included files can include other files. Filenames are relative to
144 that included files can include other files. Filenames are relative to
145 the configuration file in which the ``%include`` directive is found.
145 the configuration file in which the ``%include`` directive is found.
146 Environment variables and ``~user`` constructs are expanded in
146 Environment variables and ``~user`` constructs are expanded in
147 ``file``. This lets you do something like::
147 ``file``. This lets you do something like::
148
148
149 %include ~/.hgrc.d/$HOST.rc
149 %include ~/.hgrc.d/$HOST.rc
150
150
151 to include a different configuration file on each computer you use.
151 to include a different configuration file on each computer you use.
152
152
153 A line with ``%unset name`` will remove ``name`` from the current
153 A line with ``%unset name`` will remove ``name`` from the current
154 section, if it has been set previously.
154 section, if it has been set previously.
155
155
156 The values are either free-form text strings, lists of text strings,
156 The values are either free-form text strings, lists of text strings,
157 or Boolean values. Boolean values can be set to true using any of "1",
157 or Boolean values. Boolean values can be set to true using any of "1",
158 "yes", "true", or "on" and to false using "0", "no", "false", or "off"
158 "yes", "true", or "on" and to false using "0", "no", "false", or "off"
159 (all case insensitive).
159 (all case insensitive).
160
160
161 List values are separated by whitespace or comma, except when values are
161 List values are separated by whitespace or comma, except when values are
162 placed in double quotation marks::
162 placed in double quotation marks::
163
163
164 allow_read = "John Doe, PhD", brian, betty
164 allow_read = "John Doe, PhD", brian, betty
165
165
166 Quotation marks can be escaped by prefixing them with a backslash. Only
166 Quotation marks can be escaped by prefixing them with a backslash. Only
167 quotation marks at the beginning of a word is counted as a quotation
167 quotation marks at the beginning of a word is counted as a quotation
168 (e.g., ``foo"bar baz`` is the list of ``foo"bar`` and ``baz``).
168 (e.g., ``foo"bar baz`` is the list of ``foo"bar`` and ``baz``).
169
169
170 Sections
170 Sections
171 --------
171 --------
172
172
173 This section describes the different sections that may appear in a
173 This section describes the different sections that may appear in a
174 Mercurial configuration file, the purpose of each section, its possible
174 Mercurial configuration file, the purpose of each section, its possible
175 keys, and their possible values.
175 keys, and their possible values.
176
176
177 ``alias``
177 ``alias``
178 """""""""
178 """""""""
179
179
180 Defines command aliases.
180 Defines command aliases.
181 Aliases allow you to define your own commands in terms of other
181 Aliases allow you to define your own commands in terms of other
182 commands (or aliases), optionally including arguments. Positional
182 commands (or aliases), optionally including arguments. Positional
183 arguments in the form of ``$1``, ``$2``, etc in the alias definition
183 arguments in the form of ``$1``, ``$2``, etc in the alias definition
184 are expanded by Mercurial before execution. Positional arguments not
184 are expanded by Mercurial before execution. Positional arguments not
185 already used by ``$N`` in the definition are put at the end of the
185 already used by ``$N`` in the definition are put at the end of the
186 command to be executed.
186 command to be executed.
187
187
188 Alias definitions consist of lines of the form::
188 Alias definitions consist of lines of the form::
189
189
190 <alias> = <command> [<argument>]...
190 <alias> = <command> [<argument>]...
191
191
192 For example, this definition::
192 For example, this definition::
193
193
194 latest = log --limit 5
194 latest = log --limit 5
195
195
196 creates a new command ``latest`` that shows only the five most recent
196 creates a new command ``latest`` that shows only the five most recent
197 changesets. You can define subsequent aliases using earlier ones::
197 changesets. You can define subsequent aliases using earlier ones::
198
198
199 stable5 = latest -b stable
199 stable5 = latest -b stable
200
200
201 .. note:: It is possible to create aliases with the same names as
201 .. note:: It is possible to create aliases with the same names as
202 existing commands, which will then override the original
202 existing commands, which will then override the original
203 definitions. This is almost always a bad idea!
203 definitions. This is almost always a bad idea!
204
204
205 An alias can start with an exclamation point (``!``) to make it a
205 An alias can start with an exclamation point (``!``) to make it a
206 shell alias. A shell alias is executed with the shell and will let you
206 shell alias. A shell alias is executed with the shell and will let you
207 run arbitrary commands. As an example, ::
207 run arbitrary commands. As an example, ::
208
208
209 echo = !echo
209 echo = !echo
210
210
211 will let you do ``hg echo foo`` to have ``foo`` printed in your
211 will let you do ``hg echo foo`` to have ``foo`` printed in your
212 terminal. A better example might be::
212 terminal. A better example might be::
213
213
214 purge = !$HG status --no-status --unknown -0 | xargs -0 rm
214 purge = !$HG status --no-status --unknown -0 | xargs -0 rm
215
215
216 which will make ``hg purge`` delete all unknown files in the
216 which will make ``hg purge`` delete all unknown files in the
217 repository in the same manner as the purge extension.
217 repository in the same manner as the purge extension.
218
218
219 Shell aliases are executed in an environment where ``$HG`` expand to
219 Shell aliases are executed in an environment where ``$HG`` expand to
220 the path of the Mercurial that was used to execute the alias. This is
220 the path of the Mercurial that was used to execute the alias. This is
221 useful when you want to call further Mercurial commands in a shell
221 useful when you want to call further Mercurial commands in a shell
222 alias, as was done above for the purge alias. In addition,
222 alias, as was done above for the purge alias. In addition,
223 ``$HG_ARGS`` expand to the arguments given to Mercurial. In the ``hg
223 ``$HG_ARGS`` expand to the arguments given to Mercurial. In the ``hg
224 echo foo`` call above, ``$HG_ARGS`` would expand to ``echo foo``.
224 echo foo`` call above, ``$HG_ARGS`` would expand to ``echo foo``.
225
225
226 .. note:: Some global configuration options such as ``-R`` are
226 .. note:: Some global configuration options such as ``-R`` are
227 processed before shell aliases and will thus not be passed to
227 processed before shell aliases and will thus not be passed to
228 aliases.
228 aliases.
229
229
230 ``auth``
230 ``auth``
231 """"""""
231 """"""""
232
232
233 Authentication credentials for HTTP authentication. This section
233 Authentication credentials for HTTP authentication. This section
234 allows you to store usernames and passwords for use when logging
234 allows you to store usernames and passwords for use when logging
235 *into* HTTP servers. See the ``[web]`` configuration section if
235 *into* HTTP servers. See the ``[web]`` configuration section if
236 you want to configure *who* can login to your HTTP server.
236 you want to configure *who* can login to your HTTP server.
237
237
238 Each line has the following format::
238 Each line has the following format::
239
239
240 <name>.<argument> = <value>
240 <name>.<argument> = <value>
241
241
242 where ``<name>`` is used to group arguments into authentication
242 where ``<name>`` is used to group arguments into authentication
243 entries. Example::
243 entries. Example::
244
244
245 foo.prefix = hg.intevation.org/mercurial
245 foo.prefix = hg.intevation.org/mercurial
246 foo.username = foo
246 foo.username = foo
247 foo.password = bar
247 foo.password = bar
248 foo.schemes = http https
248 foo.schemes = http https
249
249
250 bar.prefix = secure.example.org
250 bar.prefix = secure.example.org
251 bar.key = path/to/file.key
251 bar.key = path/to/file.key
252 bar.cert = path/to/file.cert
252 bar.cert = path/to/file.cert
253 bar.schemes = https
253 bar.schemes = https
254
254
255 Supported arguments:
255 Supported arguments:
256
256
257 ``prefix``
257 ``prefix``
258 Either ``*`` or a URI prefix with or without the scheme part.
258 Either ``*`` or a URI prefix with or without the scheme part.
259 The authentication entry with the longest matching prefix is used
259 The authentication entry with the longest matching prefix is used
260 (where ``*`` matches everything and counts as a match of length
260 (where ``*`` matches everything and counts as a match of length
261 1). If the prefix doesn't include a scheme, the match is performed
261 1). If the prefix doesn't include a scheme, the match is performed
262 against the URI with its scheme stripped as well, and the schemes
262 against the URI with its scheme stripped as well, and the schemes
263 argument, q.v., is then subsequently consulted.
263 argument, q.v., is then subsequently consulted.
264
264
265 ``username``
265 ``username``
266 Optional. Username to authenticate with. If not given, and the
266 Optional. Username to authenticate with. If not given, and the
267 remote site requires basic or digest authentication, the user will
267 remote site requires basic or digest authentication, the user will
268 be prompted for it. Environment variables are expanded in the
268 be prompted for it. Environment variables are expanded in the
269 username letting you do ``foo.username = $USER``. If the URI
269 username letting you do ``foo.username = $USER``. If the URI
270 includes a username, only ``[auth]`` entries with a matching
270 includes a username, only ``[auth]`` entries with a matching
271 username or without a username will be considered.
271 username or without a username will be considered.
272
272
273 ``password``
273 ``password``
274 Optional. Password to authenticate with. If not given, and the
274 Optional. Password to authenticate with. If not given, and the
275 remote site requires basic or digest authentication, the user
275 remote site requires basic or digest authentication, the user
276 will be prompted for it.
276 will be prompted for it.
277
277
278 ``key``
278 ``key``
279 Optional. PEM encoded client certificate key file. Environment
279 Optional. PEM encoded client certificate key file. Environment
280 variables are expanded in the filename.
280 variables are expanded in the filename.
281
281
282 ``cert``
282 ``cert``
283 Optional. PEM encoded client certificate chain file. Environment
283 Optional. PEM encoded client certificate chain file. Environment
284 variables are expanded in the filename.
284 variables are expanded in the filename.
285
285
286 ``schemes``
286 ``schemes``
287 Optional. Space separated list of URI schemes to use this
287 Optional. Space separated list of URI schemes to use this
288 authentication entry with. Only used if the prefix doesn't include
288 authentication entry with. Only used if the prefix doesn't include
289 a scheme. Supported schemes are http and https. They will match
289 a scheme. Supported schemes are http and https. They will match
290 static-http and static-https respectively, as well.
290 static-http and static-https respectively, as well.
291 Default: https.
291 Default: https.
292
292
293 If no suitable authentication entry is found, the user is prompted
293 If no suitable authentication entry is found, the user is prompted
294 for credentials as usual if required by the remote.
294 for credentials as usual if required by the remote.
295
295
296
296
297 ``decode/encode``
297 ``decode/encode``
298 """""""""""""""""
298 """""""""""""""""
299
299
300 Filters for transforming files on checkout/checkin. This would
300 Filters for transforming files on checkout/checkin. This would
301 typically be used for newline processing or other
301 typically be used for newline processing or other
302 localization/canonicalization of files.
302 localization/canonicalization of files.
303
303
304 Filters consist of a filter pattern followed by a filter command.
304 Filters consist of a filter pattern followed by a filter command.
305 Filter patterns are globs by default, rooted at the repository root.
305 Filter patterns are globs by default, rooted at the repository root.
306 For example, to match any file ending in ``.txt`` in the root
306 For example, to match any file ending in ``.txt`` in the root
307 directory only, use the pattern ``*.txt``. To match any file ending
307 directory only, use the pattern ``*.txt``. To match any file ending
308 in ``.c`` anywhere in the repository, use the pattern ``**.c``.
308 in ``.c`` anywhere in the repository, use the pattern ``**.c``.
309 For each file only the first matching filter applies.
309 For each file only the first matching filter applies.
310
310
311 The filter command can start with a specifier, either ``pipe:`` or
311 The filter command can start with a specifier, either ``pipe:`` or
312 ``tempfile:``. If no specifier is given, ``pipe:`` is used by default.
312 ``tempfile:``. If no specifier is given, ``pipe:`` is used by default.
313
313
314 A ``pipe:`` command must accept data on stdin and return the transformed
314 A ``pipe:`` command must accept data on stdin and return the transformed
315 data on stdout.
315 data on stdout.
316
316
317 Pipe example::
317 Pipe example::
318
318
319 [encode]
319 [encode]
320 # uncompress gzip files on checkin to improve delta compression
320 # uncompress gzip files on checkin to improve delta compression
321 # note: not necessarily a good idea, just an example
321 # note: not necessarily a good idea, just an example
322 *.gz = pipe: gunzip
322 *.gz = pipe: gunzip
323
323
324 [decode]
324 [decode]
325 # recompress gzip files when writing them to the working dir (we
325 # recompress gzip files when writing them to the working dir (we
326 # can safely omit "pipe:", because it's the default)
326 # can safely omit "pipe:", because it's the default)
327 *.gz = gzip
327 *.gz = gzip
328
328
329 A ``tempfile:`` command is a template. The string ``INFILE`` is replaced
329 A ``tempfile:`` command is a template. The string ``INFILE`` is replaced
330 with the name of a temporary file that contains the data to be
330 with the name of a temporary file that contains the data to be
331 filtered by the command. The string ``OUTFILE`` is replaced with the name
331 filtered by the command. The string ``OUTFILE`` is replaced with the name
332 of an empty temporary file, where the filtered data must be written by
332 of an empty temporary file, where the filtered data must be written by
333 the command.
333 the command.
334
334
335 .. note:: The tempfile mechanism is recommended for Windows systems,
335 .. note:: The tempfile mechanism is recommended for Windows systems,
336 where the standard shell I/O redirection operators often have
336 where the standard shell I/O redirection operators often have
337 strange effects and may corrupt the contents of your files.
337 strange effects and may corrupt the contents of your files.
338
338
339 This filter mechanism is used internally by the ``eol`` extension to
339 This filter mechanism is used internally by the ``eol`` extension to
340 translate line ending characters between Windows (CRLF) and Unix (LF)
340 translate line ending characters between Windows (CRLF) and Unix (LF)
341 format. We suggest you use the ``eol`` extension for convenience.
341 format. We suggest you use the ``eol`` extension for convenience.
342
342
343
343
344 ``defaults``
344 ``defaults``
345 """"""""""""
345 """"""""""""
346
346
347 (defaults are deprecated. Don't use them. Use aliases instead)
347 (defaults are deprecated. Don't use them. Use aliases instead)
348
348
349 Use the ``[defaults]`` section to define command defaults, i.e. the
349 Use the ``[defaults]`` section to define command defaults, i.e. the
350 default options/arguments to pass to the specified commands.
350 default options/arguments to pass to the specified commands.
351
351
352 The following example makes :hg:`log` run in verbose mode, and
352 The following example makes :hg:`log` run in verbose mode, and
353 :hg:`status` show only the modified files, by default::
353 :hg:`status` show only the modified files, by default::
354
354
355 [defaults]
355 [defaults]
356 log = -v
356 log = -v
357 status = -m
357 status = -m
358
358
359 The actual commands, instead of their aliases, must be used when
359 The actual commands, instead of their aliases, must be used when
360 defining command defaults. The command defaults will also be applied
360 defining command defaults. The command defaults will also be applied
361 to the aliases of the commands defined.
361 to the aliases of the commands defined.
362
362
363
363
364 ``diff``
364 ``diff``
365 """"""""
365 """"""""
366
366
367 Settings used when displaying diffs. Everything except for ``unified`` is a
367 Settings used when displaying diffs. Everything except for ``unified`` is a
368 Boolean and defaults to False.
368 Boolean and defaults to False.
369
369
370 ``git``
370 ``git``
371 Use git extended diff format.
371 Use git extended diff format.
372
372
373 ``nodates``
373 ``nodates``
374 Don't include dates in diff headers.
374 Don't include dates in diff headers.
375
375
376 ``showfunc``
376 ``showfunc``
377 Show which function each change is in.
377 Show which function each change is in.
378
378
379 ``ignorews``
379 ``ignorews``
380 Ignore white space when comparing lines.
380 Ignore white space when comparing lines.
381
381
382 ``ignorewsamount``
382 ``ignorewsamount``
383 Ignore changes in the amount of white space.
383 Ignore changes in the amount of white space.
384
384
385 ``ignoreblanklines``
385 ``ignoreblanklines``
386 Ignore changes whose lines are all blank.
386 Ignore changes whose lines are all blank.
387
387
388 ``unified``
388 ``unified``
389 Number of lines of context to show.
389 Number of lines of context to show.
390
390
391 ``email``
391 ``email``
392 """""""""
392 """""""""
393
393
394 Settings for extensions that send email messages.
394 Settings for extensions that send email messages.
395
395
396 ``from``
396 ``from``
397 Optional. Email address to use in "From" header and SMTP envelope
397 Optional. Email address to use in "From" header and SMTP envelope
398 of outgoing messages.
398 of outgoing messages.
399
399
400 ``to``
400 ``to``
401 Optional. Comma-separated list of recipients' email addresses.
401 Optional. Comma-separated list of recipients' email addresses.
402
402
403 ``cc``
403 ``cc``
404 Optional. Comma-separated list of carbon copy recipients'
404 Optional. Comma-separated list of carbon copy recipients'
405 email addresses.
405 email addresses.
406
406
407 ``bcc``
407 ``bcc``
408 Optional. Comma-separated list of blind carbon copy recipients'
408 Optional. Comma-separated list of blind carbon copy recipients'
409 email addresses.
409 email addresses.
410
410
411 ``method``
411 ``method``
412 Optional. Method to use to send email messages. If value is ``smtp``
412 Optional. Method to use to send email messages. If value is ``smtp``
413 (default), use SMTP (see the ``[smtp]`` section for configuration).
413 (default), use SMTP (see the ``[smtp]`` section for configuration).
414 Otherwise, use as name of program to run that acts like sendmail
414 Otherwise, use as name of program to run that acts like sendmail
415 (takes ``-f`` option for sender, list of recipients on command line,
415 (takes ``-f`` option for sender, list of recipients on command line,
416 message on stdin). Normally, setting this to ``sendmail`` or
416 message on stdin). Normally, setting this to ``sendmail`` or
417 ``/usr/sbin/sendmail`` is enough to use sendmail to send messages.
417 ``/usr/sbin/sendmail`` is enough to use sendmail to send messages.
418
418
419 ``charsets``
419 ``charsets``
420 Optional. Comma-separated list of character sets considered
420 Optional. Comma-separated list of character sets considered
421 convenient for recipients. Addresses, headers, and parts not
421 convenient for recipients. Addresses, headers, and parts not
422 containing patches of outgoing messages will be encoded in the
422 containing patches of outgoing messages will be encoded in the
423 first character set to which conversion from local encoding
423 first character set to which conversion from local encoding
424 (``$HGENCODING``, ``ui.fallbackencoding``) succeeds. If correct
424 (``$HGENCODING``, ``ui.fallbackencoding``) succeeds. If correct
425 conversion fails, the text in question is sent as is. Defaults to
425 conversion fails, the text in question is sent as is. Defaults to
426 empty (explicit) list.
426 empty (explicit) list.
427
427
428 Order of outgoing email character sets:
428 Order of outgoing email character sets:
429
429
430 1. ``us-ascii``: always first, regardless of settings
430 1. ``us-ascii``: always first, regardless of settings
431 2. ``email.charsets``: in order given by user
431 2. ``email.charsets``: in order given by user
432 3. ``ui.fallbackencoding``: if not in email.charsets
432 3. ``ui.fallbackencoding``: if not in email.charsets
433 4. ``$HGENCODING``: if not in email.charsets
433 4. ``$HGENCODING``: if not in email.charsets
434 5. ``utf-8``: always last, regardless of settings
434 5. ``utf-8``: always last, regardless of settings
435
435
436 Email example::
436 Email example::
437
437
438 [email]
438 [email]
439 from = Joseph User <joe.user@example.com>
439 from = Joseph User <joe.user@example.com>
440 method = /usr/sbin/sendmail
440 method = /usr/sbin/sendmail
441 # charsets for western Europeans
441 # charsets for western Europeans
442 # us-ascii, utf-8 omitted, as they are tried first and last
442 # us-ascii, utf-8 omitted, as they are tried first and last
443 charsets = iso-8859-1, iso-8859-15, windows-1252
443 charsets = iso-8859-1, iso-8859-15, windows-1252
444
444
445
445
446 ``extensions``
446 ``extensions``
447 """"""""""""""
447 """"""""""""""
448
448
449 Mercurial has an extension mechanism for adding new features. To
449 Mercurial has an extension mechanism for adding new features. To
450 enable an extension, create an entry for it in this section.
450 enable an extension, create an entry for it in this section.
451
451
452 If you know that the extension is already in Python's search path,
452 If you know that the extension is already in Python's search path,
453 you can give the name of the module, followed by ``=``, with nothing
453 you can give the name of the module, followed by ``=``, with nothing
454 after the ``=``.
454 after the ``=``.
455
455
456 Otherwise, give a name that you choose, followed by ``=``, followed by
456 Otherwise, give a name that you choose, followed by ``=``, followed by
457 the path to the ``.py`` file (including the file name extension) that
457 the path to the ``.py`` file (including the file name extension) that
458 defines the extension.
458 defines the extension.
459
459
460 To explicitly disable an extension that is enabled in an hgrc of
460 To explicitly disable an extension that is enabled in an hgrc of
461 broader scope, prepend its path with ``!``, as in ``foo = !/ext/path``
461 broader scope, prepend its path with ``!``, as in ``foo = !/ext/path``
462 or ``foo = !`` when path is not supplied.
462 or ``foo = !`` when path is not supplied.
463
463
464 Example for ``~/.hgrc``::
464 Example for ``~/.hgrc``::
465
465
466 [extensions]
466 [extensions]
467 # (the mq extension will get loaded from Mercurial's path)
467 # (the mq extension will get loaded from Mercurial's path)
468 mq =
468 mq =
469 # (this extension will get loaded from the file specified)
469 # (this extension will get loaded from the file specified)
470 myfeature = ~/.hgext/myfeature.py
470 myfeature = ~/.hgext/myfeature.py
471
471
472
472
473 ``hostfingerprints``
473 ``hostfingerprints``
474 """"""""""""""""""""
474 """"""""""""""""""""
475
475
476 Fingerprints of the certificates of known HTTPS servers.
476 Fingerprints of the certificates of known HTTPS servers.
477 A HTTPS connection to a server with a fingerprint configured here will
477 A HTTPS connection to a server with a fingerprint configured here will
478 only succeed if the servers certificate matches the fingerprint.
478 only succeed if the servers certificate matches the fingerprint.
479 This is very similar to how ssh known hosts works.
479 This is very similar to how ssh known hosts works.
480 The fingerprint is the SHA-1 hash value of the DER encoded certificate.
480 The fingerprint is the SHA-1 hash value of the DER encoded certificate.
481 The CA chain and web.cacerts is not used for servers with a fingerprint.
481 The CA chain and web.cacerts is not used for servers with a fingerprint.
482
482
483 For example::
483 For example::
484
484
485 [hostfingerprints]
485 [hostfingerprints]
486 hg.intevation.org = 38:76:52:7c:87:26:9a:8f:4a:f8:d3:de:08:45:3b:ea:d6:4b:ee:cc
486 hg.intevation.org = 38:76:52:7c:87:26:9a:8f:4a:f8:d3:de:08:45:3b:ea:d6:4b:ee:cc
487
487
488 This feature is only supported when using Python 2.6 or later.
488 This feature is only supported when using Python 2.6 or later.
489
489
490
490
491 ``format``
491 ``format``
492 """"""""""
492 """"""""""
493
493
494 ``usestore``
494 ``usestore``
495 Enable or disable the "store" repository format which improves
495 Enable or disable the "store" repository format which improves
496 compatibility with systems that fold case or otherwise mangle
496 compatibility with systems that fold case or otherwise mangle
497 filenames. Enabled by default. Disabling this option will allow
497 filenames. Enabled by default. Disabling this option will allow
498 you to store longer filenames in some situations at the expense of
498 you to store longer filenames in some situations at the expense of
499 compatibility and ensures that the on-disk format of newly created
499 compatibility and ensures that the on-disk format of newly created
500 repositories will be compatible with Mercurial before version 0.9.4.
500 repositories will be compatible with Mercurial before version 0.9.4.
501
501
502 ``usefncache``
502 ``usefncache``
503 Enable or disable the "fncache" repository format which enhances
503 Enable or disable the "fncache" repository format which enhances
504 the "store" repository format (which has to be enabled to use
504 the "store" repository format (which has to be enabled to use
505 fncache) to allow longer filenames and avoids using Windows
505 fncache) to allow longer filenames and avoids using Windows
506 reserved names, e.g. "nul". Enabled by default. Disabling this
506 reserved names, e.g. "nul". Enabled by default. Disabling this
507 option ensures that the on-disk format of newly created
507 option ensures that the on-disk format of newly created
508 repositories will be compatible with Mercurial before version 1.1.
508 repositories will be compatible with Mercurial before version 1.1.
509
509
510 ``dotencode``
510 ``dotencode``
511 Enable or disable the "dotencode" repository format which enhances
511 Enable or disable the "dotencode" repository format which enhances
512 the "fncache" repository format (which has to be enabled to use
512 the "fncache" repository format (which has to be enabled to use
513 dotencode) to avoid issues with filenames starting with ._ on
513 dotencode) to avoid issues with filenames starting with ._ on
514 Mac OS X and spaces on Windows. Enabled by default. Disabling this
514 Mac OS X and spaces on Windows. Enabled by default. Disabling this
515 option ensures that the on-disk format of newly created
515 option ensures that the on-disk format of newly created
516 repositories will be compatible with Mercurial before version 1.7.
516 repositories will be compatible with Mercurial before version 1.7.
517
517
518 ``merge-patterns``
518 ``merge-patterns``
519 """"""""""""""""""
519 """"""""""""""""""
520
520
521 This section specifies merge tools to associate with particular file
521 This section specifies merge tools to associate with particular file
522 patterns. Tools matched here will take precedence over the default
522 patterns. Tools matched here will take precedence over the default
523 merge tool. Patterns are globs by default, rooted at the repository
523 merge tool. Patterns are globs by default, rooted at the repository
524 root.
524 root.
525
525
526 Example::
526 Example::
527
527
528 [merge-patterns]
528 [merge-patterns]
529 **.c = kdiff3
529 **.c = kdiff3
530 **.jpg = myimgmerge
530 **.jpg = myimgmerge
531
531
532 ``merge-tools``
532 ``merge-tools``
533 """""""""""""""
533 """""""""""""""
534
534
535 This section configures external merge tools to use for file-level
535 This section configures external merge tools to use for file-level
536 merges.
536 merges.
537
537
538 Example ``~/.hgrc``::
538 Example ``~/.hgrc``::
539
539
540 [merge-tools]
540 [merge-tools]
541 # Override stock tool location
541 # Override stock tool location
542 kdiff3.executable = ~/bin/kdiff3
542 kdiff3.executable = ~/bin/kdiff3
543 # Specify command line
543 # Specify command line
544 kdiff3.args = $base $local $other -o $output
544 kdiff3.args = $base $local $other -o $output
545 # Give higher priority
545 # Give higher priority
546 kdiff3.priority = 1
546 kdiff3.priority = 1
547
547
548 # Define new tool
548 # Define new tool
549 myHtmlTool.args = -m $local $other $base $output
549 myHtmlTool.args = -m $local $other $base $output
550 myHtmlTool.regkey = Software\FooSoftware\HtmlMerge
550 myHtmlTool.regkey = Software\FooSoftware\HtmlMerge
551 myHtmlTool.priority = 1
551 myHtmlTool.priority = 1
552
552
553 Supported arguments:
553 Supported arguments:
554
554
555 ``priority``
555 ``priority``
556 The priority in which to evaluate this tool.
556 The priority in which to evaluate this tool.
557 Default: 0.
557 Default: 0.
558
558
559 ``executable``
559 ``executable``
560 Either just the name of the executable or its pathname. On Windows,
560 Either just the name of the executable or its pathname. On Windows,
561 the path can use environment variables with ${ProgramFiles} syntax.
561 the path can use environment variables with ${ProgramFiles} syntax.
562 Default: the tool name.
562 Default: the tool name.
563
563
564 ``args``
564 ``args``
565 The arguments to pass to the tool executable. You can refer to the
565 The arguments to pass to the tool executable. You can refer to the
566 files being merged as well as the output file through these
566 files being merged as well as the output file through these
567 variables: ``$base``, ``$local``, ``$other``, ``$output``.
567 variables: ``$base``, ``$local``, ``$other``, ``$output``.
568 Default: ``$local $base $other``
568 Default: ``$local $base $other``
569
569
570 ``premerge``
570 ``premerge``
571 Attempt to run internal non-interactive 3-way merge tool before
571 Attempt to run internal non-interactive 3-way merge tool before
572 launching external tool. Options are ``true``, ``false``, or ``keep``
572 launching external tool. Options are ``true``, ``false``, or ``keep``
573 to leave markers in the file if the premerge fails.
573 to leave markers in the file if the premerge fails.
574 Default: True
574 Default: True
575
575
576 ``binary``
576 ``binary``
577 This tool can merge binary files. Defaults to False, unless tool
577 This tool can merge binary files. Defaults to False, unless tool
578 was selected by file pattern match.
578 was selected by file pattern match.
579
579
580 ``symlink``
580 ``symlink``
581 This tool can merge symlinks. Defaults to False, even if tool was
581 This tool can merge symlinks. Defaults to False, even if tool was
582 selected by file pattern match.
582 selected by file pattern match.
583
583
584 ``check``
584 ``check``
585 A list of merge success-checking options:
585 A list of merge success-checking options:
586
586
587 ``changed``
587 ``changed``
588 Ask whether merge was successful when the merged file shows no changes.
588 Ask whether merge was successful when the merged file shows no changes.
589 ``conflicts``
589 ``conflicts``
590 Check whether there are conflicts even though the tool reported success.
590 Check whether there are conflicts even though the tool reported success.
591 ``prompt``
591 ``prompt``
592 Always prompt for merge success, regardless of success reported by tool.
592 Always prompt for merge success, regardless of success reported by tool.
593
593
594 ``checkchanged``
594 ``checkchanged``
595 True is equivalent to ``check = changed``.
595 True is equivalent to ``check = changed``.
596 Default: False
596 Default: False
597
597
598 ``checkconflicts``
598 ``checkconflicts``
599 True is equivalent to ``check = conflicts``.
599 True is equivalent to ``check = conflicts``.
600 Default: False
600 Default: False
601
601
602 ``fixeol``
602 ``fixeol``
603 Attempt to fix up EOL changes caused by the merge tool.
603 Attempt to fix up EOL changes caused by the merge tool.
604 Default: False
604 Default: False
605
605
606 ``gui``
606 ``gui``
607 This tool requires a graphical interface to run. Default: False
607 This tool requires a graphical interface to run. Default: False
608
608
609 ``regkey``
609 ``regkey``
610 Windows registry key which describes install location of this
610 Windows registry key which describes install location of this
611 tool. Mercurial will search for this key first under
611 tool. Mercurial will search for this key first under
612 ``HKEY_CURRENT_USER`` and then under ``HKEY_LOCAL_MACHINE``.
612 ``HKEY_CURRENT_USER`` and then under ``HKEY_LOCAL_MACHINE``.
613 Default: None
613 Default: None
614
614
615 ``regkeyalt``
615 ``regkeyalt``
616 An alternate Windows registry key to try if the first key is not
616 An alternate Windows registry key to try if the first key is not
617 found. The alternate key uses the same ``regname`` and ``regappend``
617 found. The alternate key uses the same ``regname`` and ``regappend``
618 semantics of the primary key. The most common use for this key
618 semantics of the primary key. The most common use for this key
619 is to search for 32bit applications on 64bit operating systems.
619 is to search for 32bit applications on 64bit operating systems.
620 Default: None
620 Default: None
621
621
622 ``regname``
622 ``regname``
623 Name of value to read from specified registry key. Defaults to the
623 Name of value to read from specified registry key. Defaults to the
624 unnamed (default) value.
624 unnamed (default) value.
625
625
626 ``regappend``
626 ``regappend``
627 String to append to the value read from the registry, typically
627 String to append to the value read from the registry, typically
628 the executable name of the tool.
628 the executable name of the tool.
629 Default: None
629 Default: None
630
630
631
631
632 ``hooks``
632 ``hooks``
633 """""""""
633 """""""""
634
634
635 Commands or Python functions that get automatically executed by
635 Commands or Python functions that get automatically executed by
636 various actions such as starting or finishing a commit. Multiple
636 various actions such as starting or finishing a commit. Multiple
637 hooks can be run for the same action by appending a suffix to the
637 hooks can be run for the same action by appending a suffix to the
638 action. Overriding a site-wide hook can be done by changing its
638 action. Overriding a site-wide hook can be done by changing its
639 value or setting it to an empty string.
639 value or setting it to an empty string.
640
640
641 Example ``.hg/hgrc``::
641 Example ``.hg/hgrc``::
642
642
643 [hooks]
643 [hooks]
644 # update working directory after adding changesets
644 # update working directory after adding changesets
645 changegroup.update = hg update
645 changegroup.update = hg update
646 # do not use the site-wide hook
646 # do not use the site-wide hook
647 incoming =
647 incoming =
648 incoming.email = /my/email/hook
648 incoming.email = /my/email/hook
649 incoming.autobuild = /my/build/hook
649 incoming.autobuild = /my/build/hook
650
650
651 Most hooks are run with environment variables set that give useful
651 Most hooks are run with environment variables set that give useful
652 additional information. For each hook below, the environment
652 additional information. For each hook below, the environment
653 variables it is passed are listed with names of the form ``$HG_foo``.
653 variables it is passed are listed with names of the form ``$HG_foo``.
654
654
655 ``changegroup``
655 ``changegroup``
656 Run after a changegroup has been added via push, pull or unbundle.
656 Run after a changegroup has been added via push, pull or unbundle.
657 ID of the first new changeset is in ``$HG_NODE``. URL from which
657 ID of the first new changeset is in ``$HG_NODE``. URL from which
658 changes came is in ``$HG_URL``.
658 changes came is in ``$HG_URL``.
659
659
660 ``commit``
660 ``commit``
661 Run after a changeset has been created in the local repository. ID
661 Run after a changeset has been created in the local repository. ID
662 of the newly created changeset is in ``$HG_NODE``. Parent changeset
662 of the newly created changeset is in ``$HG_NODE``. Parent changeset
663 IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
663 IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
664
664
665 ``incoming``
665 ``incoming``
666 Run after a changeset has been pulled, pushed, or unbundled into
666 Run after a changeset has been pulled, pushed, or unbundled into
667 the local repository. The ID of the newly arrived changeset is in
667 the local repository. The ID of the newly arrived changeset is in
668 ``$HG_NODE``. URL that was source of changes came is in ``$HG_URL``.
668 ``$HG_NODE``. URL that was source of changes came is in ``$HG_URL``.
669
669
670 ``outgoing``
670 ``outgoing``
671 Run after sending changes from local repository to another. ID of
671 Run after sending changes from local repository to another. ID of
672 first changeset sent is in ``$HG_NODE``. Source of operation is in
672 first changeset sent is in ``$HG_NODE``. Source of operation is in
673 ``$HG_SOURCE``; see "preoutgoing" hook for description.
673 ``$HG_SOURCE``; see "preoutgoing" hook for description.
674
674
675 ``post-<command>``
675 ``post-<command>``
676 Run after successful invocations of the associated command. The
676 Run after successful invocations of the associated command. The
677 contents of the command line are passed as ``$HG_ARGS`` and the result
677 contents of the command line are passed as ``$HG_ARGS`` and the result
678 code in ``$HG_RESULT``. Parsed command line arguments are passed as
678 code in ``$HG_RESULT``. Parsed command line arguments are passed as
679 ``$HG_PATS`` and ``$HG_OPTS``. These contain string representations of
679 ``$HG_PATS`` and ``$HG_OPTS``. These contain string representations of
680 the python data internally passed to <command>. ``$HG_OPTS`` is a
680 the python data internally passed to <command>. ``$HG_OPTS`` is a
681 dictionary of options (with unspecified options set to their defaults).
681 dictionary of options (with unspecified options set to their defaults).
682 ``$HG_PATS`` is a list of arguments. Hook failure is ignored.
682 ``$HG_PATS`` is a list of arguments. Hook failure is ignored.
683
683
684 ``pre-<command>``
684 ``pre-<command>``
685 Run before executing the associated command. The contents of the
685 Run before executing the associated command. The contents of the
686 command line are passed as ``$HG_ARGS``. Parsed command line arguments
686 command line are passed as ``$HG_ARGS``. Parsed command line arguments
687 are passed as ``$HG_PATS`` and ``$HG_OPTS``. These contain string
687 are passed as ``$HG_PATS`` and ``$HG_OPTS``. These contain string
688 representations of the data internally passed to <command>. ``$HG_OPTS``
688 representations of the data internally passed to <command>. ``$HG_OPTS``
689 is a dictionary of options (with unspecified options set to their
689 is a dictionary of options (with unspecified options set to their
690 defaults). ``$HG_PATS`` is a list of arguments. If the hook returns
690 defaults). ``$HG_PATS`` is a list of arguments. If the hook returns
691 failure, the command doesn't execute and Mercurial returns the failure
691 failure, the command doesn't execute and Mercurial returns the failure
692 code.
692 code.
693
693
694 ``prechangegroup``
694 ``prechangegroup``
695 Run before a changegroup is added via push, pull or unbundle. Exit
695 Run before a changegroup is added via push, pull or unbundle. Exit
696 status 0 allows the changegroup to proceed. Non-zero status will
696 status 0 allows the changegroup to proceed. Non-zero status will
697 cause the push, pull or unbundle to fail. URL from which changes
697 cause the push, pull or unbundle to fail. URL from which changes
698 will come is in ``$HG_URL``.
698 will come is in ``$HG_URL``.
699
699
700 ``precommit``
700 ``precommit``
701 Run before starting a local commit. Exit status 0 allows the
701 Run before starting a local commit. Exit status 0 allows the
702 commit to proceed. Non-zero status will cause the commit to fail.
702 commit to proceed. Non-zero status will cause the commit to fail.
703 Parent changeset IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
703 Parent changeset IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
704
704
705 ``prelistkeys``
705 ``prelistkeys``
706 Run before listing pushkeys (like bookmarks) in the
706 Run before listing pushkeys (like bookmarks) in the
707 repository. Non-zero status will cause failure. The key namespace is
707 repository. Non-zero status will cause failure. The key namespace is
708 in ``$HG_NAMESPACE``.
708 in ``$HG_NAMESPACE``.
709
709
710 ``preoutgoing``
710 ``preoutgoing``
711 Run before collecting changes to send from the local repository to
711 Run before collecting changes to send from the local repository to
712 another. Non-zero status will cause failure. This lets you prevent
712 another. Non-zero status will cause failure. This lets you prevent
713 pull over HTTP or SSH. Also prevents against local pull, push
713 pull over HTTP or SSH. Also prevents against local pull, push
714 (outbound) or bundle commands, but not effective, since you can
714 (outbound) or bundle commands, but not effective, since you can
715 just copy files instead then. Source of operation is in
715 just copy files instead then. Source of operation is in
716 ``$HG_SOURCE``. If "serve", operation is happening on behalf of remote
716 ``$HG_SOURCE``. If "serve", operation is happening on behalf of remote
717 SSH or HTTP repository. If "push", "pull" or "bundle", operation
717 SSH or HTTP repository. If "push", "pull" or "bundle", operation
718 is happening on behalf of repository on same system.
718 is happening on behalf of repository on same system.
719
719
720 ``prepushkey``
720 ``prepushkey``
721 Run before a pushkey (like a bookmark) is added to the
721 Run before a pushkey (like a bookmark) is added to the
722 repository. Non-zero status will cause the key to be rejected. The
722 repository. Non-zero status will cause the key to be rejected. The
723 key namespace is in ``$HG_NAMESPACE``, the key is in ``$HG_KEY``,
723 key namespace is in ``$HG_NAMESPACE``, the key is in ``$HG_KEY``,
724 the old value (if any) is in ``$HG_OLD``, and the new value is in
724 the old value (if any) is in ``$HG_OLD``, and the new value is in
725 ``$HG_NEW``.
725 ``$HG_NEW``.
726
726
727 ``pretag``
727 ``pretag``
728 Run before creating a tag. Exit status 0 allows the tag to be
728 Run before creating a tag. Exit status 0 allows the tag to be
729 created. Non-zero status will cause the tag to fail. ID of
729 created. Non-zero status will cause the tag to fail. ID of
730 changeset to tag is in ``$HG_NODE``. Name of tag is in ``$HG_TAG``. Tag is
730 changeset to tag is in ``$HG_NODE``. Name of tag is in ``$HG_TAG``. Tag is
731 local if ``$HG_LOCAL=1``, in repository if ``$HG_LOCAL=0``.
731 local if ``$HG_LOCAL=1``, in repository if ``$HG_LOCAL=0``.
732
732
733 ``pretxnchangegroup``
733 ``pretxnchangegroup``
734 Run after a changegroup has been added via push, pull or unbundle,
734 Run after a changegroup has been added via push, pull or unbundle,
735 but before the transaction has been committed. Changegroup is
735 but before the transaction has been committed. Changegroup is
736 visible to hook program. This lets you validate incoming changes
736 visible to hook program. This lets you validate incoming changes
737 before accepting them. Passed the ID of the first new changeset in
737 before accepting them. Passed the ID of the first new changeset in
738 ``$HG_NODE``. Exit status 0 allows the transaction to commit. Non-zero
738 ``$HG_NODE``. Exit status 0 allows the transaction to commit. Non-zero
739 status will cause the transaction to be rolled back and the push,
739 status will cause the transaction to be rolled back and the push,
740 pull or unbundle will fail. URL that was source of changes is in
740 pull or unbundle will fail. URL that was source of changes is in
741 ``$HG_URL``.
741 ``$HG_URL``.
742
742
743 ``pretxncommit``
743 ``pretxncommit``
744 Run after a changeset has been created but the transaction not yet
744 Run after a changeset has been created but the transaction not yet
745 committed. Changeset is visible to hook program. This lets you
745 committed. Changeset is visible to hook program. This lets you
746 validate commit message and changes. Exit status 0 allows the
746 validate commit message and changes. Exit status 0 allows the
747 commit to proceed. Non-zero status will cause the transaction to
747 commit to proceed. Non-zero status will cause the transaction to
748 be rolled back. ID of changeset is in ``$HG_NODE``. Parent changeset
748 be rolled back. ID of changeset is in ``$HG_NODE``. Parent changeset
749 IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
749 IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
750
750
751 ``preupdate``
751 ``preupdate``
752 Run before updating the working directory. Exit status 0 allows
752 Run before updating the working directory. Exit status 0 allows
753 the update to proceed. Non-zero status will prevent the update.
753 the update to proceed. Non-zero status will prevent the update.
754 Changeset ID of first new parent is in ``$HG_PARENT1``. If merge, ID
754 Changeset ID of first new parent is in ``$HG_PARENT1``. If merge, ID
755 of second new parent is in ``$HG_PARENT2``.
755 of second new parent is in ``$HG_PARENT2``.
756
756
757 ``listkeys``
757 ``listkeys``
758 Run after listing pushkeys (like bookmarks) in the repository. The
758 Run after listing pushkeys (like bookmarks) in the repository. The
759 key namespace is in ``$HG_NAMESPACE``. ``$HG_VALUES`` is a
759 key namespace is in ``$HG_NAMESPACE``. ``$HG_VALUES`` is a
760 dictionary containing the keys and values.
760 dictionary containing the keys and values.
761
761
762 ``pushkey``
762 ``pushkey``
763 Run after a pushkey (like a bookmark) is added to the
763 Run after a pushkey (like a bookmark) is added to the
764 repository. The key namespace is in ``$HG_NAMESPACE``, the key is in
764 repository. The key namespace is in ``$HG_NAMESPACE``, the key is in
765 ``$HG_KEY``, the old value (if any) is in ``$HG_OLD``, and the new
765 ``$HG_KEY``, the old value (if any) is in ``$HG_OLD``, and the new
766 value is in ``$HG_NEW``.
766 value is in ``$HG_NEW``.
767
767
768 ``tag``
768 ``tag``
769 Run after a tag is created. ID of tagged changeset is in ``$HG_NODE``.
769 Run after a tag is created. ID of tagged changeset is in ``$HG_NODE``.
770 Name of tag is in ``$HG_TAG``. Tag is local if ``$HG_LOCAL=1``, in
770 Name of tag is in ``$HG_TAG``. Tag is local if ``$HG_LOCAL=1``, in
771 repository if ``$HG_LOCAL=0``.
771 repository if ``$HG_LOCAL=0``.
772
772
773 ``update``
773 ``update``
774 Run after updating the working directory. Changeset ID of first
774 Run after updating the working directory. Changeset ID of first
775 new parent is in ``$HG_PARENT1``. If merge, ID of second new parent is
775 new parent is in ``$HG_PARENT1``. If merge, ID of second new parent is
776 in ``$HG_PARENT2``. If the update succeeded, ``$HG_ERROR=0``. If the
776 in ``$HG_PARENT2``. If the update succeeded, ``$HG_ERROR=0``. If the
777 update failed (e.g. because conflicts not resolved), ``$HG_ERROR=1``.
777 update failed (e.g. because conflicts not resolved), ``$HG_ERROR=1``.
778
778
779 .. note:: It is generally better to use standard hooks rather than the
779 .. note:: It is generally better to use standard hooks rather than the
780 generic pre- and post- command hooks as they are guaranteed to be
780 generic pre- and post- command hooks as they are guaranteed to be
781 called in the appropriate contexts for influencing transactions.
781 called in the appropriate contexts for influencing transactions.
782 Also, hooks like "commit" will be called in all contexts that
782 Also, hooks like "commit" will be called in all contexts that
783 generate a commit (e.g. tag) and not just the commit command.
783 generate a commit (e.g. tag) and not just the commit command.
784
784
785 .. note:: Environment variables with empty values may not be passed to
785 .. note:: Environment variables with empty values may not be passed to
786 hooks on platforms such as Windows. As an example, ``$HG_PARENT2``
786 hooks on platforms such as Windows. As an example, ``$HG_PARENT2``
787 will have an empty value under Unix-like platforms for non-merge
787 will have an empty value under Unix-like platforms for non-merge
788 changesets, while it will not be available at all under Windows.
788 changesets, while it will not be available at all under Windows.
789
789
790 The syntax for Python hooks is as follows::
790 The syntax for Python hooks is as follows::
791
791
792 hookname = python:modulename.submodule.callable
792 hookname = python:modulename.submodule.callable
793 hookname = python:/path/to/python/module.py:callable
793 hookname = python:/path/to/python/module.py:callable
794
794
795 Python hooks are run within the Mercurial process. Each hook is
795 Python hooks are run within the Mercurial process. Each hook is
796 called with at least three keyword arguments: a ui object (keyword
796 called with at least three keyword arguments: a ui object (keyword
797 ``ui``), a repository object (keyword ``repo``), and a ``hooktype``
797 ``ui``), a repository object (keyword ``repo``), and a ``hooktype``
798 keyword that tells what kind of hook is used. Arguments listed as
798 keyword that tells what kind of hook is used. Arguments listed as
799 environment variables above are passed as keyword arguments, with no
799 environment variables above are passed as keyword arguments, with no
800 ``HG_`` prefix, and names in lower case.
800 ``HG_`` prefix, and names in lower case.
801
801
802 If a Python hook returns a "true" value or raises an exception, this
802 If a Python hook returns a "true" value or raises an exception, this
803 is treated as a failure.
803 is treated as a failure.
804
804
805
805
806 ``http_proxy``
806 ``http_proxy``
807 """"""""""""""
807 """"""""""""""
808
808
809 Used to access web-based Mercurial repositories through a HTTP
809 Used to access web-based Mercurial repositories through a HTTP
810 proxy.
810 proxy.
811
811
812 ``host``
812 ``host``
813 Host name and (optional) port of the proxy server, for example
813 Host name and (optional) port of the proxy server, for example
814 "myproxy:8000".
814 "myproxy:8000".
815
815
816 ``no``
816 ``no``
817 Optional. Comma-separated list of host names that should bypass
817 Optional. Comma-separated list of host names that should bypass
818 the proxy.
818 the proxy.
819
819
820 ``passwd``
820 ``passwd``
821 Optional. Password to authenticate with at the proxy server.
821 Optional. Password to authenticate with at the proxy server.
822
822
823 ``user``
823 ``user``
824 Optional. User name to authenticate with at the proxy server.
824 Optional. User name to authenticate with at the proxy server.
825
825
826 ``always``
826 ``always``
827 Optional. Always use the proxy, even for localhost and any entries
827 Optional. Always use the proxy, even for localhost and any entries
828 in ``http_proxy.no``. True or False. Default: False.
828 in ``http_proxy.no``. True or False. Default: False.
829
829
830 ``smtp``
830 ``smtp``
831 """"""""
831 """"""""
832
832
833 Configuration for extensions that need to send email messages.
833 Configuration for extensions that need to send email messages.
834
834
835 ``host``
835 ``host``
836 Host name of mail server, e.g. "mail.example.com".
836 Host name of mail server, e.g. "mail.example.com".
837
837
838 ``port``
838 ``port``
839 Optional. Port to connect to on mail server. Default: 25.
839 Optional. Port to connect to on mail server. Default: 25.
840
840
841 ``tls``
841 ``tls``
842 Optional. Method to enable TLS when connecting to mail server: starttls,
842 Optional. Method to enable TLS when connecting to mail server: starttls,
843 smtps or none. Default: none.
843 smtps or none. Default: none.
844
844
845 ``username``
845 ``username``
846 Optional. User name for authenticating with the SMTP server.
846 Optional. User name for authenticating with the SMTP server.
847 Default: none.
847 Default: none.
848
848
849 ``password``
849 ``password``
850 Optional. Password for authenticating with the SMTP server. If not
850 Optional. Password for authenticating with the SMTP server. If not
851 specified, interactive sessions will prompt the user for a
851 specified, interactive sessions will prompt the user for a
852 password; non-interactive sessions will fail. Default: none.
852 password; non-interactive sessions will fail. Default: none.
853
853
854 ``local_hostname``
854 ``local_hostname``
855 Optional. It's the hostname that the sender can use to identify
855 Optional. It's the hostname that the sender can use to identify
856 itself to the MTA.
856 itself to the MTA.
857
857
858
858
859 ``patch``
859 ``patch``
860 """""""""
860 """""""""
861
861
862 Settings used when applying patches, for instance through the 'import'
862 Settings used when applying patches, for instance through the 'import'
863 command or with Mercurial Queues extension.
863 command or with Mercurial Queues extension.
864
864
865 ``eol``
865 ``eol``
866 When set to 'strict' patch content and patched files end of lines
866 When set to 'strict' patch content and patched files end of lines
867 are preserved. When set to ``lf`` or ``crlf``, both files end of
867 are preserved. When set to ``lf`` or ``crlf``, both files end of
868 lines are ignored when patching and the result line endings are
868 lines are ignored when patching and the result line endings are
869 normalized to either LF (Unix) or CRLF (Windows). When set to
869 normalized to either LF (Unix) or CRLF (Windows). When set to
870 ``auto``, end of lines are again ignored while patching but line
870 ``auto``, end of lines are again ignored while patching but line
871 endings in patched files are normalized to their original setting
871 endings in patched files are normalized to their original setting
872 on a per-file basis. If target file does not exist or has no end
872 on a per-file basis. If target file does not exist or has no end
873 of line, patch line endings are preserved.
873 of line, patch line endings are preserved.
874 Default: strict.
874 Default: strict.
875
875
876
876
877 ``paths``
877 ``paths``
878 """""""""
878 """""""""
879
879
880 Assigns symbolic names to repositories. The left side is the
880 Assigns symbolic names to repositories. The left side is the
881 symbolic name, and the right gives the directory or URL that is the
881 symbolic name, and the right gives the directory or URL that is the
882 location of the repository. Default paths can be declared by setting
882 location of the repository. Default paths can be declared by setting
883 the following entries.
883 the following entries.
884
884
885 ``default``
885 ``default``
886 Directory or URL to use when pulling if no source is specified.
886 Directory or URL to use when pulling if no source is specified.
887 Default is set to repository from which the current repository was
887 Default is set to repository from which the current repository was
888 cloned.
888 cloned.
889
889
890 ``default-push``
890 ``default-push``
891 Optional. Directory or URL to use when pushing if no destination
891 Optional. Directory or URL to use when pushing if no destination
892 is specified.
892 is specified.
893
893
894
894
895 ``profiling``
895 ``profiling``
896 """""""""""""
896 """""""""""""
897
897
898 Specifies profiling format and file output. In this section
898 Specifies profiling format and file output. In this section
899 description, 'profiling data' stands for the raw data collected
899 description, 'profiling data' stands for the raw data collected
900 during profiling, while 'profiling report' stands for a statistical
900 during profiling, while 'profiling report' stands for a statistical
901 text report generated from the profiling data. The profiling is done
901 text report generated from the profiling data. The profiling is done
902 using lsprof.
902 using lsprof.
903
903
904 ``format``
904 ``format``
905 Profiling format.
905 Profiling format.
906 Default: text.
906 Default: text.
907
907
908 ``text``
908 ``text``
909 Generate a profiling report. When saving to a file, it should be
909 Generate a profiling report. When saving to a file, it should be
910 noted that only the report is saved, and the profiling data is
910 noted that only the report is saved, and the profiling data is
911 not kept.
911 not kept.
912 ``kcachegrind``
912 ``kcachegrind``
913 Format profiling data for kcachegrind use: when saving to a
913 Format profiling data for kcachegrind use: when saving to a
914 file, the generated file can directly be loaded into
914 file, the generated file can directly be loaded into
915 kcachegrind.
915 kcachegrind.
916
916
917 ``output``
917 ``output``
918 File path where profiling data or report should be saved. If the
918 File path where profiling data or report should be saved. If the
919 file exists, it is replaced. Default: None, data is printed on
919 file exists, it is replaced. Default: None, data is printed on
920 stderr
920 stderr
921
921
922 ``revsetalias``
922 ``revsetalias``
923 """""""""""""""
923 """""""""""""""
924
924
925 Alias definitions for revsets. See :hg:`help revsets` for details.
925 Alias definitions for revsets. See :hg:`help revsets` for details.
926
926
927 ``server``
927 ``server``
928 """"""""""
928 """"""""""
929
929
930 Controls generic server settings.
930 Controls generic server settings.
931
931
932 ``uncompressed``
932 ``uncompressed``
933 Whether to allow clients to clone a repository using the
933 Whether to allow clients to clone a repository using the
934 uncompressed streaming protocol. This transfers about 40% more
934 uncompressed streaming protocol. This transfers about 40% more
935 data than a regular clone, but uses less memory and CPU on both
935 data than a regular clone, but uses less memory and CPU on both
936 server and client. Over a LAN (100 Mbps or better) or a very fast
936 server and client. Over a LAN (100 Mbps or better) or a very fast
937 WAN, an uncompressed streaming clone is a lot faster (~10x) than a
937 WAN, an uncompressed streaming clone is a lot faster (~10x) than a
938 regular clone. Over most WAN connections (anything slower than
938 regular clone. Over most WAN connections (anything slower than
939 about 6 Mbps), uncompressed streaming is slower, because of the
939 about 6 Mbps), uncompressed streaming is slower, because of the
940 extra data transfer overhead. This mode will also temporarily hold
940 extra data transfer overhead. This mode will also temporarily hold
941 the write lock while determining what data to transfer.
941 the write lock while determining what data to transfer.
942 Default is True.
942 Default is True.
943
943
944 ``validate``
944 ``validate``
945 Whether to validate the completeness of pushed changesets by
945 Whether to validate the completeness of pushed changesets by
946 checking that all new file revisions specified in manifests are
946 checking that all new file revisions specified in manifests are
947 present. Default is False.
947 present. Default is False.
948
948
949 ``subpaths``
949 ``subpaths``
950 """"""""""""
950 """"""""""""
951
951
952 Defines subrepositories source locations rewriting rules of the form::
952 Defines subrepositories source locations rewriting rules of the form::
953
953
954 <pattern> = <replacement>
954 <pattern> = <replacement>
955
955
956 Where ``pattern`` is a regular expression matching the source and
956 Where ``pattern`` is a regular expression matching the source and
957 ``replacement`` is the replacement string used to rewrite it. Groups
957 ``replacement`` is the replacement string used to rewrite it. Groups
958 can be matched in ``pattern`` and referenced in ``replacements``. For
958 can be matched in ``pattern`` and referenced in ``replacements``. For
959 instance::
959 instance::
960
960
961 http://server/(.*)-hg/ = http://hg.server/\1/
961 http://server/(.*)-hg/ = http://hg.server/\1/
962
962
963 rewrites ``http://server/foo-hg/`` into ``http://hg.server/foo/``.
963 rewrites ``http://server/foo-hg/`` into ``http://hg.server/foo/``.
964
964
965 All patterns are applied in definition order.
965 All patterns are applied in definition order.
966
966
967 ``trusted``
967 ``trusted``
968 """""""""""
968 """""""""""
969
969
970 Mercurial will not use the settings in the
970 Mercurial will not use the settings in the
971 ``.hg/hgrc`` file from a repository if it doesn't belong to a trusted
971 ``.hg/hgrc`` file from a repository if it doesn't belong to a trusted
972 user or to a trusted group, as various hgrc features allow arbitrary
972 user or to a trusted group, as various hgrc features allow arbitrary
973 commands to be run. This issue is often encountered when configuring
973 commands to be run. This issue is often encountered when configuring
974 hooks or extensions for shared repositories or servers. However,
974 hooks or extensions for shared repositories or servers. However,
975 the web interface will use some safe settings from the ``[web]``
975 the web interface will use some safe settings from the ``[web]``
976 section.
976 section.
977
977
978 This section specifies what users and groups are trusted. The
978 This section specifies what users and groups are trusted. The
979 current user is always trusted. To trust everybody, list a user or a
979 current user is always trusted. To trust everybody, list a user or a
980 group with name ``*``. These settings must be placed in an
980 group with name ``*``. These settings must be placed in an
981 *already-trusted file* to take effect, such as ``$HOME/.hgrc`` of the
981 *already-trusted file* to take effect, such as ``$HOME/.hgrc`` of the
982 user or service running Mercurial.
982 user or service running Mercurial.
983
983
984 ``users``
984 ``users``
985 Comma-separated list of trusted users.
985 Comma-separated list of trusted users.
986
986
987 ``groups``
987 ``groups``
988 Comma-separated list of trusted groups.
988 Comma-separated list of trusted groups.
989
989
990
990
991 ``ui``
991 ``ui``
992 """"""
992 """"""
993
993
994 User interface controls.
994 User interface controls.
995
995
996 ``archivemeta``
996 ``archivemeta``
997 Whether to include the .hg_archival.txt file containing meta data
997 Whether to include the .hg_archival.txt file containing meta data
998 (hashes for the repository base and for tip) in archives created
998 (hashes for the repository base and for tip) in archives created
999 by the :hg:`archive` command or downloaded via hgweb.
999 by the :hg:`archive` command or downloaded via hgweb.
1000 Default is True.
1000 Default is True.
1001
1001
1002 ``askusername``
1002 ``askusername``
1003 Whether to prompt for a username when committing. If True, and
1003 Whether to prompt for a username when committing. If True, and
1004 neither ``$HGUSER`` nor ``$EMAIL`` has been specified, then the user will
1004 neither ``$HGUSER`` nor ``$EMAIL`` has been specified, then the user will
1005 be prompted to enter a username. If no username is entered, the
1005 be prompted to enter a username. If no username is entered, the
1006 default ``USER@HOST`` is used instead.
1006 default ``USER@HOST`` is used instead.
1007 Default is False.
1007 Default is False.
1008
1008
1009 ``commitsubrepos``
1009 ``commitsubrepos``
1010 Whether to commit modified subrepositories when committing the
1010 Whether to commit modified subrepositories when committing the
1011 parent repository. If False and one subrepository has uncommitted
1011 parent repository. If False and one subrepository has uncommitted
1012 changes, abort the commit.
1012 changes, abort the commit.
1013 Default is True.
1013 Default is False.
1014
1014
1015 ``debug``
1015 ``debug``
1016 Print debugging information. True or False. Default is False.
1016 Print debugging information. True or False. Default is False.
1017
1017
1018 ``editor``
1018 ``editor``
1019 The editor to use during a commit. Default is ``$EDITOR`` or ``vi``.
1019 The editor to use during a commit. Default is ``$EDITOR`` or ``vi``.
1020
1020
1021 ``fallbackencoding``
1021 ``fallbackencoding``
1022 Encoding to try if it's not possible to decode the changelog using
1022 Encoding to try if it's not possible to decode the changelog using
1023 UTF-8. Default is ISO-8859-1.
1023 UTF-8. Default is ISO-8859-1.
1024
1024
1025 ``ignore``
1025 ``ignore``
1026 A file to read per-user ignore patterns from. This file should be
1026 A file to read per-user ignore patterns from. This file should be
1027 in the same format as a repository-wide .hgignore file. This
1027 in the same format as a repository-wide .hgignore file. This
1028 option supports hook syntax, so if you want to specify multiple
1028 option supports hook syntax, so if you want to specify multiple
1029 ignore files, you can do so by setting something like
1029 ignore files, you can do so by setting something like
1030 ``ignore.other = ~/.hgignore2``. For details of the ignore file
1030 ``ignore.other = ~/.hgignore2``. For details of the ignore file
1031 format, see the ``hgignore(5)`` man page.
1031 format, see the ``hgignore(5)`` man page.
1032
1032
1033 ``interactive``
1033 ``interactive``
1034 Allow to prompt the user. True or False. Default is True.
1034 Allow to prompt the user. True or False. Default is True.
1035
1035
1036 ``logtemplate``
1036 ``logtemplate``
1037 Template string for commands that print changesets.
1037 Template string for commands that print changesets.
1038
1038
1039 ``merge``
1039 ``merge``
1040 The conflict resolution program to use during a manual merge.
1040 The conflict resolution program to use during a manual merge.
1041 For more information on merge tools see :hg:`help merge-tools`.
1041 For more information on merge tools see :hg:`help merge-tools`.
1042 For configuring merge tools see the ``[merge-tools]`` section.
1042 For configuring merge tools see the ``[merge-tools]`` section.
1043
1043
1044 ``portablefilenames``
1044 ``portablefilenames``
1045 Check for portable filenames. Can be ``warn``, ``ignore`` or ``abort``.
1045 Check for portable filenames. Can be ``warn``, ``ignore`` or ``abort``.
1046 Default is ``warn``.
1046 Default is ``warn``.
1047 If set to ``warn`` (or ``true``), a warning message is printed on POSIX
1047 If set to ``warn`` (or ``true``), a warning message is printed on POSIX
1048 platforms, if a file with a non-portable filename is added (e.g. a file
1048 platforms, if a file with a non-portable filename is added (e.g. a file
1049 with a name that can't be created on Windows because it contains reserved
1049 with a name that can't be created on Windows because it contains reserved
1050 parts like ``AUX``, reserved characters like ``:``, or would cause a case
1050 parts like ``AUX``, reserved characters like ``:``, or would cause a case
1051 collision with an existing file).
1051 collision with an existing file).
1052 If set to ``ignore`` (or ``false``), no warning is printed.
1052 If set to ``ignore`` (or ``false``), no warning is printed.
1053 If set to ``abort``, the command is aborted.
1053 If set to ``abort``, the command is aborted.
1054 On Windows, this configuration option is ignored and the command aborted.
1054 On Windows, this configuration option is ignored and the command aborted.
1055
1055
1056 ``quiet``
1056 ``quiet``
1057 Reduce the amount of output printed. True or False. Default is False.
1057 Reduce the amount of output printed. True or False. Default is False.
1058
1058
1059 ``remotecmd``
1059 ``remotecmd``
1060 remote command to use for clone/push/pull operations. Default is ``hg``.
1060 remote command to use for clone/push/pull operations. Default is ``hg``.
1061
1061
1062 ``report_untrusted``
1062 ``report_untrusted``
1063 Warn if a ``.hg/hgrc`` file is ignored due to not being owned by a
1063 Warn if a ``.hg/hgrc`` file is ignored due to not being owned by a
1064 trusted user or group. True or False. Default is True.
1064 trusted user or group. True or False. Default is True.
1065
1065
1066 ``slash``
1066 ``slash``
1067 Display paths using a slash (``/``) as the path separator. This
1067 Display paths using a slash (``/``) as the path separator. This
1068 only makes a difference on systems where the default path
1068 only makes a difference on systems where the default path
1069 separator is not the slash character (e.g. Windows uses the
1069 separator is not the slash character (e.g. Windows uses the
1070 backslash character (``\``)).
1070 backslash character (``\``)).
1071 Default is False.
1071 Default is False.
1072
1072
1073 ``ssh``
1073 ``ssh``
1074 command to use for SSH connections. Default is ``ssh``.
1074 command to use for SSH connections. Default is ``ssh``.
1075
1075
1076 ``strict``
1076 ``strict``
1077 Require exact command names, instead of allowing unambiguous
1077 Require exact command names, instead of allowing unambiguous
1078 abbreviations. True or False. Default is False.
1078 abbreviations. True or False. Default is False.
1079
1079
1080 ``style``
1080 ``style``
1081 Name of style to use for command output.
1081 Name of style to use for command output.
1082
1082
1083 ``timeout``
1083 ``timeout``
1084 The timeout used when a lock is held (in seconds), a negative value
1084 The timeout used when a lock is held (in seconds), a negative value
1085 means no timeout. Default is 600.
1085 means no timeout. Default is 600.
1086
1086
1087 ``traceback``
1087 ``traceback``
1088 Mercurial always prints a traceback when an unknown exception
1088 Mercurial always prints a traceback when an unknown exception
1089 occurs. Setting this to True will make Mercurial print a traceback
1089 occurs. Setting this to True will make Mercurial print a traceback
1090 on all exceptions, even those recognized by Mercurial (such as
1090 on all exceptions, even those recognized by Mercurial (such as
1091 IOError or MemoryError). Default is False.
1091 IOError or MemoryError). Default is False.
1092
1092
1093 ``username``
1093 ``username``
1094 The committer of a changeset created when running "commit".
1094 The committer of a changeset created when running "commit".
1095 Typically a person's name and email address, e.g. ``Fred Widget
1095 Typically a person's name and email address, e.g. ``Fred Widget
1096 <fred@example.com>``. Default is ``$EMAIL`` or ``username@hostname``. If
1096 <fred@example.com>``. Default is ``$EMAIL`` or ``username@hostname``. If
1097 the username in hgrc is empty, it has to be specified manually or
1097 the username in hgrc is empty, it has to be specified manually or
1098 in a different hgrc file (e.g. ``$HOME/.hgrc``, if the admin set
1098 in a different hgrc file (e.g. ``$HOME/.hgrc``, if the admin set
1099 ``username =`` in the system hgrc). Environment variables in the
1099 ``username =`` in the system hgrc). Environment variables in the
1100 username are expanded.
1100 username are expanded.
1101
1101
1102 ``verbose``
1102 ``verbose``
1103 Increase the amount of output printed. True or False. Default is False.
1103 Increase the amount of output printed. True or False. Default is False.
1104
1104
1105
1105
1106 ``web``
1106 ``web``
1107 """""""
1107 """""""
1108
1108
1109 Web interface configuration. The settings in this section apply to
1109 Web interface configuration. The settings in this section apply to
1110 both the builtin webserver (started by :hg:`serve`) and the script you
1110 both the builtin webserver (started by :hg:`serve`) and the script you
1111 run through a webserver (``hgweb.cgi`` and the derivatives for FastCGI
1111 run through a webserver (``hgweb.cgi`` and the derivatives for FastCGI
1112 and WSGI).
1112 and WSGI).
1113
1113
1114 The Mercurial webserver does no authentication (it does not prompt for
1114 The Mercurial webserver does no authentication (it does not prompt for
1115 usernames and passwords to validate *who* users are), but it does do
1115 usernames and passwords to validate *who* users are), but it does do
1116 authorization (it grants or denies access for *authenticated users*
1116 authorization (it grants or denies access for *authenticated users*
1117 based on settings in this section). You must either configure your
1117 based on settings in this section). You must either configure your
1118 webserver to do authentication for you, or disable the authorization
1118 webserver to do authentication for you, or disable the authorization
1119 checks.
1119 checks.
1120
1120
1121 For a quick setup in a trusted environment, e.g., a private LAN, where
1121 For a quick setup in a trusted environment, e.g., a private LAN, where
1122 you want it to accept pushes from anybody, you can use the following
1122 you want it to accept pushes from anybody, you can use the following
1123 command line::
1123 command line::
1124
1124
1125 $ hg --config web.allow_push=* --config web.push_ssl=False serve
1125 $ hg --config web.allow_push=* --config web.push_ssl=False serve
1126
1126
1127 Note that this will allow anybody to push anything to the server and
1127 Note that this will allow anybody to push anything to the server and
1128 that this should not be used for public servers.
1128 that this should not be used for public servers.
1129
1129
1130 The full set of options is:
1130 The full set of options is:
1131
1131
1132 ``accesslog``
1132 ``accesslog``
1133 Where to output the access log. Default is stdout.
1133 Where to output the access log. Default is stdout.
1134
1134
1135 ``address``
1135 ``address``
1136 Interface address to bind to. Default is all.
1136 Interface address to bind to. Default is all.
1137
1137
1138 ``allow_archive``
1138 ``allow_archive``
1139 List of archive format (bz2, gz, zip) allowed for downloading.
1139 List of archive format (bz2, gz, zip) allowed for downloading.
1140 Default is empty.
1140 Default is empty.
1141
1141
1142 ``allowbz2``
1142 ``allowbz2``
1143 (DEPRECATED) Whether to allow .tar.bz2 downloading of repository
1143 (DEPRECATED) Whether to allow .tar.bz2 downloading of repository
1144 revisions.
1144 revisions.
1145 Default is False.
1145 Default is False.
1146
1146
1147 ``allowgz``
1147 ``allowgz``
1148 (DEPRECATED) Whether to allow .tar.gz downloading of repository
1148 (DEPRECATED) Whether to allow .tar.gz downloading of repository
1149 revisions.
1149 revisions.
1150 Default is False.
1150 Default is False.
1151
1151
1152 ``allowpull``
1152 ``allowpull``
1153 Whether to allow pulling from the repository. Default is True.
1153 Whether to allow pulling from the repository. Default is True.
1154
1154
1155 ``allow_push``
1155 ``allow_push``
1156 Whether to allow pushing to the repository. If empty or not set,
1156 Whether to allow pushing to the repository. If empty or not set,
1157 push is not allowed. If the special value ``*``, any remote user can
1157 push is not allowed. If the special value ``*``, any remote user can
1158 push, including unauthenticated users. Otherwise, the remote user
1158 push, including unauthenticated users. Otherwise, the remote user
1159 must have been authenticated, and the authenticated user name must
1159 must have been authenticated, and the authenticated user name must
1160 be present in this list. The contents of the allow_push list are
1160 be present in this list. The contents of the allow_push list are
1161 examined after the deny_push list.
1161 examined after the deny_push list.
1162
1162
1163 ``guessmime``
1163 ``guessmime``
1164 Control MIME types for raw download of file content.
1164 Control MIME types for raw download of file content.
1165 Set to True to let hgweb guess the content type from the file
1165 Set to True to let hgweb guess the content type from the file
1166 extension. This will serve HTML files as ``text/html`` and might
1166 extension. This will serve HTML files as ``text/html`` and might
1167 allow cross-site scripting attacks when serving untrusted
1167 allow cross-site scripting attacks when serving untrusted
1168 repositories. Default is False.
1168 repositories. Default is False.
1169
1169
1170 ``allow_read``
1170 ``allow_read``
1171 If the user has not already been denied repository access due to
1171 If the user has not already been denied repository access due to
1172 the contents of deny_read, this list determines whether to grant
1172 the contents of deny_read, this list determines whether to grant
1173 repository access to the user. If this list is not empty, and the
1173 repository access to the user. If this list is not empty, and the
1174 user is unauthenticated or not present in the list, then access is
1174 user is unauthenticated or not present in the list, then access is
1175 denied for the user. If the list is empty or not set, then access
1175 denied for the user. If the list is empty or not set, then access
1176 is permitted to all users by default. Setting allow_read to the
1176 is permitted to all users by default. Setting allow_read to the
1177 special value ``*`` is equivalent to it not being set (i.e. access
1177 special value ``*`` is equivalent to it not being set (i.e. access
1178 is permitted to all users). The contents of the allow_read list are
1178 is permitted to all users). The contents of the allow_read list are
1179 examined after the deny_read list.
1179 examined after the deny_read list.
1180
1180
1181 ``allowzip``
1181 ``allowzip``
1182 (DEPRECATED) Whether to allow .zip downloading of repository
1182 (DEPRECATED) Whether to allow .zip downloading of repository
1183 revisions. Default is False. This feature creates temporary files.
1183 revisions. Default is False. This feature creates temporary files.
1184
1184
1185 ``baseurl``
1185 ``baseurl``
1186 Base URL to use when publishing URLs in other locations, so
1186 Base URL to use when publishing URLs in other locations, so
1187 third-party tools like email notification hooks can construct
1187 third-party tools like email notification hooks can construct
1188 URLs. Example: ``http://hgserver/repos/``.
1188 URLs. Example: ``http://hgserver/repos/``.
1189
1189
1190 ``cacerts``
1190 ``cacerts``
1191 Path to file containing a list of PEM encoded certificate
1191 Path to file containing a list of PEM encoded certificate
1192 authority certificates. Environment variables and ``~user``
1192 authority certificates. Environment variables and ``~user``
1193 constructs are expanded in the filename. If specified on the
1193 constructs are expanded in the filename. If specified on the
1194 client, then it will verify the identity of remote HTTPS servers
1194 client, then it will verify the identity of remote HTTPS servers
1195 with these certificates. The form must be as follows::
1195 with these certificates. The form must be as follows::
1196
1196
1197 -----BEGIN CERTIFICATE-----
1197 -----BEGIN CERTIFICATE-----
1198 ... (certificate in base64 PEM encoding) ...
1198 ... (certificate in base64 PEM encoding) ...
1199 -----END CERTIFICATE-----
1199 -----END CERTIFICATE-----
1200 -----BEGIN CERTIFICATE-----
1200 -----BEGIN CERTIFICATE-----
1201 ... (certificate in base64 PEM encoding) ...
1201 ... (certificate in base64 PEM encoding) ...
1202 -----END CERTIFICATE-----
1202 -----END CERTIFICATE-----
1203
1203
1204 This feature is only supported when using Python 2.6 or later. If you wish
1204 This feature is only supported when using Python 2.6 or later. If you wish
1205 to use it with earlier versions of Python, install the backported
1205 to use it with earlier versions of Python, install the backported
1206 version of the ssl library that is available from
1206 version of the ssl library that is available from
1207 ``http://pypi.python.org``.
1207 ``http://pypi.python.org``.
1208
1208
1209 You can use OpenSSL's CA certificate file if your platform has one.
1209 You can use OpenSSL's CA certificate file if your platform has one.
1210 On most Linux systems this will be ``/etc/ssl/certs/ca-certificates.crt``.
1210 On most Linux systems this will be ``/etc/ssl/certs/ca-certificates.crt``.
1211 Otherwise you will have to generate this file manually.
1211 Otherwise you will have to generate this file manually.
1212
1212
1213 To disable SSL verification temporarily, specify ``--insecure`` from
1213 To disable SSL verification temporarily, specify ``--insecure`` from
1214 command line.
1214 command line.
1215
1215
1216 ``cache``
1216 ``cache``
1217 Whether to support caching in hgweb. Defaults to True.
1217 Whether to support caching in hgweb. Defaults to True.
1218
1218
1219 ``contact``
1219 ``contact``
1220 Name or email address of the person in charge of the repository.
1220 Name or email address of the person in charge of the repository.
1221 Defaults to ui.username or ``$EMAIL`` or "unknown" if unset or empty.
1221 Defaults to ui.username or ``$EMAIL`` or "unknown" if unset or empty.
1222
1222
1223 ``deny_push``
1223 ``deny_push``
1224 Whether to deny pushing to the repository. If empty or not set,
1224 Whether to deny pushing to the repository. If empty or not set,
1225 push is not denied. If the special value ``*``, all remote users are
1225 push is not denied. If the special value ``*``, all remote users are
1226 denied push. Otherwise, unauthenticated users are all denied, and
1226 denied push. Otherwise, unauthenticated users are all denied, and
1227 any authenticated user name present in this list is also denied. The
1227 any authenticated user name present in this list is also denied. The
1228 contents of the deny_push list are examined before the allow_push list.
1228 contents of the deny_push list are examined before the allow_push list.
1229
1229
1230 ``deny_read``
1230 ``deny_read``
1231 Whether to deny reading/viewing of the repository. If this list is
1231 Whether to deny reading/viewing of the repository. If this list is
1232 not empty, unauthenticated users are all denied, and any
1232 not empty, unauthenticated users are all denied, and any
1233 authenticated user name present in this list is also denied access to
1233 authenticated user name present in this list is also denied access to
1234 the repository. If set to the special value ``*``, all remote users
1234 the repository. If set to the special value ``*``, all remote users
1235 are denied access (rarely needed ;). If deny_read is empty or not set,
1235 are denied access (rarely needed ;). If deny_read is empty or not set,
1236 the determination of repository access depends on the presence and
1236 the determination of repository access depends on the presence and
1237 content of the allow_read list (see description). If both
1237 content of the allow_read list (see description). If both
1238 deny_read and allow_read are empty or not set, then access is
1238 deny_read and allow_read are empty or not set, then access is
1239 permitted to all users by default. If the repository is being
1239 permitted to all users by default. If the repository is being
1240 served via hgwebdir, denied users will not be able to see it in
1240 served via hgwebdir, denied users will not be able to see it in
1241 the list of repositories. The contents of the deny_read list have
1241 the list of repositories. The contents of the deny_read list have
1242 priority over (are examined before) the contents of the allow_read
1242 priority over (are examined before) the contents of the allow_read
1243 list.
1243 list.
1244
1244
1245 ``descend``
1245 ``descend``
1246 hgwebdir indexes will not descend into subdirectories. Only repositories
1246 hgwebdir indexes will not descend into subdirectories. Only repositories
1247 directly in the current path will be shown (other repositories are still
1247 directly in the current path will be shown (other repositories are still
1248 available from the index corresponding to their containing path).
1248 available from the index corresponding to their containing path).
1249
1249
1250 ``description``
1250 ``description``
1251 Textual description of the repository's purpose or contents.
1251 Textual description of the repository's purpose or contents.
1252 Default is "unknown".
1252 Default is "unknown".
1253
1253
1254 ``encoding``
1254 ``encoding``
1255 Character encoding name. Default is the current locale charset.
1255 Character encoding name. Default is the current locale charset.
1256 Example: "UTF-8"
1256 Example: "UTF-8"
1257
1257
1258 ``errorlog``
1258 ``errorlog``
1259 Where to output the error log. Default is stderr.
1259 Where to output the error log. Default is stderr.
1260
1260
1261 ``hidden``
1261 ``hidden``
1262 Whether to hide the repository in the hgwebdir index.
1262 Whether to hide the repository in the hgwebdir index.
1263 Default is False.
1263 Default is False.
1264
1264
1265 ``ipv6``
1265 ``ipv6``
1266 Whether to use IPv6. Default is False.
1266 Whether to use IPv6. Default is False.
1267
1267
1268 ``logoimg``
1268 ``logoimg``
1269 File name of the logo image that some templates display on each page.
1269 File name of the logo image that some templates display on each page.
1270 The file name is relative to ``staticurl``. That is, the full path to
1270 The file name is relative to ``staticurl``. That is, the full path to
1271 the logo image is "staticurl/logoimg".
1271 the logo image is "staticurl/logoimg".
1272 If unset, ``hglogo.png`` will be used.
1272 If unset, ``hglogo.png`` will be used.
1273
1273
1274 ``logourl``
1274 ``logourl``
1275 Base URL to use for logos. If unset, ``http://mercurial.selenic.com/``
1275 Base URL to use for logos. If unset, ``http://mercurial.selenic.com/``
1276 will be used.
1276 will be used.
1277
1277
1278 ``name``
1278 ``name``
1279 Repository name to use in the web interface. Default is current
1279 Repository name to use in the web interface. Default is current
1280 working directory.
1280 working directory.
1281
1281
1282 ``maxchanges``
1282 ``maxchanges``
1283 Maximum number of changes to list on the changelog. Default is 10.
1283 Maximum number of changes to list on the changelog. Default is 10.
1284
1284
1285 ``maxfiles``
1285 ``maxfiles``
1286 Maximum number of files to list per changeset. Default is 10.
1286 Maximum number of files to list per changeset. Default is 10.
1287
1287
1288 ``port``
1288 ``port``
1289 Port to listen on. Default is 8000.
1289 Port to listen on. Default is 8000.
1290
1290
1291 ``prefix``
1291 ``prefix``
1292 Prefix path to serve from. Default is '' (server root).
1292 Prefix path to serve from. Default is '' (server root).
1293
1293
1294 ``push_ssl``
1294 ``push_ssl``
1295 Whether to require that inbound pushes be transported over SSL to
1295 Whether to require that inbound pushes be transported over SSL to
1296 prevent password sniffing. Default is True.
1296 prevent password sniffing. Default is True.
1297
1297
1298 ``staticurl``
1298 ``staticurl``
1299 Base URL to use for static files. If unset, static files (e.g. the
1299 Base URL to use for static files. If unset, static files (e.g. the
1300 hgicon.png favicon) will be served by the CGI script itself. Use
1300 hgicon.png favicon) will be served by the CGI script itself. Use
1301 this setting to serve them directly with the HTTP server.
1301 this setting to serve them directly with the HTTP server.
1302 Example: ``http://hgserver/static/``.
1302 Example: ``http://hgserver/static/``.
1303
1303
1304 ``stripes``
1304 ``stripes``
1305 How many lines a "zebra stripe" should span in multiline output.
1305 How many lines a "zebra stripe" should span in multiline output.
1306 Default is 1; set to 0 to disable.
1306 Default is 1; set to 0 to disable.
1307
1307
1308 ``style``
1308 ``style``
1309 Which template map style to use.
1309 Which template map style to use.
1310
1310
1311 ``templates``
1311 ``templates``
1312 Where to find the HTML templates. Default is install path.
1312 Where to find the HTML templates. Default is install path.
@@ -1,2084 +1,2085 b''
1 # localrepo.py - read/write repository class for mercurial
1 # localrepo.py - read/write repository class 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 bin, hex, nullid, nullrev, short
8 from node import bin, hex, nullid, nullrev, short
9 from i18n import _
9 from i18n import _
10 import repo, changegroup, subrepo, discovery, pushkey
10 import repo, changegroup, subrepo, discovery, pushkey
11 import changelog, dirstate, filelog, manifest, context, bookmarks
11 import changelog, dirstate, filelog, manifest, context, bookmarks
12 import lock, transaction, store, encoding
12 import lock, transaction, store, encoding
13 import scmutil, util, extensions, hook, error, revset
13 import scmutil, util, extensions, hook, error, revset
14 import match as matchmod
14 import match as matchmod
15 import merge as mergemod
15 import merge as mergemod
16 import tags as tagsmod
16 import tags as tagsmod
17 from lock import release
17 from lock import release
18 import weakref, errno, os, time, inspect
18 import weakref, errno, os, time, inspect
19 propertycache = util.propertycache
19 propertycache = util.propertycache
20 filecache = scmutil.filecache
20 filecache = scmutil.filecache
21
21
22 class localrepository(repo.repository):
22 class localrepository(repo.repository):
23 capabilities = set(('lookup', 'changegroupsubset', 'branchmap', 'pushkey',
23 capabilities = set(('lookup', 'changegroupsubset', 'branchmap', 'pushkey',
24 'known', 'getbundle'))
24 'known', 'getbundle'))
25 supportedformats = set(('revlogv1', 'generaldelta'))
25 supportedformats = set(('revlogv1', 'generaldelta'))
26 supported = supportedformats | set(('store', 'fncache', 'shared',
26 supported = supportedformats | set(('store', 'fncache', 'shared',
27 'dotencode'))
27 'dotencode'))
28
28
29 def __init__(self, baseui, path=None, create=False):
29 def __init__(self, baseui, path=None, create=False):
30 repo.repository.__init__(self)
30 repo.repository.__init__(self)
31 self.root = os.path.realpath(util.expandpath(path))
31 self.root = os.path.realpath(util.expandpath(path))
32 self.path = os.path.join(self.root, ".hg")
32 self.path = os.path.join(self.root, ".hg")
33 self.origroot = path
33 self.origroot = path
34 self.auditor = scmutil.pathauditor(self.root, self._checknested)
34 self.auditor = scmutil.pathauditor(self.root, self._checknested)
35 self.opener = scmutil.opener(self.path)
35 self.opener = scmutil.opener(self.path)
36 self.wopener = scmutil.opener(self.root)
36 self.wopener = scmutil.opener(self.root)
37 self.baseui = baseui
37 self.baseui = baseui
38 self.ui = baseui.copy()
38 self.ui = baseui.copy()
39
39
40 try:
40 try:
41 self.ui.readconfig(self.join("hgrc"), self.root)
41 self.ui.readconfig(self.join("hgrc"), self.root)
42 extensions.loadall(self.ui)
42 extensions.loadall(self.ui)
43 except IOError:
43 except IOError:
44 pass
44 pass
45
45
46 if not os.path.isdir(self.path):
46 if not os.path.isdir(self.path):
47 if create:
47 if create:
48 if not os.path.exists(path):
48 if not os.path.exists(path):
49 util.makedirs(path)
49 util.makedirs(path)
50 util.makedir(self.path, notindexed=True)
50 util.makedir(self.path, notindexed=True)
51 requirements = ["revlogv1"]
51 requirements = ["revlogv1"]
52 if self.ui.configbool('format', 'usestore', True):
52 if self.ui.configbool('format', 'usestore', True):
53 os.mkdir(os.path.join(self.path, "store"))
53 os.mkdir(os.path.join(self.path, "store"))
54 requirements.append("store")
54 requirements.append("store")
55 if self.ui.configbool('format', 'usefncache', True):
55 if self.ui.configbool('format', 'usefncache', True):
56 requirements.append("fncache")
56 requirements.append("fncache")
57 if self.ui.configbool('format', 'dotencode', True):
57 if self.ui.configbool('format', 'dotencode', True):
58 requirements.append('dotencode')
58 requirements.append('dotencode')
59 # create an invalid changelog
59 # create an invalid changelog
60 self.opener.append(
60 self.opener.append(
61 "00changelog.i",
61 "00changelog.i",
62 '\0\0\0\2' # represents revlogv2
62 '\0\0\0\2' # represents revlogv2
63 ' dummy changelog to prevent using the old repo layout'
63 ' dummy changelog to prevent using the old repo layout'
64 )
64 )
65 if self.ui.configbool('format', 'generaldelta', False):
65 if self.ui.configbool('format', 'generaldelta', False):
66 requirements.append("generaldelta")
66 requirements.append("generaldelta")
67 requirements = set(requirements)
67 requirements = set(requirements)
68 else:
68 else:
69 raise error.RepoError(_("repository %s not found") % path)
69 raise error.RepoError(_("repository %s not found") % path)
70 elif create:
70 elif create:
71 raise error.RepoError(_("repository %s already exists") % path)
71 raise error.RepoError(_("repository %s already exists") % path)
72 else:
72 else:
73 try:
73 try:
74 requirements = scmutil.readrequires(self.opener, self.supported)
74 requirements = scmutil.readrequires(self.opener, self.supported)
75 except IOError, inst:
75 except IOError, inst:
76 if inst.errno != errno.ENOENT:
76 if inst.errno != errno.ENOENT:
77 raise
77 raise
78 requirements = set()
78 requirements = set()
79
79
80 self.sharedpath = self.path
80 self.sharedpath = self.path
81 try:
81 try:
82 s = os.path.realpath(self.opener.read("sharedpath").rstrip('\n'))
82 s = os.path.realpath(self.opener.read("sharedpath").rstrip('\n'))
83 if not os.path.exists(s):
83 if not os.path.exists(s):
84 raise error.RepoError(
84 raise error.RepoError(
85 _('.hg/sharedpath points to nonexistent directory %s') % s)
85 _('.hg/sharedpath points to nonexistent directory %s') % s)
86 self.sharedpath = s
86 self.sharedpath = s
87 except IOError, inst:
87 except IOError, inst:
88 if inst.errno != errno.ENOENT:
88 if inst.errno != errno.ENOENT:
89 raise
89 raise
90
90
91 self.store = store.store(requirements, self.sharedpath, scmutil.opener)
91 self.store = store.store(requirements, self.sharedpath, scmutil.opener)
92 self.spath = self.store.path
92 self.spath = self.store.path
93 self.sopener = self.store.opener
93 self.sopener = self.store.opener
94 self.sjoin = self.store.join
94 self.sjoin = self.store.join
95 self.opener.createmode = self.store.createmode
95 self.opener.createmode = self.store.createmode
96 self._applyrequirements(requirements)
96 self._applyrequirements(requirements)
97 if create:
97 if create:
98 self._writerequirements()
98 self._writerequirements()
99
99
100
100
101 self._branchcache = None
101 self._branchcache = None
102 self._branchcachetip = None
102 self._branchcachetip = None
103 self.filterpats = {}
103 self.filterpats = {}
104 self._datafilters = {}
104 self._datafilters = {}
105 self._transref = self._lockref = self._wlockref = None
105 self._transref = self._lockref = self._wlockref = None
106
106
107 # A cache for various files under .hg/ that tracks file changes,
107 # A cache for various files under .hg/ that tracks file changes,
108 # (used by the filecache decorator)
108 # (used by the filecache decorator)
109 #
109 #
110 # Maps a property name to its util.filecacheentry
110 # Maps a property name to its util.filecacheentry
111 self._filecache = {}
111 self._filecache = {}
112
112
113 def _applyrequirements(self, requirements):
113 def _applyrequirements(self, requirements):
114 self.requirements = requirements
114 self.requirements = requirements
115 openerreqs = set(('revlogv1', 'generaldelta'))
115 openerreqs = set(('revlogv1', 'generaldelta'))
116 self.sopener.options = dict((r, 1) for r in requirements
116 self.sopener.options = dict((r, 1) for r in requirements
117 if r in openerreqs)
117 if r in openerreqs)
118
118
119 def _writerequirements(self):
119 def _writerequirements(self):
120 reqfile = self.opener("requires", "w")
120 reqfile = self.opener("requires", "w")
121 for r in self.requirements:
121 for r in self.requirements:
122 reqfile.write("%s\n" % r)
122 reqfile.write("%s\n" % r)
123 reqfile.close()
123 reqfile.close()
124
124
125 def _checknested(self, path):
125 def _checknested(self, path):
126 """Determine if path is a legal nested repository."""
126 """Determine if path is a legal nested repository."""
127 if not path.startswith(self.root):
127 if not path.startswith(self.root):
128 return False
128 return False
129 subpath = path[len(self.root) + 1:]
129 subpath = path[len(self.root) + 1:]
130
130
131 # XXX: Checking against the current working copy is wrong in
131 # XXX: Checking against the current working copy is wrong in
132 # the sense that it can reject things like
132 # the sense that it can reject things like
133 #
133 #
134 # $ hg cat -r 10 sub/x.txt
134 # $ hg cat -r 10 sub/x.txt
135 #
135 #
136 # if sub/ is no longer a subrepository in the working copy
136 # if sub/ is no longer a subrepository in the working copy
137 # parent revision.
137 # parent revision.
138 #
138 #
139 # However, it can of course also allow things that would have
139 # However, it can of course also allow things that would have
140 # been rejected before, such as the above cat command if sub/
140 # been rejected before, such as the above cat command if sub/
141 # is a subrepository now, but was a normal directory before.
141 # is a subrepository now, but was a normal directory before.
142 # The old path auditor would have rejected by mistake since it
142 # The old path auditor would have rejected by mistake since it
143 # panics when it sees sub/.hg/.
143 # panics when it sees sub/.hg/.
144 #
144 #
145 # All in all, checking against the working copy seems sensible
145 # All in all, checking against the working copy seems sensible
146 # since we want to prevent access to nested repositories on
146 # since we want to prevent access to nested repositories on
147 # the filesystem *now*.
147 # the filesystem *now*.
148 ctx = self[None]
148 ctx = self[None]
149 parts = util.splitpath(subpath)
149 parts = util.splitpath(subpath)
150 while parts:
150 while parts:
151 prefix = os.sep.join(parts)
151 prefix = os.sep.join(parts)
152 if prefix in ctx.substate:
152 if prefix in ctx.substate:
153 if prefix == subpath:
153 if prefix == subpath:
154 return True
154 return True
155 else:
155 else:
156 sub = ctx.sub(prefix)
156 sub = ctx.sub(prefix)
157 return sub.checknested(subpath[len(prefix) + 1:])
157 return sub.checknested(subpath[len(prefix) + 1:])
158 else:
158 else:
159 parts.pop()
159 parts.pop()
160 return False
160 return False
161
161
162 @filecache('bookmarks')
162 @filecache('bookmarks')
163 def _bookmarks(self):
163 def _bookmarks(self):
164 return bookmarks.read(self)
164 return bookmarks.read(self)
165
165
166 @filecache('bookmarks.current')
166 @filecache('bookmarks.current')
167 def _bookmarkcurrent(self):
167 def _bookmarkcurrent(self):
168 return bookmarks.readcurrent(self)
168 return bookmarks.readcurrent(self)
169
169
170 def _writebookmarks(self, marks):
170 def _writebookmarks(self, marks):
171 bookmarks.write(self)
171 bookmarks.write(self)
172
172
173 @filecache('00changelog.i', True)
173 @filecache('00changelog.i', True)
174 def changelog(self):
174 def changelog(self):
175 c = changelog.changelog(self.sopener)
175 c = changelog.changelog(self.sopener)
176 if 'HG_PENDING' in os.environ:
176 if 'HG_PENDING' in os.environ:
177 p = os.environ['HG_PENDING']
177 p = os.environ['HG_PENDING']
178 if p.startswith(self.root):
178 if p.startswith(self.root):
179 c.readpending('00changelog.i.a')
179 c.readpending('00changelog.i.a')
180 return c
180 return c
181
181
182 @filecache('00manifest.i', True)
182 @filecache('00manifest.i', True)
183 def manifest(self):
183 def manifest(self):
184 return manifest.manifest(self.sopener)
184 return manifest.manifest(self.sopener)
185
185
186 @filecache('dirstate')
186 @filecache('dirstate')
187 def dirstate(self):
187 def dirstate(self):
188 warned = [0]
188 warned = [0]
189 def validate(node):
189 def validate(node):
190 try:
190 try:
191 self.changelog.rev(node)
191 self.changelog.rev(node)
192 return node
192 return node
193 except error.LookupError:
193 except error.LookupError:
194 if not warned[0]:
194 if not warned[0]:
195 warned[0] = True
195 warned[0] = True
196 self.ui.warn(_("warning: ignoring unknown"
196 self.ui.warn(_("warning: ignoring unknown"
197 " working parent %s!\n") % short(node))
197 " working parent %s!\n") % short(node))
198 return nullid
198 return nullid
199
199
200 return dirstate.dirstate(self.opener, self.ui, self.root, validate)
200 return dirstate.dirstate(self.opener, self.ui, self.root, validate)
201
201
202 def __getitem__(self, changeid):
202 def __getitem__(self, changeid):
203 if changeid is None:
203 if changeid is None:
204 return context.workingctx(self)
204 return context.workingctx(self)
205 return context.changectx(self, changeid)
205 return context.changectx(self, changeid)
206
206
207 def __contains__(self, changeid):
207 def __contains__(self, changeid):
208 try:
208 try:
209 return bool(self.lookup(changeid))
209 return bool(self.lookup(changeid))
210 except error.RepoLookupError:
210 except error.RepoLookupError:
211 return False
211 return False
212
212
213 def __nonzero__(self):
213 def __nonzero__(self):
214 return True
214 return True
215
215
216 def __len__(self):
216 def __len__(self):
217 return len(self.changelog)
217 return len(self.changelog)
218
218
219 def __iter__(self):
219 def __iter__(self):
220 for i in xrange(len(self)):
220 for i in xrange(len(self)):
221 yield i
221 yield i
222
222
223 def set(self, expr, *args):
223 def set(self, expr, *args):
224 '''
224 '''
225 Yield a context for each matching revision, after doing arg
225 Yield a context for each matching revision, after doing arg
226 replacement via revset.formatspec
226 replacement via revset.formatspec
227 '''
227 '''
228
228
229 expr = revset.formatspec(expr, *args)
229 expr = revset.formatspec(expr, *args)
230 m = revset.match(None, expr)
230 m = revset.match(None, expr)
231 for r in m(self, range(len(self))):
231 for r in m(self, range(len(self))):
232 yield self[r]
232 yield self[r]
233
233
234 def url(self):
234 def url(self):
235 return 'file:' + self.root
235 return 'file:' + self.root
236
236
237 def hook(self, name, throw=False, **args):
237 def hook(self, name, throw=False, **args):
238 return hook.hook(self.ui, self, name, throw, **args)
238 return hook.hook(self.ui, self, name, throw, **args)
239
239
240 tag_disallowed = ':\r\n'
240 tag_disallowed = ':\r\n'
241
241
242 def _tag(self, names, node, message, local, user, date, extra={}):
242 def _tag(self, names, node, message, local, user, date, extra={}):
243 if isinstance(names, str):
243 if isinstance(names, str):
244 allchars = names
244 allchars = names
245 names = (names,)
245 names = (names,)
246 else:
246 else:
247 allchars = ''.join(names)
247 allchars = ''.join(names)
248 for c in self.tag_disallowed:
248 for c in self.tag_disallowed:
249 if c in allchars:
249 if c in allchars:
250 raise util.Abort(_('%r cannot be used in a tag name') % c)
250 raise util.Abort(_('%r cannot be used in a tag name') % c)
251
251
252 branches = self.branchmap()
252 branches = self.branchmap()
253 for name in names:
253 for name in names:
254 self.hook('pretag', throw=True, node=hex(node), tag=name,
254 self.hook('pretag', throw=True, node=hex(node), tag=name,
255 local=local)
255 local=local)
256 if name in branches:
256 if name in branches:
257 self.ui.warn(_("warning: tag %s conflicts with existing"
257 self.ui.warn(_("warning: tag %s conflicts with existing"
258 " branch name\n") % name)
258 " branch name\n") % name)
259
259
260 def writetags(fp, names, munge, prevtags):
260 def writetags(fp, names, munge, prevtags):
261 fp.seek(0, 2)
261 fp.seek(0, 2)
262 if prevtags and prevtags[-1] != '\n':
262 if prevtags and prevtags[-1] != '\n':
263 fp.write('\n')
263 fp.write('\n')
264 for name in names:
264 for name in names:
265 m = munge and munge(name) or name
265 m = munge and munge(name) or name
266 if self._tagscache.tagtypes and name in self._tagscache.tagtypes:
266 if self._tagscache.tagtypes and name in self._tagscache.tagtypes:
267 old = self.tags().get(name, nullid)
267 old = self.tags().get(name, nullid)
268 fp.write('%s %s\n' % (hex(old), m))
268 fp.write('%s %s\n' % (hex(old), m))
269 fp.write('%s %s\n' % (hex(node), m))
269 fp.write('%s %s\n' % (hex(node), m))
270 fp.close()
270 fp.close()
271
271
272 prevtags = ''
272 prevtags = ''
273 if local:
273 if local:
274 try:
274 try:
275 fp = self.opener('localtags', 'r+')
275 fp = self.opener('localtags', 'r+')
276 except IOError:
276 except IOError:
277 fp = self.opener('localtags', 'a')
277 fp = self.opener('localtags', 'a')
278 else:
278 else:
279 prevtags = fp.read()
279 prevtags = fp.read()
280
280
281 # local tags are stored in the current charset
281 # local tags are stored in the current charset
282 writetags(fp, names, None, prevtags)
282 writetags(fp, names, None, prevtags)
283 for name in names:
283 for name in names:
284 self.hook('tag', node=hex(node), tag=name, local=local)
284 self.hook('tag', node=hex(node), tag=name, local=local)
285 return
285 return
286
286
287 try:
287 try:
288 fp = self.wfile('.hgtags', 'rb+')
288 fp = self.wfile('.hgtags', 'rb+')
289 except IOError, e:
289 except IOError, e:
290 if e.errno != errno.ENOENT:
290 if e.errno != errno.ENOENT:
291 raise
291 raise
292 fp = self.wfile('.hgtags', 'ab')
292 fp = self.wfile('.hgtags', 'ab')
293 else:
293 else:
294 prevtags = fp.read()
294 prevtags = fp.read()
295
295
296 # committed tags are stored in UTF-8
296 # committed tags are stored in UTF-8
297 writetags(fp, names, encoding.fromlocal, prevtags)
297 writetags(fp, names, encoding.fromlocal, prevtags)
298
298
299 fp.close()
299 fp.close()
300
300
301 if '.hgtags' not in self.dirstate:
301 if '.hgtags' not in self.dirstate:
302 self[None].add(['.hgtags'])
302 self[None].add(['.hgtags'])
303
303
304 m = matchmod.exact(self.root, '', ['.hgtags'])
304 m = matchmod.exact(self.root, '', ['.hgtags'])
305 tagnode = self.commit(message, user, date, extra=extra, match=m)
305 tagnode = self.commit(message, user, date, extra=extra, match=m)
306
306
307 for name in names:
307 for name in names:
308 self.hook('tag', node=hex(node), tag=name, local=local)
308 self.hook('tag', node=hex(node), tag=name, local=local)
309
309
310 return tagnode
310 return tagnode
311
311
312 def tag(self, names, node, message, local, user, date):
312 def tag(self, names, node, message, local, user, date):
313 '''tag a revision with one or more symbolic names.
313 '''tag a revision with one or more symbolic names.
314
314
315 names is a list of strings or, when adding a single tag, names may be a
315 names is a list of strings or, when adding a single tag, names may be a
316 string.
316 string.
317
317
318 if local is True, the tags are stored in a per-repository file.
318 if local is True, the tags are stored in a per-repository file.
319 otherwise, they are stored in the .hgtags file, and a new
319 otherwise, they are stored in the .hgtags file, and a new
320 changeset is committed with the change.
320 changeset is committed with the change.
321
321
322 keyword arguments:
322 keyword arguments:
323
323
324 local: whether to store tags in non-version-controlled file
324 local: whether to store tags in non-version-controlled file
325 (default False)
325 (default False)
326
326
327 message: commit message to use if committing
327 message: commit message to use if committing
328
328
329 user: name of user to use if committing
329 user: name of user to use if committing
330
330
331 date: date tuple to use if committing'''
331 date: date tuple to use if committing'''
332
332
333 if not local:
333 if not local:
334 for x in self.status()[:5]:
334 for x in self.status()[:5]:
335 if '.hgtags' in x:
335 if '.hgtags' in x:
336 raise util.Abort(_('working copy of .hgtags is changed '
336 raise util.Abort(_('working copy of .hgtags is changed '
337 '(please commit .hgtags manually)'))
337 '(please commit .hgtags manually)'))
338
338
339 self.tags() # instantiate the cache
339 self.tags() # instantiate the cache
340 self._tag(names, node, message, local, user, date)
340 self._tag(names, node, message, local, user, date)
341
341
342 @propertycache
342 @propertycache
343 def _tagscache(self):
343 def _tagscache(self):
344 '''Returns a tagscache object that contains various tags related caches.'''
344 '''Returns a tagscache object that contains various tags related caches.'''
345
345
346 # This simplifies its cache management by having one decorated
346 # This simplifies its cache management by having one decorated
347 # function (this one) and the rest simply fetch things from it.
347 # function (this one) and the rest simply fetch things from it.
348 class tagscache(object):
348 class tagscache(object):
349 def __init__(self):
349 def __init__(self):
350 # These two define the set of tags for this repository. tags
350 # These two define the set of tags for this repository. tags
351 # maps tag name to node; tagtypes maps tag name to 'global' or
351 # maps tag name to node; tagtypes maps tag name to 'global' or
352 # 'local'. (Global tags are defined by .hgtags across all
352 # 'local'. (Global tags are defined by .hgtags across all
353 # heads, and local tags are defined in .hg/localtags.)
353 # heads, and local tags are defined in .hg/localtags.)
354 # They constitute the in-memory cache of tags.
354 # They constitute the in-memory cache of tags.
355 self.tags = self.tagtypes = None
355 self.tags = self.tagtypes = None
356
356
357 self.nodetagscache = self.tagslist = None
357 self.nodetagscache = self.tagslist = None
358
358
359 cache = tagscache()
359 cache = tagscache()
360 cache.tags, cache.tagtypes = self._findtags()
360 cache.tags, cache.tagtypes = self._findtags()
361
361
362 return cache
362 return cache
363
363
364 def tags(self):
364 def tags(self):
365 '''return a mapping of tag to node'''
365 '''return a mapping of tag to node'''
366 return self._tagscache.tags
366 return self._tagscache.tags
367
367
368 def _findtags(self):
368 def _findtags(self):
369 '''Do the hard work of finding tags. Return a pair of dicts
369 '''Do the hard work of finding tags. Return a pair of dicts
370 (tags, tagtypes) where tags maps tag name to node, and tagtypes
370 (tags, tagtypes) where tags maps tag name to node, and tagtypes
371 maps tag name to a string like \'global\' or \'local\'.
371 maps tag name to a string like \'global\' or \'local\'.
372 Subclasses or extensions are free to add their own tags, but
372 Subclasses or extensions are free to add their own tags, but
373 should be aware that the returned dicts will be retained for the
373 should be aware that the returned dicts will be retained for the
374 duration of the localrepo object.'''
374 duration of the localrepo object.'''
375
375
376 # XXX what tagtype should subclasses/extensions use? Currently
376 # XXX what tagtype should subclasses/extensions use? Currently
377 # mq and bookmarks add tags, but do not set the tagtype at all.
377 # mq and bookmarks add tags, but do not set the tagtype at all.
378 # Should each extension invent its own tag type? Should there
378 # Should each extension invent its own tag type? Should there
379 # be one tagtype for all such "virtual" tags? Or is the status
379 # be one tagtype for all such "virtual" tags? Or is the status
380 # quo fine?
380 # quo fine?
381
381
382 alltags = {} # map tag name to (node, hist)
382 alltags = {} # map tag name to (node, hist)
383 tagtypes = {}
383 tagtypes = {}
384
384
385 tagsmod.findglobaltags(self.ui, self, alltags, tagtypes)
385 tagsmod.findglobaltags(self.ui, self, alltags, tagtypes)
386 tagsmod.readlocaltags(self.ui, self, alltags, tagtypes)
386 tagsmod.readlocaltags(self.ui, self, alltags, tagtypes)
387
387
388 # Build the return dicts. Have to re-encode tag names because
388 # Build the return dicts. Have to re-encode tag names because
389 # the tags module always uses UTF-8 (in order not to lose info
389 # the tags module always uses UTF-8 (in order not to lose info
390 # writing to the cache), but the rest of Mercurial wants them in
390 # writing to the cache), but the rest of Mercurial wants them in
391 # local encoding.
391 # local encoding.
392 tags = {}
392 tags = {}
393 for (name, (node, hist)) in alltags.iteritems():
393 for (name, (node, hist)) in alltags.iteritems():
394 if node != nullid:
394 if node != nullid:
395 try:
395 try:
396 # ignore tags to unknown nodes
396 # ignore tags to unknown nodes
397 self.changelog.lookup(node)
397 self.changelog.lookup(node)
398 tags[encoding.tolocal(name)] = node
398 tags[encoding.tolocal(name)] = node
399 except error.LookupError:
399 except error.LookupError:
400 pass
400 pass
401 tags['tip'] = self.changelog.tip()
401 tags['tip'] = self.changelog.tip()
402 tagtypes = dict([(encoding.tolocal(name), value)
402 tagtypes = dict([(encoding.tolocal(name), value)
403 for (name, value) in tagtypes.iteritems()])
403 for (name, value) in tagtypes.iteritems()])
404 return (tags, tagtypes)
404 return (tags, tagtypes)
405
405
406 def tagtype(self, tagname):
406 def tagtype(self, tagname):
407 '''
407 '''
408 return the type of the given tag. result can be:
408 return the type of the given tag. result can be:
409
409
410 'local' : a local tag
410 'local' : a local tag
411 'global' : a global tag
411 'global' : a global tag
412 None : tag does not exist
412 None : tag does not exist
413 '''
413 '''
414
414
415 return self._tagscache.tagtypes.get(tagname)
415 return self._tagscache.tagtypes.get(tagname)
416
416
417 def tagslist(self):
417 def tagslist(self):
418 '''return a list of tags ordered by revision'''
418 '''return a list of tags ordered by revision'''
419 if not self._tagscache.tagslist:
419 if not self._tagscache.tagslist:
420 l = []
420 l = []
421 for t, n in self.tags().iteritems():
421 for t, n in self.tags().iteritems():
422 r = self.changelog.rev(n)
422 r = self.changelog.rev(n)
423 l.append((r, t, n))
423 l.append((r, t, n))
424 self._tagscache.tagslist = [(t, n) for r, t, n in sorted(l)]
424 self._tagscache.tagslist = [(t, n) for r, t, n in sorted(l)]
425
425
426 return self._tagscache.tagslist
426 return self._tagscache.tagslist
427
427
428 def nodetags(self, node):
428 def nodetags(self, node):
429 '''return the tags associated with a node'''
429 '''return the tags associated with a node'''
430 if not self._tagscache.nodetagscache:
430 if not self._tagscache.nodetagscache:
431 nodetagscache = {}
431 nodetagscache = {}
432 for t, n in self.tags().iteritems():
432 for t, n in self.tags().iteritems():
433 nodetagscache.setdefault(n, []).append(t)
433 nodetagscache.setdefault(n, []).append(t)
434 for tags in nodetagscache.itervalues():
434 for tags in nodetagscache.itervalues():
435 tags.sort()
435 tags.sort()
436 self._tagscache.nodetagscache = nodetagscache
436 self._tagscache.nodetagscache = nodetagscache
437 return self._tagscache.nodetagscache.get(node, [])
437 return self._tagscache.nodetagscache.get(node, [])
438
438
439 def nodebookmarks(self, node):
439 def nodebookmarks(self, node):
440 marks = []
440 marks = []
441 for bookmark, n in self._bookmarks.iteritems():
441 for bookmark, n in self._bookmarks.iteritems():
442 if n == node:
442 if n == node:
443 marks.append(bookmark)
443 marks.append(bookmark)
444 return sorted(marks)
444 return sorted(marks)
445
445
446 def _branchtags(self, partial, lrev):
446 def _branchtags(self, partial, lrev):
447 # TODO: rename this function?
447 # TODO: rename this function?
448 tiprev = len(self) - 1
448 tiprev = len(self) - 1
449 if lrev != tiprev:
449 if lrev != tiprev:
450 ctxgen = (self[r] for r in xrange(lrev + 1, tiprev + 1))
450 ctxgen = (self[r] for r in xrange(lrev + 1, tiprev + 1))
451 self._updatebranchcache(partial, ctxgen)
451 self._updatebranchcache(partial, ctxgen)
452 self._writebranchcache(partial, self.changelog.tip(), tiprev)
452 self._writebranchcache(partial, self.changelog.tip(), tiprev)
453
453
454 return partial
454 return partial
455
455
456 def updatebranchcache(self):
456 def updatebranchcache(self):
457 tip = self.changelog.tip()
457 tip = self.changelog.tip()
458 if self._branchcache is not None and self._branchcachetip == tip:
458 if self._branchcache is not None and self._branchcachetip == tip:
459 return self._branchcache
459 return self._branchcache
460
460
461 oldtip = self._branchcachetip
461 oldtip = self._branchcachetip
462 self._branchcachetip = tip
462 self._branchcachetip = tip
463 if oldtip is None or oldtip not in self.changelog.nodemap:
463 if oldtip is None or oldtip not in self.changelog.nodemap:
464 partial, last, lrev = self._readbranchcache()
464 partial, last, lrev = self._readbranchcache()
465 else:
465 else:
466 lrev = self.changelog.rev(oldtip)
466 lrev = self.changelog.rev(oldtip)
467 partial = self._branchcache
467 partial = self._branchcache
468
468
469 self._branchtags(partial, lrev)
469 self._branchtags(partial, lrev)
470 # this private cache holds all heads (not just tips)
470 # this private cache holds all heads (not just tips)
471 self._branchcache = partial
471 self._branchcache = partial
472
472
473 def branchmap(self):
473 def branchmap(self):
474 '''returns a dictionary {branch: [branchheads]}'''
474 '''returns a dictionary {branch: [branchheads]}'''
475 self.updatebranchcache()
475 self.updatebranchcache()
476 return self._branchcache
476 return self._branchcache
477
477
478 def branchtags(self):
478 def branchtags(self):
479 '''return a dict where branch names map to the tipmost head of
479 '''return a dict where branch names map to the tipmost head of
480 the branch, open heads come before closed'''
480 the branch, open heads come before closed'''
481 bt = {}
481 bt = {}
482 for bn, heads in self.branchmap().iteritems():
482 for bn, heads in self.branchmap().iteritems():
483 tip = heads[-1]
483 tip = heads[-1]
484 for h in reversed(heads):
484 for h in reversed(heads):
485 if 'close' not in self.changelog.read(h)[5]:
485 if 'close' not in self.changelog.read(h)[5]:
486 tip = h
486 tip = h
487 break
487 break
488 bt[bn] = tip
488 bt[bn] = tip
489 return bt
489 return bt
490
490
491 def _readbranchcache(self):
491 def _readbranchcache(self):
492 partial = {}
492 partial = {}
493 try:
493 try:
494 f = self.opener("cache/branchheads")
494 f = self.opener("cache/branchheads")
495 lines = f.read().split('\n')
495 lines = f.read().split('\n')
496 f.close()
496 f.close()
497 except (IOError, OSError):
497 except (IOError, OSError):
498 return {}, nullid, nullrev
498 return {}, nullid, nullrev
499
499
500 try:
500 try:
501 last, lrev = lines.pop(0).split(" ", 1)
501 last, lrev = lines.pop(0).split(" ", 1)
502 last, lrev = bin(last), int(lrev)
502 last, lrev = bin(last), int(lrev)
503 if lrev >= len(self) or self[lrev].node() != last:
503 if lrev >= len(self) or self[lrev].node() != last:
504 # invalidate the cache
504 # invalidate the cache
505 raise ValueError('invalidating branch cache (tip differs)')
505 raise ValueError('invalidating branch cache (tip differs)')
506 for l in lines:
506 for l in lines:
507 if not l:
507 if not l:
508 continue
508 continue
509 node, label = l.split(" ", 1)
509 node, label = l.split(" ", 1)
510 label = encoding.tolocal(label.strip())
510 label = encoding.tolocal(label.strip())
511 partial.setdefault(label, []).append(bin(node))
511 partial.setdefault(label, []).append(bin(node))
512 except KeyboardInterrupt:
512 except KeyboardInterrupt:
513 raise
513 raise
514 except Exception, inst:
514 except Exception, inst:
515 if self.ui.debugflag:
515 if self.ui.debugflag:
516 self.ui.warn(str(inst), '\n')
516 self.ui.warn(str(inst), '\n')
517 partial, last, lrev = {}, nullid, nullrev
517 partial, last, lrev = {}, nullid, nullrev
518 return partial, last, lrev
518 return partial, last, lrev
519
519
520 def _writebranchcache(self, branches, tip, tiprev):
520 def _writebranchcache(self, branches, tip, tiprev):
521 try:
521 try:
522 f = self.opener("cache/branchheads", "w", atomictemp=True)
522 f = self.opener("cache/branchheads", "w", atomictemp=True)
523 f.write("%s %s\n" % (hex(tip), tiprev))
523 f.write("%s %s\n" % (hex(tip), tiprev))
524 for label, nodes in branches.iteritems():
524 for label, nodes in branches.iteritems():
525 for node in nodes:
525 for node in nodes:
526 f.write("%s %s\n" % (hex(node), encoding.fromlocal(label)))
526 f.write("%s %s\n" % (hex(node), encoding.fromlocal(label)))
527 f.close()
527 f.close()
528 except (IOError, OSError):
528 except (IOError, OSError):
529 pass
529 pass
530
530
531 def _updatebranchcache(self, partial, ctxgen):
531 def _updatebranchcache(self, partial, ctxgen):
532 # collect new branch entries
532 # collect new branch entries
533 newbranches = {}
533 newbranches = {}
534 for c in ctxgen:
534 for c in ctxgen:
535 newbranches.setdefault(c.branch(), []).append(c.node())
535 newbranches.setdefault(c.branch(), []).append(c.node())
536 # if older branchheads are reachable from new ones, they aren't
536 # if older branchheads are reachable from new ones, they aren't
537 # really branchheads. Note checking parents is insufficient:
537 # really branchheads. Note checking parents is insufficient:
538 # 1 (branch a) -> 2 (branch b) -> 3 (branch a)
538 # 1 (branch a) -> 2 (branch b) -> 3 (branch a)
539 for branch, newnodes in newbranches.iteritems():
539 for branch, newnodes in newbranches.iteritems():
540 bheads = partial.setdefault(branch, [])
540 bheads = partial.setdefault(branch, [])
541 bheads.extend(newnodes)
541 bheads.extend(newnodes)
542 if len(bheads) <= 1:
542 if len(bheads) <= 1:
543 continue
543 continue
544 bheads = sorted(bheads, key=lambda x: self[x].rev())
544 bheads = sorted(bheads, key=lambda x: self[x].rev())
545 # starting from tip means fewer passes over reachable
545 # starting from tip means fewer passes over reachable
546 while newnodes:
546 while newnodes:
547 latest = newnodes.pop()
547 latest = newnodes.pop()
548 if latest not in bheads:
548 if latest not in bheads:
549 continue
549 continue
550 minbhrev = self[bheads[0]].node()
550 minbhrev = self[bheads[0]].node()
551 reachable = self.changelog.reachable(latest, minbhrev)
551 reachable = self.changelog.reachable(latest, minbhrev)
552 reachable.remove(latest)
552 reachable.remove(latest)
553 if reachable:
553 if reachable:
554 bheads = [b for b in bheads if b not in reachable]
554 bheads = [b for b in bheads if b not in reachable]
555 partial[branch] = bheads
555 partial[branch] = bheads
556
556
557 def lookup(self, key):
557 def lookup(self, key):
558 if isinstance(key, int):
558 if isinstance(key, int):
559 return self.changelog.node(key)
559 return self.changelog.node(key)
560 elif key == '.':
560 elif key == '.':
561 return self.dirstate.p1()
561 return self.dirstate.p1()
562 elif key == 'null':
562 elif key == 'null':
563 return nullid
563 return nullid
564 elif key == 'tip':
564 elif key == 'tip':
565 return self.changelog.tip()
565 return self.changelog.tip()
566 n = self.changelog._match(key)
566 n = self.changelog._match(key)
567 if n:
567 if n:
568 return n
568 return n
569 if key in self._bookmarks:
569 if key in self._bookmarks:
570 return self._bookmarks[key]
570 return self._bookmarks[key]
571 if key in self.tags():
571 if key in self.tags():
572 return self.tags()[key]
572 return self.tags()[key]
573 if key in self.branchtags():
573 if key in self.branchtags():
574 return self.branchtags()[key]
574 return self.branchtags()[key]
575 n = self.changelog._partialmatch(key)
575 n = self.changelog._partialmatch(key)
576 if n:
576 if n:
577 return n
577 return n
578
578
579 # can't find key, check if it might have come from damaged dirstate
579 # can't find key, check if it might have come from damaged dirstate
580 if key in self.dirstate.parents():
580 if key in self.dirstate.parents():
581 raise error.Abort(_("working directory has unknown parent '%s'!")
581 raise error.Abort(_("working directory has unknown parent '%s'!")
582 % short(key))
582 % short(key))
583 try:
583 try:
584 if len(key) == 20:
584 if len(key) == 20:
585 key = hex(key)
585 key = hex(key)
586 except TypeError:
586 except TypeError:
587 pass
587 pass
588 raise error.RepoLookupError(_("unknown revision '%s'") % key)
588 raise error.RepoLookupError(_("unknown revision '%s'") % key)
589
589
590 def lookupbranch(self, key, remote=None):
590 def lookupbranch(self, key, remote=None):
591 repo = remote or self
591 repo = remote or self
592 if key in repo.branchmap():
592 if key in repo.branchmap():
593 return key
593 return key
594
594
595 repo = (remote and remote.local()) and remote or self
595 repo = (remote and remote.local()) and remote or self
596 return repo[key].branch()
596 return repo[key].branch()
597
597
598 def known(self, nodes):
598 def known(self, nodes):
599 nm = self.changelog.nodemap
599 nm = self.changelog.nodemap
600 return [(n in nm) for n in nodes]
600 return [(n in nm) for n in nodes]
601
601
602 def local(self):
602 def local(self):
603 return self
603 return self
604
604
605 def join(self, f):
605 def join(self, f):
606 return os.path.join(self.path, f)
606 return os.path.join(self.path, f)
607
607
608 def wjoin(self, f):
608 def wjoin(self, f):
609 return os.path.join(self.root, f)
609 return os.path.join(self.root, f)
610
610
611 def file(self, f):
611 def file(self, f):
612 if f[0] == '/':
612 if f[0] == '/':
613 f = f[1:]
613 f = f[1:]
614 return filelog.filelog(self.sopener, f)
614 return filelog.filelog(self.sopener, f)
615
615
616 def changectx(self, changeid):
616 def changectx(self, changeid):
617 return self[changeid]
617 return self[changeid]
618
618
619 def parents(self, changeid=None):
619 def parents(self, changeid=None):
620 '''get list of changectxs for parents of changeid'''
620 '''get list of changectxs for parents of changeid'''
621 return self[changeid].parents()
621 return self[changeid].parents()
622
622
623 def filectx(self, path, changeid=None, fileid=None):
623 def filectx(self, path, changeid=None, fileid=None):
624 """changeid can be a changeset revision, node, or tag.
624 """changeid can be a changeset revision, node, or tag.
625 fileid can be a file revision or node."""
625 fileid can be a file revision or node."""
626 return context.filectx(self, path, changeid, fileid)
626 return context.filectx(self, path, changeid, fileid)
627
627
628 def getcwd(self):
628 def getcwd(self):
629 return self.dirstate.getcwd()
629 return self.dirstate.getcwd()
630
630
631 def pathto(self, f, cwd=None):
631 def pathto(self, f, cwd=None):
632 return self.dirstate.pathto(f, cwd)
632 return self.dirstate.pathto(f, cwd)
633
633
634 def wfile(self, f, mode='r'):
634 def wfile(self, f, mode='r'):
635 return self.wopener(f, mode)
635 return self.wopener(f, mode)
636
636
637 def _link(self, f):
637 def _link(self, f):
638 return os.path.islink(self.wjoin(f))
638 return os.path.islink(self.wjoin(f))
639
639
640 def _loadfilter(self, filter):
640 def _loadfilter(self, filter):
641 if filter not in self.filterpats:
641 if filter not in self.filterpats:
642 l = []
642 l = []
643 for pat, cmd in self.ui.configitems(filter):
643 for pat, cmd in self.ui.configitems(filter):
644 if cmd == '!':
644 if cmd == '!':
645 continue
645 continue
646 mf = matchmod.match(self.root, '', [pat])
646 mf = matchmod.match(self.root, '', [pat])
647 fn = None
647 fn = None
648 params = cmd
648 params = cmd
649 for name, filterfn in self._datafilters.iteritems():
649 for name, filterfn in self._datafilters.iteritems():
650 if cmd.startswith(name):
650 if cmd.startswith(name):
651 fn = filterfn
651 fn = filterfn
652 params = cmd[len(name):].lstrip()
652 params = cmd[len(name):].lstrip()
653 break
653 break
654 if not fn:
654 if not fn:
655 fn = lambda s, c, **kwargs: util.filter(s, c)
655 fn = lambda s, c, **kwargs: util.filter(s, c)
656 # Wrap old filters not supporting keyword arguments
656 # Wrap old filters not supporting keyword arguments
657 if not inspect.getargspec(fn)[2]:
657 if not inspect.getargspec(fn)[2]:
658 oldfn = fn
658 oldfn = fn
659 fn = lambda s, c, **kwargs: oldfn(s, c)
659 fn = lambda s, c, **kwargs: oldfn(s, c)
660 l.append((mf, fn, params))
660 l.append((mf, fn, params))
661 self.filterpats[filter] = l
661 self.filterpats[filter] = l
662 return self.filterpats[filter]
662 return self.filterpats[filter]
663
663
664 def _filter(self, filterpats, filename, data):
664 def _filter(self, filterpats, filename, data):
665 for mf, fn, cmd in filterpats:
665 for mf, fn, cmd in filterpats:
666 if mf(filename):
666 if mf(filename):
667 self.ui.debug("filtering %s through %s\n" % (filename, cmd))
667 self.ui.debug("filtering %s through %s\n" % (filename, cmd))
668 data = fn(data, cmd, ui=self.ui, repo=self, filename=filename)
668 data = fn(data, cmd, ui=self.ui, repo=self, filename=filename)
669 break
669 break
670
670
671 return data
671 return data
672
672
673 @propertycache
673 @propertycache
674 def _encodefilterpats(self):
674 def _encodefilterpats(self):
675 return self._loadfilter('encode')
675 return self._loadfilter('encode')
676
676
677 @propertycache
677 @propertycache
678 def _decodefilterpats(self):
678 def _decodefilterpats(self):
679 return self._loadfilter('decode')
679 return self._loadfilter('decode')
680
680
681 def adddatafilter(self, name, filter):
681 def adddatafilter(self, name, filter):
682 self._datafilters[name] = filter
682 self._datafilters[name] = filter
683
683
684 def wread(self, filename):
684 def wread(self, filename):
685 if self._link(filename):
685 if self._link(filename):
686 data = os.readlink(self.wjoin(filename))
686 data = os.readlink(self.wjoin(filename))
687 else:
687 else:
688 data = self.wopener.read(filename)
688 data = self.wopener.read(filename)
689 return self._filter(self._encodefilterpats, filename, data)
689 return self._filter(self._encodefilterpats, filename, data)
690
690
691 def wwrite(self, filename, data, flags):
691 def wwrite(self, filename, data, flags):
692 data = self._filter(self._decodefilterpats, filename, data)
692 data = self._filter(self._decodefilterpats, filename, data)
693 if 'l' in flags:
693 if 'l' in flags:
694 self.wopener.symlink(data, filename)
694 self.wopener.symlink(data, filename)
695 else:
695 else:
696 self.wopener.write(filename, data)
696 self.wopener.write(filename, data)
697 if 'x' in flags:
697 if 'x' in flags:
698 util.setflags(self.wjoin(filename), False, True)
698 util.setflags(self.wjoin(filename), False, True)
699
699
700 def wwritedata(self, filename, data):
700 def wwritedata(self, filename, data):
701 return self._filter(self._decodefilterpats, filename, data)
701 return self._filter(self._decodefilterpats, filename, data)
702
702
703 def transaction(self, desc):
703 def transaction(self, desc):
704 tr = self._transref and self._transref() or None
704 tr = self._transref and self._transref() or None
705 if tr and tr.running():
705 if tr and tr.running():
706 return tr.nest()
706 return tr.nest()
707
707
708 # abort here if the journal already exists
708 # abort here if the journal already exists
709 if os.path.exists(self.sjoin("journal")):
709 if os.path.exists(self.sjoin("journal")):
710 raise error.RepoError(
710 raise error.RepoError(
711 _("abandoned transaction found - run hg recover"))
711 _("abandoned transaction found - run hg recover"))
712
712
713 journalfiles = self._writejournal(desc)
713 journalfiles = self._writejournal(desc)
714 renames = [(x, undoname(x)) for x in journalfiles]
714 renames = [(x, undoname(x)) for x in journalfiles]
715
715
716 tr = transaction.transaction(self.ui.warn, self.sopener,
716 tr = transaction.transaction(self.ui.warn, self.sopener,
717 self.sjoin("journal"),
717 self.sjoin("journal"),
718 aftertrans(renames),
718 aftertrans(renames),
719 self.store.createmode)
719 self.store.createmode)
720 self._transref = weakref.ref(tr)
720 self._transref = weakref.ref(tr)
721 return tr
721 return tr
722
722
723 def _writejournal(self, desc):
723 def _writejournal(self, desc):
724 # save dirstate for rollback
724 # save dirstate for rollback
725 try:
725 try:
726 ds = self.opener.read("dirstate")
726 ds = self.opener.read("dirstate")
727 except IOError:
727 except IOError:
728 ds = ""
728 ds = ""
729 self.opener.write("journal.dirstate", ds)
729 self.opener.write("journal.dirstate", ds)
730 self.opener.write("journal.branch",
730 self.opener.write("journal.branch",
731 encoding.fromlocal(self.dirstate.branch()))
731 encoding.fromlocal(self.dirstate.branch()))
732 self.opener.write("journal.desc",
732 self.opener.write("journal.desc",
733 "%d\n%s\n" % (len(self), desc))
733 "%d\n%s\n" % (len(self), desc))
734
734
735 bkname = self.join('bookmarks')
735 bkname = self.join('bookmarks')
736 if os.path.exists(bkname):
736 if os.path.exists(bkname):
737 util.copyfile(bkname, self.join('journal.bookmarks'))
737 util.copyfile(bkname, self.join('journal.bookmarks'))
738 else:
738 else:
739 self.opener.write('journal.bookmarks', '')
739 self.opener.write('journal.bookmarks', '')
740
740
741 return (self.sjoin('journal'), self.join('journal.dirstate'),
741 return (self.sjoin('journal'), self.join('journal.dirstate'),
742 self.join('journal.branch'), self.join('journal.desc'),
742 self.join('journal.branch'), self.join('journal.desc'),
743 self.join('journal.bookmarks'))
743 self.join('journal.bookmarks'))
744
744
745 def recover(self):
745 def recover(self):
746 lock = self.lock()
746 lock = self.lock()
747 try:
747 try:
748 if os.path.exists(self.sjoin("journal")):
748 if os.path.exists(self.sjoin("journal")):
749 self.ui.status(_("rolling back interrupted transaction\n"))
749 self.ui.status(_("rolling back interrupted transaction\n"))
750 transaction.rollback(self.sopener, self.sjoin("journal"),
750 transaction.rollback(self.sopener, self.sjoin("journal"),
751 self.ui.warn)
751 self.ui.warn)
752 self.invalidate()
752 self.invalidate()
753 return True
753 return True
754 else:
754 else:
755 self.ui.warn(_("no interrupted transaction available\n"))
755 self.ui.warn(_("no interrupted transaction available\n"))
756 return False
756 return False
757 finally:
757 finally:
758 lock.release()
758 lock.release()
759
759
760 def rollback(self, dryrun=False, force=False):
760 def rollback(self, dryrun=False, force=False):
761 wlock = lock = None
761 wlock = lock = None
762 try:
762 try:
763 wlock = self.wlock()
763 wlock = self.wlock()
764 lock = self.lock()
764 lock = self.lock()
765 if os.path.exists(self.sjoin("undo")):
765 if os.path.exists(self.sjoin("undo")):
766 return self._rollback(dryrun, force)
766 return self._rollback(dryrun, force)
767 else:
767 else:
768 self.ui.warn(_("no rollback information available\n"))
768 self.ui.warn(_("no rollback information available\n"))
769 return 1
769 return 1
770 finally:
770 finally:
771 release(lock, wlock)
771 release(lock, wlock)
772
772
773 def _rollback(self, dryrun, force):
773 def _rollback(self, dryrun, force):
774 ui = self.ui
774 ui = self.ui
775 try:
775 try:
776 args = self.opener.read('undo.desc').splitlines()
776 args = self.opener.read('undo.desc').splitlines()
777 (oldlen, desc, detail) = (int(args[0]), args[1], None)
777 (oldlen, desc, detail) = (int(args[0]), args[1], None)
778 if len(args) >= 3:
778 if len(args) >= 3:
779 detail = args[2]
779 detail = args[2]
780 oldtip = oldlen - 1
780 oldtip = oldlen - 1
781
781
782 if detail and ui.verbose:
782 if detail and ui.verbose:
783 msg = (_('repository tip rolled back to revision %s'
783 msg = (_('repository tip rolled back to revision %s'
784 ' (undo %s: %s)\n')
784 ' (undo %s: %s)\n')
785 % (oldtip, desc, detail))
785 % (oldtip, desc, detail))
786 else:
786 else:
787 msg = (_('repository tip rolled back to revision %s'
787 msg = (_('repository tip rolled back to revision %s'
788 ' (undo %s)\n')
788 ' (undo %s)\n')
789 % (oldtip, desc))
789 % (oldtip, desc))
790 except IOError:
790 except IOError:
791 msg = _('rolling back unknown transaction\n')
791 msg = _('rolling back unknown transaction\n')
792 desc = None
792 desc = None
793
793
794 if not force and self['.'] != self['tip'] and desc == 'commit':
794 if not force and self['.'] != self['tip'] and desc == 'commit':
795 raise util.Abort(
795 raise util.Abort(
796 _('rollback of last commit while not checked out '
796 _('rollback of last commit while not checked out '
797 'may lose data'), hint=_('use -f to force'))
797 'may lose data'), hint=_('use -f to force'))
798
798
799 ui.status(msg)
799 ui.status(msg)
800 if dryrun:
800 if dryrun:
801 return 0
801 return 0
802
802
803 parents = self.dirstate.parents()
803 parents = self.dirstate.parents()
804 transaction.rollback(self.sopener, self.sjoin('undo'), ui.warn)
804 transaction.rollback(self.sopener, self.sjoin('undo'), ui.warn)
805 if os.path.exists(self.join('undo.bookmarks')):
805 if os.path.exists(self.join('undo.bookmarks')):
806 util.rename(self.join('undo.bookmarks'),
806 util.rename(self.join('undo.bookmarks'),
807 self.join('bookmarks'))
807 self.join('bookmarks'))
808 self.invalidate()
808 self.invalidate()
809
809
810 parentgone = (parents[0] not in self.changelog.nodemap or
810 parentgone = (parents[0] not in self.changelog.nodemap or
811 parents[1] not in self.changelog.nodemap)
811 parents[1] not in self.changelog.nodemap)
812 if parentgone:
812 if parentgone:
813 util.rename(self.join('undo.dirstate'), self.join('dirstate'))
813 util.rename(self.join('undo.dirstate'), self.join('dirstate'))
814 try:
814 try:
815 branch = self.opener.read('undo.branch')
815 branch = self.opener.read('undo.branch')
816 self.dirstate.setbranch(branch)
816 self.dirstate.setbranch(branch)
817 except IOError:
817 except IOError:
818 ui.warn(_('named branch could not be reset: '
818 ui.warn(_('named branch could not be reset: '
819 'current branch is still \'%s\'\n')
819 'current branch is still \'%s\'\n')
820 % self.dirstate.branch())
820 % self.dirstate.branch())
821
821
822 self.dirstate.invalidate()
822 self.dirstate.invalidate()
823 self.destroyed()
823 self.destroyed()
824 parents = tuple([p.rev() for p in self.parents()])
824 parents = tuple([p.rev() for p in self.parents()])
825 if len(parents) > 1:
825 if len(parents) > 1:
826 ui.status(_('working directory now based on '
826 ui.status(_('working directory now based on '
827 'revisions %d and %d\n') % parents)
827 'revisions %d and %d\n') % parents)
828 else:
828 else:
829 ui.status(_('working directory now based on '
829 ui.status(_('working directory now based on '
830 'revision %d\n') % parents)
830 'revision %d\n') % parents)
831 return 0
831 return 0
832
832
833 def invalidatecaches(self):
833 def invalidatecaches(self):
834 try:
834 try:
835 delattr(self, '_tagscache')
835 delattr(self, '_tagscache')
836 except AttributeError:
836 except AttributeError:
837 pass
837 pass
838
838
839 self._branchcache = None # in UTF-8
839 self._branchcache = None # in UTF-8
840 self._branchcachetip = None
840 self._branchcachetip = None
841
841
842 def invalidatedirstate(self):
842 def invalidatedirstate(self):
843 '''Invalidates the dirstate, causing the next call to dirstate
843 '''Invalidates the dirstate, causing the next call to dirstate
844 to check if it was modified since the last time it was read,
844 to check if it was modified since the last time it was read,
845 rereading it if it has.
845 rereading it if it has.
846
846
847 This is different to dirstate.invalidate() that it doesn't always
847 This is different to dirstate.invalidate() that it doesn't always
848 rereads the dirstate. Use dirstate.invalidate() if you want to
848 rereads the dirstate. Use dirstate.invalidate() if you want to
849 explicitly read the dirstate again (i.e. restoring it to a previous
849 explicitly read the dirstate again (i.e. restoring it to a previous
850 known good state).'''
850 known good state).'''
851 try:
851 try:
852 delattr(self, 'dirstate')
852 delattr(self, 'dirstate')
853 except AttributeError:
853 except AttributeError:
854 pass
854 pass
855
855
856 def invalidate(self):
856 def invalidate(self):
857 for k in self._filecache:
857 for k in self._filecache:
858 # dirstate is invalidated separately in invalidatedirstate()
858 # dirstate is invalidated separately in invalidatedirstate()
859 if k == 'dirstate':
859 if k == 'dirstate':
860 continue
860 continue
861
861
862 try:
862 try:
863 delattr(self, k)
863 delattr(self, k)
864 except AttributeError:
864 except AttributeError:
865 pass
865 pass
866 self.invalidatecaches()
866 self.invalidatecaches()
867
867
868 def _lock(self, lockname, wait, releasefn, acquirefn, desc):
868 def _lock(self, lockname, wait, releasefn, acquirefn, desc):
869 try:
869 try:
870 l = lock.lock(lockname, 0, releasefn, desc=desc)
870 l = lock.lock(lockname, 0, releasefn, desc=desc)
871 except error.LockHeld, inst:
871 except error.LockHeld, inst:
872 if not wait:
872 if not wait:
873 raise
873 raise
874 self.ui.warn(_("waiting for lock on %s held by %r\n") %
874 self.ui.warn(_("waiting for lock on %s held by %r\n") %
875 (desc, inst.locker))
875 (desc, inst.locker))
876 # default to 600 seconds timeout
876 # default to 600 seconds timeout
877 l = lock.lock(lockname, int(self.ui.config("ui", "timeout", "600")),
877 l = lock.lock(lockname, int(self.ui.config("ui", "timeout", "600")),
878 releasefn, desc=desc)
878 releasefn, desc=desc)
879 if acquirefn:
879 if acquirefn:
880 acquirefn()
880 acquirefn()
881 return l
881 return l
882
882
883 def lock(self, wait=True):
883 def lock(self, wait=True):
884 '''Lock the repository store (.hg/store) and return a weak reference
884 '''Lock the repository store (.hg/store) and return a weak reference
885 to the lock. Use this before modifying the store (e.g. committing or
885 to the lock. Use this before modifying the store (e.g. committing or
886 stripping). If you are opening a transaction, get a lock as well.)'''
886 stripping). If you are opening a transaction, get a lock as well.)'''
887 l = self._lockref and self._lockref()
887 l = self._lockref and self._lockref()
888 if l is not None and l.held:
888 if l is not None and l.held:
889 l.lock()
889 l.lock()
890 return l
890 return l
891
891
892 def unlock():
892 def unlock():
893 self.store.write()
893 self.store.write()
894 for k, ce in self._filecache.items():
894 for k, ce in self._filecache.items():
895 if k == 'dirstate':
895 if k == 'dirstate':
896 continue
896 continue
897 ce.refresh()
897 ce.refresh()
898
898
899 l = self._lock(self.sjoin("lock"), wait, unlock,
899 l = self._lock(self.sjoin("lock"), wait, unlock,
900 self.invalidate, _('repository %s') % self.origroot)
900 self.invalidate, _('repository %s') % self.origroot)
901 self._lockref = weakref.ref(l)
901 self._lockref = weakref.ref(l)
902 return l
902 return l
903
903
904 def wlock(self, wait=True):
904 def wlock(self, wait=True):
905 '''Lock the non-store parts of the repository (everything under
905 '''Lock the non-store parts of the repository (everything under
906 .hg except .hg/store) and return a weak reference to the lock.
906 .hg except .hg/store) and return a weak reference to the lock.
907 Use this before modifying files in .hg.'''
907 Use this before modifying files in .hg.'''
908 l = self._wlockref and self._wlockref()
908 l = self._wlockref and self._wlockref()
909 if l is not None and l.held:
909 if l is not None and l.held:
910 l.lock()
910 l.lock()
911 return l
911 return l
912
912
913 def unlock():
913 def unlock():
914 self.dirstate.write()
914 self.dirstate.write()
915 ce = self._filecache.get('dirstate')
915 ce = self._filecache.get('dirstate')
916 if ce:
916 if ce:
917 ce.refresh()
917 ce.refresh()
918
918
919 l = self._lock(self.join("wlock"), wait, unlock,
919 l = self._lock(self.join("wlock"), wait, unlock,
920 self.invalidatedirstate, _('working directory of %s') %
920 self.invalidatedirstate, _('working directory of %s') %
921 self.origroot)
921 self.origroot)
922 self._wlockref = weakref.ref(l)
922 self._wlockref = weakref.ref(l)
923 return l
923 return l
924
924
925 def _filecommit(self, fctx, manifest1, manifest2, linkrev, tr, changelist):
925 def _filecommit(self, fctx, manifest1, manifest2, linkrev, tr, changelist):
926 """
926 """
927 commit an individual file as part of a larger transaction
927 commit an individual file as part of a larger transaction
928 """
928 """
929
929
930 fname = fctx.path()
930 fname = fctx.path()
931 text = fctx.data()
931 text = fctx.data()
932 flog = self.file(fname)
932 flog = self.file(fname)
933 fparent1 = manifest1.get(fname, nullid)
933 fparent1 = manifest1.get(fname, nullid)
934 fparent2 = fparent2o = manifest2.get(fname, nullid)
934 fparent2 = fparent2o = manifest2.get(fname, nullid)
935
935
936 meta = {}
936 meta = {}
937 copy = fctx.renamed()
937 copy = fctx.renamed()
938 if copy and copy[0] != fname:
938 if copy and copy[0] != fname:
939 # Mark the new revision of this file as a copy of another
939 # Mark the new revision of this file as a copy of another
940 # file. This copy data will effectively act as a parent
940 # file. This copy data will effectively act as a parent
941 # of this new revision. If this is a merge, the first
941 # of this new revision. If this is a merge, the first
942 # parent will be the nullid (meaning "look up the copy data")
942 # parent will be the nullid (meaning "look up the copy data")
943 # and the second one will be the other parent. For example:
943 # and the second one will be the other parent. For example:
944 #
944 #
945 # 0 --- 1 --- 3 rev1 changes file foo
945 # 0 --- 1 --- 3 rev1 changes file foo
946 # \ / rev2 renames foo to bar and changes it
946 # \ / rev2 renames foo to bar and changes it
947 # \- 2 -/ rev3 should have bar with all changes and
947 # \- 2 -/ rev3 should have bar with all changes and
948 # should record that bar descends from
948 # should record that bar descends from
949 # bar in rev2 and foo in rev1
949 # bar in rev2 and foo in rev1
950 #
950 #
951 # this allows this merge to succeed:
951 # this allows this merge to succeed:
952 #
952 #
953 # 0 --- 1 --- 3 rev4 reverts the content change from rev2
953 # 0 --- 1 --- 3 rev4 reverts the content change from rev2
954 # \ / merging rev3 and rev4 should use bar@rev2
954 # \ / merging rev3 and rev4 should use bar@rev2
955 # \- 2 --- 4 as the merge base
955 # \- 2 --- 4 as the merge base
956 #
956 #
957
957
958 cfname = copy[0]
958 cfname = copy[0]
959 crev = manifest1.get(cfname)
959 crev = manifest1.get(cfname)
960 newfparent = fparent2
960 newfparent = fparent2
961
961
962 if manifest2: # branch merge
962 if manifest2: # branch merge
963 if fparent2 == nullid or crev is None: # copied on remote side
963 if fparent2 == nullid or crev is None: # copied on remote side
964 if cfname in manifest2:
964 if cfname in manifest2:
965 crev = manifest2[cfname]
965 crev = manifest2[cfname]
966 newfparent = fparent1
966 newfparent = fparent1
967
967
968 # find source in nearest ancestor if we've lost track
968 # find source in nearest ancestor if we've lost track
969 if not crev:
969 if not crev:
970 self.ui.debug(" %s: searching for copy revision for %s\n" %
970 self.ui.debug(" %s: searching for copy revision for %s\n" %
971 (fname, cfname))
971 (fname, cfname))
972 for ancestor in self[None].ancestors():
972 for ancestor in self[None].ancestors():
973 if cfname in ancestor:
973 if cfname in ancestor:
974 crev = ancestor[cfname].filenode()
974 crev = ancestor[cfname].filenode()
975 break
975 break
976
976
977 if crev:
977 if crev:
978 self.ui.debug(" %s: copy %s:%s\n" % (fname, cfname, hex(crev)))
978 self.ui.debug(" %s: copy %s:%s\n" % (fname, cfname, hex(crev)))
979 meta["copy"] = cfname
979 meta["copy"] = cfname
980 meta["copyrev"] = hex(crev)
980 meta["copyrev"] = hex(crev)
981 fparent1, fparent2 = nullid, newfparent
981 fparent1, fparent2 = nullid, newfparent
982 else:
982 else:
983 self.ui.warn(_("warning: can't find ancestor for '%s' "
983 self.ui.warn(_("warning: can't find ancestor for '%s' "
984 "copied from '%s'!\n") % (fname, cfname))
984 "copied from '%s'!\n") % (fname, cfname))
985
985
986 elif fparent2 != nullid:
986 elif fparent2 != nullid:
987 # is one parent an ancestor of the other?
987 # is one parent an ancestor of the other?
988 fparentancestor = flog.ancestor(fparent1, fparent2)
988 fparentancestor = flog.ancestor(fparent1, fparent2)
989 if fparentancestor == fparent1:
989 if fparentancestor == fparent1:
990 fparent1, fparent2 = fparent2, nullid
990 fparent1, fparent2 = fparent2, nullid
991 elif fparentancestor == fparent2:
991 elif fparentancestor == fparent2:
992 fparent2 = nullid
992 fparent2 = nullid
993
993
994 # is the file changed?
994 # is the file changed?
995 if fparent2 != nullid or flog.cmp(fparent1, text) or meta:
995 if fparent2 != nullid or flog.cmp(fparent1, text) or meta:
996 changelist.append(fname)
996 changelist.append(fname)
997 return flog.add(text, meta, tr, linkrev, fparent1, fparent2)
997 return flog.add(text, meta, tr, linkrev, fparent1, fparent2)
998
998
999 # are just the flags changed during merge?
999 # are just the flags changed during merge?
1000 if fparent1 != fparent2o and manifest1.flags(fname) != fctx.flags():
1000 if fparent1 != fparent2o and manifest1.flags(fname) != fctx.flags():
1001 changelist.append(fname)
1001 changelist.append(fname)
1002
1002
1003 return fparent1
1003 return fparent1
1004
1004
1005 def commit(self, text="", user=None, date=None, match=None, force=False,
1005 def commit(self, text="", user=None, date=None, match=None, force=False,
1006 editor=False, extra={}):
1006 editor=False, extra={}):
1007 """Add a new revision to current repository.
1007 """Add a new revision to current repository.
1008
1008
1009 Revision information is gathered from the working directory,
1009 Revision information is gathered from the working directory,
1010 match can be used to filter the committed files. If editor is
1010 match can be used to filter the committed files. If editor is
1011 supplied, it is called to get a commit message.
1011 supplied, it is called to get a commit message.
1012 """
1012 """
1013
1013
1014 def fail(f, msg):
1014 def fail(f, msg):
1015 raise util.Abort('%s: %s' % (f, msg))
1015 raise util.Abort('%s: %s' % (f, msg))
1016
1016
1017 if not match:
1017 if not match:
1018 match = matchmod.always(self.root, '')
1018 match = matchmod.always(self.root, '')
1019
1019
1020 if not force:
1020 if not force:
1021 vdirs = []
1021 vdirs = []
1022 match.dir = vdirs.append
1022 match.dir = vdirs.append
1023 match.bad = fail
1023 match.bad = fail
1024
1024
1025 wlock = self.wlock()
1025 wlock = self.wlock()
1026 try:
1026 try:
1027 wctx = self[None]
1027 wctx = self[None]
1028 merge = len(wctx.parents()) > 1
1028 merge = len(wctx.parents()) > 1
1029
1029
1030 if (not force and merge and match and
1030 if (not force and merge and match and
1031 (match.files() or match.anypats())):
1031 (match.files() or match.anypats())):
1032 raise util.Abort(_('cannot partially commit a merge '
1032 raise util.Abort(_('cannot partially commit a merge '
1033 '(do not specify files or patterns)'))
1033 '(do not specify files or patterns)'))
1034
1034
1035 changes = self.status(match=match, clean=force)
1035 changes = self.status(match=match, clean=force)
1036 if force:
1036 if force:
1037 changes[0].extend(changes[6]) # mq may commit unchanged files
1037 changes[0].extend(changes[6]) # mq may commit unchanged files
1038
1038
1039 # check subrepos
1039 # check subrepos
1040 subs = []
1040 subs = []
1041 removedsubs = set()
1041 removedsubs = set()
1042 if '.hgsub' in wctx:
1042 if '.hgsub' in wctx:
1043 # only manage subrepos and .hgsubstate if .hgsub is present
1043 # only manage subrepos and .hgsubstate if .hgsub is present
1044 for p in wctx.parents():
1044 for p in wctx.parents():
1045 removedsubs.update(s for s in p.substate if match(s))
1045 removedsubs.update(s for s in p.substate if match(s))
1046 for s in wctx.substate:
1046 for s in wctx.substate:
1047 removedsubs.discard(s)
1047 removedsubs.discard(s)
1048 if match(s) and wctx.sub(s).dirty():
1048 if match(s) and wctx.sub(s).dirty():
1049 subs.append(s)
1049 subs.append(s)
1050 if (subs or removedsubs):
1050 if (subs or removedsubs):
1051 if (not match('.hgsub') and
1051 if (not match('.hgsub') and
1052 '.hgsub' in (wctx.modified() + wctx.added())):
1052 '.hgsub' in (wctx.modified() + wctx.added())):
1053 raise util.Abort(
1053 raise util.Abort(
1054 _("can't commit subrepos without .hgsub"))
1054 _("can't commit subrepos without .hgsub"))
1055 if '.hgsubstate' not in changes[0]:
1055 if '.hgsubstate' not in changes[0]:
1056 changes[0].insert(0, '.hgsubstate')
1056 changes[0].insert(0, '.hgsubstate')
1057 if '.hgsubstate' in changes[2]:
1057 if '.hgsubstate' in changes[2]:
1058 changes[2].remove('.hgsubstate')
1058 changes[2].remove('.hgsubstate')
1059 elif '.hgsub' in changes[2]:
1059 elif '.hgsub' in changes[2]:
1060 # clean up .hgsubstate when .hgsub is removed
1060 # clean up .hgsubstate when .hgsub is removed
1061 if ('.hgsubstate' in wctx and
1061 if ('.hgsubstate' in wctx and
1062 '.hgsubstate' not in changes[0] + changes[1] + changes[2]):
1062 '.hgsubstate' not in changes[0] + changes[1] + changes[2]):
1063 changes[2].insert(0, '.hgsubstate')
1063 changes[2].insert(0, '.hgsubstate')
1064
1064
1065 if subs and not self.ui.configbool('ui', 'commitsubrepos', True):
1065 if subs and not self.ui.configbool('ui', 'commitsubrepos', False):
1066 changedsubs = [s for s in subs if wctx.sub(s).dirty(True)]
1066 changedsubs = [s for s in subs if wctx.sub(s).dirty(True)]
1067 if changedsubs:
1067 if changedsubs:
1068 raise util.Abort(_("uncommitted changes in subrepo %s")
1068 raise util.Abort(_("uncommitted changes in subrepo %s")
1069 % changedsubs[0])
1069 % changedsubs[0],
1070 hint=_("use --subrepos for recursive commit"))
1070
1071
1071 # make sure all explicit patterns are matched
1072 # make sure all explicit patterns are matched
1072 if not force and match.files():
1073 if not force and match.files():
1073 matched = set(changes[0] + changes[1] + changes[2])
1074 matched = set(changes[0] + changes[1] + changes[2])
1074
1075
1075 for f in match.files():
1076 for f in match.files():
1076 if f == '.' or f in matched or f in wctx.substate:
1077 if f == '.' or f in matched or f in wctx.substate:
1077 continue
1078 continue
1078 if f in changes[3]: # missing
1079 if f in changes[3]: # missing
1079 fail(f, _('file not found!'))
1080 fail(f, _('file not found!'))
1080 if f in vdirs: # visited directory
1081 if f in vdirs: # visited directory
1081 d = f + '/'
1082 d = f + '/'
1082 for mf in matched:
1083 for mf in matched:
1083 if mf.startswith(d):
1084 if mf.startswith(d):
1084 break
1085 break
1085 else:
1086 else:
1086 fail(f, _("no match under directory!"))
1087 fail(f, _("no match under directory!"))
1087 elif f not in self.dirstate:
1088 elif f not in self.dirstate:
1088 fail(f, _("file not tracked!"))
1089 fail(f, _("file not tracked!"))
1089
1090
1090 if (not force and not extra.get("close") and not merge
1091 if (not force and not extra.get("close") and not merge
1091 and not (changes[0] or changes[1] or changes[2])
1092 and not (changes[0] or changes[1] or changes[2])
1092 and wctx.branch() == wctx.p1().branch()):
1093 and wctx.branch() == wctx.p1().branch()):
1093 return None
1094 return None
1094
1095
1095 ms = mergemod.mergestate(self)
1096 ms = mergemod.mergestate(self)
1096 for f in changes[0]:
1097 for f in changes[0]:
1097 if f in ms and ms[f] == 'u':
1098 if f in ms and ms[f] == 'u':
1098 raise util.Abort(_("unresolved merge conflicts "
1099 raise util.Abort(_("unresolved merge conflicts "
1099 "(see hg help resolve)"))
1100 "(see hg help resolve)"))
1100
1101
1101 cctx = context.workingctx(self, text, user, date, extra, changes)
1102 cctx = context.workingctx(self, text, user, date, extra, changes)
1102 if editor:
1103 if editor:
1103 cctx._text = editor(self, cctx, subs)
1104 cctx._text = editor(self, cctx, subs)
1104 edited = (text != cctx._text)
1105 edited = (text != cctx._text)
1105
1106
1106 # commit subs
1107 # commit subs
1107 if subs or removedsubs:
1108 if subs or removedsubs:
1108 state = wctx.substate.copy()
1109 state = wctx.substate.copy()
1109 for s in sorted(subs):
1110 for s in sorted(subs):
1110 sub = wctx.sub(s)
1111 sub = wctx.sub(s)
1111 self.ui.status(_('committing subrepository %s\n') %
1112 self.ui.status(_('committing subrepository %s\n') %
1112 subrepo.subrelpath(sub))
1113 subrepo.subrelpath(sub))
1113 sr = sub.commit(cctx._text, user, date)
1114 sr = sub.commit(cctx._text, user, date)
1114 state[s] = (state[s][0], sr)
1115 state[s] = (state[s][0], sr)
1115 subrepo.writestate(self, state)
1116 subrepo.writestate(self, state)
1116
1117
1117 # Save commit message in case this transaction gets rolled back
1118 # Save commit message in case this transaction gets rolled back
1118 # (e.g. by a pretxncommit hook). Leave the content alone on
1119 # (e.g. by a pretxncommit hook). Leave the content alone on
1119 # the assumption that the user will use the same editor again.
1120 # the assumption that the user will use the same editor again.
1120 msgfn = self.savecommitmessage(cctx._text)
1121 msgfn = self.savecommitmessage(cctx._text)
1121
1122
1122 p1, p2 = self.dirstate.parents()
1123 p1, p2 = self.dirstate.parents()
1123 hookp1, hookp2 = hex(p1), (p2 != nullid and hex(p2) or '')
1124 hookp1, hookp2 = hex(p1), (p2 != nullid and hex(p2) or '')
1124 try:
1125 try:
1125 self.hook("precommit", throw=True, parent1=hookp1, parent2=hookp2)
1126 self.hook("precommit", throw=True, parent1=hookp1, parent2=hookp2)
1126 ret = self.commitctx(cctx, True)
1127 ret = self.commitctx(cctx, True)
1127 except:
1128 except:
1128 if edited:
1129 if edited:
1129 self.ui.write(
1130 self.ui.write(
1130 _('note: commit message saved in %s\n') % msgfn)
1131 _('note: commit message saved in %s\n') % msgfn)
1131 raise
1132 raise
1132
1133
1133 # update bookmarks, dirstate and mergestate
1134 # update bookmarks, dirstate and mergestate
1134 bookmarks.update(self, p1, ret)
1135 bookmarks.update(self, p1, ret)
1135 for f in changes[0] + changes[1]:
1136 for f in changes[0] + changes[1]:
1136 self.dirstate.normal(f)
1137 self.dirstate.normal(f)
1137 for f in changes[2]:
1138 for f in changes[2]:
1138 self.dirstate.drop(f)
1139 self.dirstate.drop(f)
1139 self.dirstate.setparents(ret)
1140 self.dirstate.setparents(ret)
1140 ms.reset()
1141 ms.reset()
1141 finally:
1142 finally:
1142 wlock.release()
1143 wlock.release()
1143
1144
1144 self.hook("commit", node=hex(ret), parent1=hookp1, parent2=hookp2)
1145 self.hook("commit", node=hex(ret), parent1=hookp1, parent2=hookp2)
1145 return ret
1146 return ret
1146
1147
1147 def commitctx(self, ctx, error=False):
1148 def commitctx(self, ctx, error=False):
1148 """Add a new revision to current repository.
1149 """Add a new revision to current repository.
1149 Revision information is passed via the context argument.
1150 Revision information is passed via the context argument.
1150 """
1151 """
1151
1152
1152 tr = lock = None
1153 tr = lock = None
1153 removed = list(ctx.removed())
1154 removed = list(ctx.removed())
1154 p1, p2 = ctx.p1(), ctx.p2()
1155 p1, p2 = ctx.p1(), ctx.p2()
1155 user = ctx.user()
1156 user = ctx.user()
1156
1157
1157 lock = self.lock()
1158 lock = self.lock()
1158 try:
1159 try:
1159 tr = self.transaction("commit")
1160 tr = self.transaction("commit")
1160 trp = weakref.proxy(tr)
1161 trp = weakref.proxy(tr)
1161
1162
1162 if ctx.files():
1163 if ctx.files():
1163 m1 = p1.manifest().copy()
1164 m1 = p1.manifest().copy()
1164 m2 = p2.manifest()
1165 m2 = p2.manifest()
1165
1166
1166 # check in files
1167 # check in files
1167 new = {}
1168 new = {}
1168 changed = []
1169 changed = []
1169 linkrev = len(self)
1170 linkrev = len(self)
1170 for f in sorted(ctx.modified() + ctx.added()):
1171 for f in sorted(ctx.modified() + ctx.added()):
1171 self.ui.note(f + "\n")
1172 self.ui.note(f + "\n")
1172 try:
1173 try:
1173 fctx = ctx[f]
1174 fctx = ctx[f]
1174 new[f] = self._filecommit(fctx, m1, m2, linkrev, trp,
1175 new[f] = self._filecommit(fctx, m1, m2, linkrev, trp,
1175 changed)
1176 changed)
1176 m1.set(f, fctx.flags())
1177 m1.set(f, fctx.flags())
1177 except OSError, inst:
1178 except OSError, inst:
1178 self.ui.warn(_("trouble committing %s!\n") % f)
1179 self.ui.warn(_("trouble committing %s!\n") % f)
1179 raise
1180 raise
1180 except IOError, inst:
1181 except IOError, inst:
1181 errcode = getattr(inst, 'errno', errno.ENOENT)
1182 errcode = getattr(inst, 'errno', errno.ENOENT)
1182 if error or errcode and errcode != errno.ENOENT:
1183 if error or errcode and errcode != errno.ENOENT:
1183 self.ui.warn(_("trouble committing %s!\n") % f)
1184 self.ui.warn(_("trouble committing %s!\n") % f)
1184 raise
1185 raise
1185 else:
1186 else:
1186 removed.append(f)
1187 removed.append(f)
1187
1188
1188 # update manifest
1189 # update manifest
1189 m1.update(new)
1190 m1.update(new)
1190 removed = [f for f in sorted(removed) if f in m1 or f in m2]
1191 removed = [f for f in sorted(removed) if f in m1 or f in m2]
1191 drop = [f for f in removed if f in m1]
1192 drop = [f for f in removed if f in m1]
1192 for f in drop:
1193 for f in drop:
1193 del m1[f]
1194 del m1[f]
1194 mn = self.manifest.add(m1, trp, linkrev, p1.manifestnode(),
1195 mn = self.manifest.add(m1, trp, linkrev, p1.manifestnode(),
1195 p2.manifestnode(), (new, drop))
1196 p2.manifestnode(), (new, drop))
1196 files = changed + removed
1197 files = changed + removed
1197 else:
1198 else:
1198 mn = p1.manifestnode()
1199 mn = p1.manifestnode()
1199 files = []
1200 files = []
1200
1201
1201 # update changelog
1202 # update changelog
1202 self.changelog.delayupdate()
1203 self.changelog.delayupdate()
1203 n = self.changelog.add(mn, files, ctx.description(),
1204 n = self.changelog.add(mn, files, ctx.description(),
1204 trp, p1.node(), p2.node(),
1205 trp, p1.node(), p2.node(),
1205 user, ctx.date(), ctx.extra().copy())
1206 user, ctx.date(), ctx.extra().copy())
1206 p = lambda: self.changelog.writepending() and self.root or ""
1207 p = lambda: self.changelog.writepending() and self.root or ""
1207 xp1, xp2 = p1.hex(), p2 and p2.hex() or ''
1208 xp1, xp2 = p1.hex(), p2 and p2.hex() or ''
1208 self.hook('pretxncommit', throw=True, node=hex(n), parent1=xp1,
1209 self.hook('pretxncommit', throw=True, node=hex(n), parent1=xp1,
1209 parent2=xp2, pending=p)
1210 parent2=xp2, pending=p)
1210 self.changelog.finalize(trp)
1211 self.changelog.finalize(trp)
1211 tr.close()
1212 tr.close()
1212
1213
1213 if self._branchcache:
1214 if self._branchcache:
1214 self.updatebranchcache()
1215 self.updatebranchcache()
1215 return n
1216 return n
1216 finally:
1217 finally:
1217 if tr:
1218 if tr:
1218 tr.release()
1219 tr.release()
1219 lock.release()
1220 lock.release()
1220
1221
1221 def destroyed(self):
1222 def destroyed(self):
1222 '''Inform the repository that nodes have been destroyed.
1223 '''Inform the repository that nodes have been destroyed.
1223 Intended for use by strip and rollback, so there's a common
1224 Intended for use by strip and rollback, so there's a common
1224 place for anything that has to be done after destroying history.'''
1225 place for anything that has to be done after destroying history.'''
1225 # XXX it might be nice if we could take the list of destroyed
1226 # XXX it might be nice if we could take the list of destroyed
1226 # nodes, but I don't see an easy way for rollback() to do that
1227 # nodes, but I don't see an easy way for rollback() to do that
1227
1228
1228 # Ensure the persistent tag cache is updated. Doing it now
1229 # Ensure the persistent tag cache is updated. Doing it now
1229 # means that the tag cache only has to worry about destroyed
1230 # means that the tag cache only has to worry about destroyed
1230 # heads immediately after a strip/rollback. That in turn
1231 # heads immediately after a strip/rollback. That in turn
1231 # guarantees that "cachetip == currenttip" (comparing both rev
1232 # guarantees that "cachetip == currenttip" (comparing both rev
1232 # and node) always means no nodes have been added or destroyed.
1233 # and node) always means no nodes have been added or destroyed.
1233
1234
1234 # XXX this is suboptimal when qrefresh'ing: we strip the current
1235 # XXX this is suboptimal when qrefresh'ing: we strip the current
1235 # head, refresh the tag cache, then immediately add a new head.
1236 # head, refresh the tag cache, then immediately add a new head.
1236 # But I think doing it this way is necessary for the "instant
1237 # But I think doing it this way is necessary for the "instant
1237 # tag cache retrieval" case to work.
1238 # tag cache retrieval" case to work.
1238 self.invalidatecaches()
1239 self.invalidatecaches()
1239
1240
1240 def walk(self, match, node=None):
1241 def walk(self, match, node=None):
1241 '''
1242 '''
1242 walk recursively through the directory tree or a given
1243 walk recursively through the directory tree or a given
1243 changeset, finding all files matched by the match
1244 changeset, finding all files matched by the match
1244 function
1245 function
1245 '''
1246 '''
1246 return self[node].walk(match)
1247 return self[node].walk(match)
1247
1248
1248 def status(self, node1='.', node2=None, match=None,
1249 def status(self, node1='.', node2=None, match=None,
1249 ignored=False, clean=False, unknown=False,
1250 ignored=False, clean=False, unknown=False,
1250 listsubrepos=False):
1251 listsubrepos=False):
1251 """return status of files between two nodes or node and working directory
1252 """return status of files between two nodes or node and working directory
1252
1253
1253 If node1 is None, use the first dirstate parent instead.
1254 If node1 is None, use the first dirstate parent instead.
1254 If node2 is None, compare node1 with working directory.
1255 If node2 is None, compare node1 with working directory.
1255 """
1256 """
1256
1257
1257 def mfmatches(ctx):
1258 def mfmatches(ctx):
1258 mf = ctx.manifest().copy()
1259 mf = ctx.manifest().copy()
1259 for fn in mf.keys():
1260 for fn in mf.keys():
1260 if not match(fn):
1261 if not match(fn):
1261 del mf[fn]
1262 del mf[fn]
1262 return mf
1263 return mf
1263
1264
1264 if isinstance(node1, context.changectx):
1265 if isinstance(node1, context.changectx):
1265 ctx1 = node1
1266 ctx1 = node1
1266 else:
1267 else:
1267 ctx1 = self[node1]
1268 ctx1 = self[node1]
1268 if isinstance(node2, context.changectx):
1269 if isinstance(node2, context.changectx):
1269 ctx2 = node2
1270 ctx2 = node2
1270 else:
1271 else:
1271 ctx2 = self[node2]
1272 ctx2 = self[node2]
1272
1273
1273 working = ctx2.rev() is None
1274 working = ctx2.rev() is None
1274 parentworking = working and ctx1 == self['.']
1275 parentworking = working and ctx1 == self['.']
1275 match = match or matchmod.always(self.root, self.getcwd())
1276 match = match or matchmod.always(self.root, self.getcwd())
1276 listignored, listclean, listunknown = ignored, clean, unknown
1277 listignored, listclean, listunknown = ignored, clean, unknown
1277
1278
1278 # load earliest manifest first for caching reasons
1279 # load earliest manifest first for caching reasons
1279 if not working and ctx2.rev() < ctx1.rev():
1280 if not working and ctx2.rev() < ctx1.rev():
1280 ctx2.manifest()
1281 ctx2.manifest()
1281
1282
1282 if not parentworking:
1283 if not parentworking:
1283 def bad(f, msg):
1284 def bad(f, msg):
1284 if f not in ctx1:
1285 if f not in ctx1:
1285 self.ui.warn('%s: %s\n' % (self.dirstate.pathto(f), msg))
1286 self.ui.warn('%s: %s\n' % (self.dirstate.pathto(f), msg))
1286 match.bad = bad
1287 match.bad = bad
1287
1288
1288 if working: # we need to scan the working dir
1289 if working: # we need to scan the working dir
1289 subrepos = []
1290 subrepos = []
1290 if '.hgsub' in self.dirstate:
1291 if '.hgsub' in self.dirstate:
1291 subrepos = ctx2.substate.keys()
1292 subrepos = ctx2.substate.keys()
1292 s = self.dirstate.status(match, subrepos, listignored,
1293 s = self.dirstate.status(match, subrepos, listignored,
1293 listclean, listunknown)
1294 listclean, listunknown)
1294 cmp, modified, added, removed, deleted, unknown, ignored, clean = s
1295 cmp, modified, added, removed, deleted, unknown, ignored, clean = s
1295
1296
1296 # check for any possibly clean files
1297 # check for any possibly clean files
1297 if parentworking and cmp:
1298 if parentworking and cmp:
1298 fixup = []
1299 fixup = []
1299 # do a full compare of any files that might have changed
1300 # do a full compare of any files that might have changed
1300 for f in sorted(cmp):
1301 for f in sorted(cmp):
1301 if (f not in ctx1 or ctx2.flags(f) != ctx1.flags(f)
1302 if (f not in ctx1 or ctx2.flags(f) != ctx1.flags(f)
1302 or ctx1[f].cmp(ctx2[f])):
1303 or ctx1[f].cmp(ctx2[f])):
1303 modified.append(f)
1304 modified.append(f)
1304 else:
1305 else:
1305 fixup.append(f)
1306 fixup.append(f)
1306
1307
1307 # update dirstate for files that are actually clean
1308 # update dirstate for files that are actually clean
1308 if fixup:
1309 if fixup:
1309 if listclean:
1310 if listclean:
1310 clean += fixup
1311 clean += fixup
1311
1312
1312 try:
1313 try:
1313 # updating the dirstate is optional
1314 # updating the dirstate is optional
1314 # so we don't wait on the lock
1315 # so we don't wait on the lock
1315 wlock = self.wlock(False)
1316 wlock = self.wlock(False)
1316 try:
1317 try:
1317 for f in fixup:
1318 for f in fixup:
1318 self.dirstate.normal(f)
1319 self.dirstate.normal(f)
1319 finally:
1320 finally:
1320 wlock.release()
1321 wlock.release()
1321 except error.LockError:
1322 except error.LockError:
1322 pass
1323 pass
1323
1324
1324 if not parentworking:
1325 if not parentworking:
1325 mf1 = mfmatches(ctx1)
1326 mf1 = mfmatches(ctx1)
1326 if working:
1327 if working:
1327 # we are comparing working dir against non-parent
1328 # we are comparing working dir against non-parent
1328 # generate a pseudo-manifest for the working dir
1329 # generate a pseudo-manifest for the working dir
1329 mf2 = mfmatches(self['.'])
1330 mf2 = mfmatches(self['.'])
1330 for f in cmp + modified + added:
1331 for f in cmp + modified + added:
1331 mf2[f] = None
1332 mf2[f] = None
1332 mf2.set(f, ctx2.flags(f))
1333 mf2.set(f, ctx2.flags(f))
1333 for f in removed:
1334 for f in removed:
1334 if f in mf2:
1335 if f in mf2:
1335 del mf2[f]
1336 del mf2[f]
1336 else:
1337 else:
1337 # we are comparing two revisions
1338 # we are comparing two revisions
1338 deleted, unknown, ignored = [], [], []
1339 deleted, unknown, ignored = [], [], []
1339 mf2 = mfmatches(ctx2)
1340 mf2 = mfmatches(ctx2)
1340
1341
1341 modified, added, clean = [], [], []
1342 modified, added, clean = [], [], []
1342 for fn in mf2:
1343 for fn in mf2:
1343 if fn in mf1:
1344 if fn in mf1:
1344 if (fn not in deleted and
1345 if (fn not in deleted and
1345 (mf1.flags(fn) != mf2.flags(fn) or
1346 (mf1.flags(fn) != mf2.flags(fn) or
1346 (mf1[fn] != mf2[fn] and
1347 (mf1[fn] != mf2[fn] and
1347 (mf2[fn] or ctx1[fn].cmp(ctx2[fn]))))):
1348 (mf2[fn] or ctx1[fn].cmp(ctx2[fn]))))):
1348 modified.append(fn)
1349 modified.append(fn)
1349 elif listclean:
1350 elif listclean:
1350 clean.append(fn)
1351 clean.append(fn)
1351 del mf1[fn]
1352 del mf1[fn]
1352 elif fn not in deleted:
1353 elif fn not in deleted:
1353 added.append(fn)
1354 added.append(fn)
1354 removed = mf1.keys()
1355 removed = mf1.keys()
1355
1356
1356 r = modified, added, removed, deleted, unknown, ignored, clean
1357 r = modified, added, removed, deleted, unknown, ignored, clean
1357
1358
1358 if listsubrepos:
1359 if listsubrepos:
1359 for subpath, sub in subrepo.itersubrepos(ctx1, ctx2):
1360 for subpath, sub in subrepo.itersubrepos(ctx1, ctx2):
1360 if working:
1361 if working:
1361 rev2 = None
1362 rev2 = None
1362 else:
1363 else:
1363 rev2 = ctx2.substate[subpath][1]
1364 rev2 = ctx2.substate[subpath][1]
1364 try:
1365 try:
1365 submatch = matchmod.narrowmatcher(subpath, match)
1366 submatch = matchmod.narrowmatcher(subpath, match)
1366 s = sub.status(rev2, match=submatch, ignored=listignored,
1367 s = sub.status(rev2, match=submatch, ignored=listignored,
1367 clean=listclean, unknown=listunknown,
1368 clean=listclean, unknown=listunknown,
1368 listsubrepos=True)
1369 listsubrepos=True)
1369 for rfiles, sfiles in zip(r, s):
1370 for rfiles, sfiles in zip(r, s):
1370 rfiles.extend("%s/%s" % (subpath, f) for f in sfiles)
1371 rfiles.extend("%s/%s" % (subpath, f) for f in sfiles)
1371 except error.LookupError:
1372 except error.LookupError:
1372 self.ui.status(_("skipping missing subrepository: %s\n")
1373 self.ui.status(_("skipping missing subrepository: %s\n")
1373 % subpath)
1374 % subpath)
1374
1375
1375 for l in r:
1376 for l in r:
1376 l.sort()
1377 l.sort()
1377 return r
1378 return r
1378
1379
1379 def heads(self, start=None):
1380 def heads(self, start=None):
1380 heads = self.changelog.heads(start)
1381 heads = self.changelog.heads(start)
1381 # sort the output in rev descending order
1382 # sort the output in rev descending order
1382 return sorted(heads, key=self.changelog.rev, reverse=True)
1383 return sorted(heads, key=self.changelog.rev, reverse=True)
1383
1384
1384 def branchheads(self, branch=None, start=None, closed=False):
1385 def branchheads(self, branch=None, start=None, closed=False):
1385 '''return a (possibly filtered) list of heads for the given branch
1386 '''return a (possibly filtered) list of heads for the given branch
1386
1387
1387 Heads are returned in topological order, from newest to oldest.
1388 Heads are returned in topological order, from newest to oldest.
1388 If branch is None, use the dirstate branch.
1389 If branch is None, use the dirstate branch.
1389 If start is not None, return only heads reachable from start.
1390 If start is not None, return only heads reachable from start.
1390 If closed is True, return heads that are marked as closed as well.
1391 If closed is True, return heads that are marked as closed as well.
1391 '''
1392 '''
1392 if branch is None:
1393 if branch is None:
1393 branch = self[None].branch()
1394 branch = self[None].branch()
1394 branches = self.branchmap()
1395 branches = self.branchmap()
1395 if branch not in branches:
1396 if branch not in branches:
1396 return []
1397 return []
1397 # the cache returns heads ordered lowest to highest
1398 # the cache returns heads ordered lowest to highest
1398 bheads = list(reversed(branches[branch]))
1399 bheads = list(reversed(branches[branch]))
1399 if start is not None:
1400 if start is not None:
1400 # filter out the heads that cannot be reached from startrev
1401 # filter out the heads that cannot be reached from startrev
1401 fbheads = set(self.changelog.nodesbetween([start], bheads)[2])
1402 fbheads = set(self.changelog.nodesbetween([start], bheads)[2])
1402 bheads = [h for h in bheads if h in fbheads]
1403 bheads = [h for h in bheads if h in fbheads]
1403 if not closed:
1404 if not closed:
1404 bheads = [h for h in bheads if
1405 bheads = [h for h in bheads if
1405 ('close' not in self.changelog.read(h)[5])]
1406 ('close' not in self.changelog.read(h)[5])]
1406 return bheads
1407 return bheads
1407
1408
1408 def branches(self, nodes):
1409 def branches(self, nodes):
1409 if not nodes:
1410 if not nodes:
1410 nodes = [self.changelog.tip()]
1411 nodes = [self.changelog.tip()]
1411 b = []
1412 b = []
1412 for n in nodes:
1413 for n in nodes:
1413 t = n
1414 t = n
1414 while True:
1415 while True:
1415 p = self.changelog.parents(n)
1416 p = self.changelog.parents(n)
1416 if p[1] != nullid or p[0] == nullid:
1417 if p[1] != nullid or p[0] == nullid:
1417 b.append((t, n, p[0], p[1]))
1418 b.append((t, n, p[0], p[1]))
1418 break
1419 break
1419 n = p[0]
1420 n = p[0]
1420 return b
1421 return b
1421
1422
1422 def between(self, pairs):
1423 def between(self, pairs):
1423 r = []
1424 r = []
1424
1425
1425 for top, bottom in pairs:
1426 for top, bottom in pairs:
1426 n, l, i = top, [], 0
1427 n, l, i = top, [], 0
1427 f = 1
1428 f = 1
1428
1429
1429 while n != bottom and n != nullid:
1430 while n != bottom and n != nullid:
1430 p = self.changelog.parents(n)[0]
1431 p = self.changelog.parents(n)[0]
1431 if i == f:
1432 if i == f:
1432 l.append(n)
1433 l.append(n)
1433 f = f * 2
1434 f = f * 2
1434 n = p
1435 n = p
1435 i += 1
1436 i += 1
1436
1437
1437 r.append(l)
1438 r.append(l)
1438
1439
1439 return r
1440 return r
1440
1441
1441 def pull(self, remote, heads=None, force=False):
1442 def pull(self, remote, heads=None, force=False):
1442 lock = self.lock()
1443 lock = self.lock()
1443 try:
1444 try:
1444 tmp = discovery.findcommonincoming(self, remote, heads=heads,
1445 tmp = discovery.findcommonincoming(self, remote, heads=heads,
1445 force=force)
1446 force=force)
1446 common, fetch, rheads = tmp
1447 common, fetch, rheads = tmp
1447 if not fetch:
1448 if not fetch:
1448 self.ui.status(_("no changes found\n"))
1449 self.ui.status(_("no changes found\n"))
1449 result = 0
1450 result = 0
1450 else:
1451 else:
1451 if heads is None and list(common) == [nullid]:
1452 if heads is None and list(common) == [nullid]:
1452 self.ui.status(_("requesting all changes\n"))
1453 self.ui.status(_("requesting all changes\n"))
1453 elif heads is None and remote.capable('changegroupsubset'):
1454 elif heads is None and remote.capable('changegroupsubset'):
1454 # issue1320, avoid a race if remote changed after discovery
1455 # issue1320, avoid a race if remote changed after discovery
1455 heads = rheads
1456 heads = rheads
1456
1457
1457 if remote.capable('getbundle'):
1458 if remote.capable('getbundle'):
1458 cg = remote.getbundle('pull', common=common,
1459 cg = remote.getbundle('pull', common=common,
1459 heads=heads or rheads)
1460 heads=heads or rheads)
1460 elif heads is None:
1461 elif heads is None:
1461 cg = remote.changegroup(fetch, 'pull')
1462 cg = remote.changegroup(fetch, 'pull')
1462 elif not remote.capable('changegroupsubset'):
1463 elif not remote.capable('changegroupsubset'):
1463 raise util.Abort(_("partial pull cannot be done because "
1464 raise util.Abort(_("partial pull cannot be done because "
1464 "other repository doesn't support "
1465 "other repository doesn't support "
1465 "changegroupsubset."))
1466 "changegroupsubset."))
1466 else:
1467 else:
1467 cg = remote.changegroupsubset(fetch, heads, 'pull')
1468 cg = remote.changegroupsubset(fetch, heads, 'pull')
1468 result = self.addchangegroup(cg, 'pull', remote.url(),
1469 result = self.addchangegroup(cg, 'pull', remote.url(),
1469 lock=lock)
1470 lock=lock)
1470 finally:
1471 finally:
1471 lock.release()
1472 lock.release()
1472
1473
1473 return result
1474 return result
1474
1475
1475 def checkpush(self, force, revs):
1476 def checkpush(self, force, revs):
1476 """Extensions can override this function if additional checks have
1477 """Extensions can override this function if additional checks have
1477 to be performed before pushing, or call it if they override push
1478 to be performed before pushing, or call it if they override push
1478 command.
1479 command.
1479 """
1480 """
1480 pass
1481 pass
1481
1482
1482 def push(self, remote, force=False, revs=None, newbranch=False):
1483 def push(self, remote, force=False, revs=None, newbranch=False):
1483 '''Push outgoing changesets (limited by revs) from the current
1484 '''Push outgoing changesets (limited by revs) from the current
1484 repository to remote. Return an integer:
1485 repository to remote. Return an integer:
1485 - 0 means HTTP error *or* nothing to push
1486 - 0 means HTTP error *or* nothing to push
1486 - 1 means we pushed and remote head count is unchanged *or*
1487 - 1 means we pushed and remote head count is unchanged *or*
1487 we have outgoing changesets but refused to push
1488 we have outgoing changesets but refused to push
1488 - other values as described by addchangegroup()
1489 - other values as described by addchangegroup()
1489 '''
1490 '''
1490 # there are two ways to push to remote repo:
1491 # there are two ways to push to remote repo:
1491 #
1492 #
1492 # addchangegroup assumes local user can lock remote
1493 # addchangegroup assumes local user can lock remote
1493 # repo (local filesystem, old ssh servers).
1494 # repo (local filesystem, old ssh servers).
1494 #
1495 #
1495 # unbundle assumes local user cannot lock remote repo (new ssh
1496 # unbundle assumes local user cannot lock remote repo (new ssh
1496 # servers, http servers).
1497 # servers, http servers).
1497
1498
1498 self.checkpush(force, revs)
1499 self.checkpush(force, revs)
1499 lock = None
1500 lock = None
1500 unbundle = remote.capable('unbundle')
1501 unbundle = remote.capable('unbundle')
1501 if not unbundle:
1502 if not unbundle:
1502 lock = remote.lock()
1503 lock = remote.lock()
1503 try:
1504 try:
1504 cg, remote_heads = discovery.prepush(self, remote, force, revs,
1505 cg, remote_heads = discovery.prepush(self, remote, force, revs,
1505 newbranch)
1506 newbranch)
1506 ret = remote_heads
1507 ret = remote_heads
1507 if cg is not None:
1508 if cg is not None:
1508 if unbundle:
1509 if unbundle:
1509 # local repo finds heads on server, finds out what
1510 # local repo finds heads on server, finds out what
1510 # revs it must push. once revs transferred, if server
1511 # revs it must push. once revs transferred, if server
1511 # finds it has different heads (someone else won
1512 # finds it has different heads (someone else won
1512 # commit/push race), server aborts.
1513 # commit/push race), server aborts.
1513 if force:
1514 if force:
1514 remote_heads = ['force']
1515 remote_heads = ['force']
1515 # ssh: return remote's addchangegroup()
1516 # ssh: return remote's addchangegroup()
1516 # http: return remote's addchangegroup() or 0 for error
1517 # http: return remote's addchangegroup() or 0 for error
1517 ret = remote.unbundle(cg, remote_heads, 'push')
1518 ret = remote.unbundle(cg, remote_heads, 'push')
1518 else:
1519 else:
1519 # we return an integer indicating remote head count change
1520 # we return an integer indicating remote head count change
1520 ret = remote.addchangegroup(cg, 'push', self.url(),
1521 ret = remote.addchangegroup(cg, 'push', self.url(),
1521 lock=lock)
1522 lock=lock)
1522 finally:
1523 finally:
1523 if lock is not None:
1524 if lock is not None:
1524 lock.release()
1525 lock.release()
1525
1526
1526 self.ui.debug("checking for updated bookmarks\n")
1527 self.ui.debug("checking for updated bookmarks\n")
1527 rb = remote.listkeys('bookmarks')
1528 rb = remote.listkeys('bookmarks')
1528 for k in rb.keys():
1529 for k in rb.keys():
1529 if k in self._bookmarks:
1530 if k in self._bookmarks:
1530 nr, nl = rb[k], hex(self._bookmarks[k])
1531 nr, nl = rb[k], hex(self._bookmarks[k])
1531 if nr in self:
1532 if nr in self:
1532 cr = self[nr]
1533 cr = self[nr]
1533 cl = self[nl]
1534 cl = self[nl]
1534 if cl in cr.descendants():
1535 if cl in cr.descendants():
1535 r = remote.pushkey('bookmarks', k, nr, nl)
1536 r = remote.pushkey('bookmarks', k, nr, nl)
1536 if r:
1537 if r:
1537 self.ui.status(_("updating bookmark %s\n") % k)
1538 self.ui.status(_("updating bookmark %s\n") % k)
1538 else:
1539 else:
1539 self.ui.warn(_('updating bookmark %s'
1540 self.ui.warn(_('updating bookmark %s'
1540 ' failed!\n') % k)
1541 ' failed!\n') % k)
1541
1542
1542 return ret
1543 return ret
1543
1544
1544 def changegroupinfo(self, nodes, source):
1545 def changegroupinfo(self, nodes, source):
1545 if self.ui.verbose or source == 'bundle':
1546 if self.ui.verbose or source == 'bundle':
1546 self.ui.status(_("%d changesets found\n") % len(nodes))
1547 self.ui.status(_("%d changesets found\n") % len(nodes))
1547 if self.ui.debugflag:
1548 if self.ui.debugflag:
1548 self.ui.debug("list of changesets:\n")
1549 self.ui.debug("list of changesets:\n")
1549 for node in nodes:
1550 for node in nodes:
1550 self.ui.debug("%s\n" % hex(node))
1551 self.ui.debug("%s\n" % hex(node))
1551
1552
1552 def changegroupsubset(self, bases, heads, source):
1553 def changegroupsubset(self, bases, heads, source):
1553 """Compute a changegroup consisting of all the nodes that are
1554 """Compute a changegroup consisting of all the nodes that are
1554 descendants of any of the bases and ancestors of any of the heads.
1555 descendants of any of the bases and ancestors of any of the heads.
1555 Return a chunkbuffer object whose read() method will return
1556 Return a chunkbuffer object whose read() method will return
1556 successive changegroup chunks.
1557 successive changegroup chunks.
1557
1558
1558 It is fairly complex as determining which filenodes and which
1559 It is fairly complex as determining which filenodes and which
1559 manifest nodes need to be included for the changeset to be complete
1560 manifest nodes need to be included for the changeset to be complete
1560 is non-trivial.
1561 is non-trivial.
1561
1562
1562 Another wrinkle is doing the reverse, figuring out which changeset in
1563 Another wrinkle is doing the reverse, figuring out which changeset in
1563 the changegroup a particular filenode or manifestnode belongs to.
1564 the changegroup a particular filenode or manifestnode belongs to.
1564 """
1565 """
1565 cl = self.changelog
1566 cl = self.changelog
1566 if not bases:
1567 if not bases:
1567 bases = [nullid]
1568 bases = [nullid]
1568 csets, bases, heads = cl.nodesbetween(bases, heads)
1569 csets, bases, heads = cl.nodesbetween(bases, heads)
1569 # We assume that all ancestors of bases are known
1570 # We assume that all ancestors of bases are known
1570 common = set(cl.ancestors(*[cl.rev(n) for n in bases]))
1571 common = set(cl.ancestors(*[cl.rev(n) for n in bases]))
1571 return self._changegroupsubset(common, csets, heads, source)
1572 return self._changegroupsubset(common, csets, heads, source)
1572
1573
1573 def getbundle(self, source, heads=None, common=None):
1574 def getbundle(self, source, heads=None, common=None):
1574 """Like changegroupsubset, but returns the set difference between the
1575 """Like changegroupsubset, but returns the set difference between the
1575 ancestors of heads and the ancestors common.
1576 ancestors of heads and the ancestors common.
1576
1577
1577 If heads is None, use the local heads. If common is None, use [nullid].
1578 If heads is None, use the local heads. If common is None, use [nullid].
1578
1579
1579 The nodes in common might not all be known locally due to the way the
1580 The nodes in common might not all be known locally due to the way the
1580 current discovery protocol works.
1581 current discovery protocol works.
1581 """
1582 """
1582 cl = self.changelog
1583 cl = self.changelog
1583 if common:
1584 if common:
1584 nm = cl.nodemap
1585 nm = cl.nodemap
1585 common = [n for n in common if n in nm]
1586 common = [n for n in common if n in nm]
1586 else:
1587 else:
1587 common = [nullid]
1588 common = [nullid]
1588 if not heads:
1589 if not heads:
1589 heads = cl.heads()
1590 heads = cl.heads()
1590 common, missing = cl.findcommonmissing(common, heads)
1591 common, missing = cl.findcommonmissing(common, heads)
1591 if not missing:
1592 if not missing:
1592 return None
1593 return None
1593 return self._changegroupsubset(common, missing, heads, source)
1594 return self._changegroupsubset(common, missing, heads, source)
1594
1595
1595 def _changegroupsubset(self, commonrevs, csets, heads, source):
1596 def _changegroupsubset(self, commonrevs, csets, heads, source):
1596
1597
1597 cl = self.changelog
1598 cl = self.changelog
1598 mf = self.manifest
1599 mf = self.manifest
1599 mfs = {} # needed manifests
1600 mfs = {} # needed manifests
1600 fnodes = {} # needed file nodes
1601 fnodes = {} # needed file nodes
1601 changedfiles = set()
1602 changedfiles = set()
1602 fstate = ['', {}]
1603 fstate = ['', {}]
1603 count = [0]
1604 count = [0]
1604
1605
1605 # can we go through the fast path ?
1606 # can we go through the fast path ?
1606 heads.sort()
1607 heads.sort()
1607 if heads == sorted(self.heads()):
1608 if heads == sorted(self.heads()):
1608 return self._changegroup(csets, source)
1609 return self._changegroup(csets, source)
1609
1610
1610 # slow path
1611 # slow path
1611 self.hook('preoutgoing', throw=True, source=source)
1612 self.hook('preoutgoing', throw=True, source=source)
1612 self.changegroupinfo(csets, source)
1613 self.changegroupinfo(csets, source)
1613
1614
1614 # filter any nodes that claim to be part of the known set
1615 # filter any nodes that claim to be part of the known set
1615 def prune(revlog, missing):
1616 def prune(revlog, missing):
1616 return [n for n in missing
1617 return [n for n in missing
1617 if revlog.linkrev(revlog.rev(n)) not in commonrevs]
1618 if revlog.linkrev(revlog.rev(n)) not in commonrevs]
1618
1619
1619 def lookup(revlog, x):
1620 def lookup(revlog, x):
1620 if revlog == cl:
1621 if revlog == cl:
1621 c = cl.read(x)
1622 c = cl.read(x)
1622 changedfiles.update(c[3])
1623 changedfiles.update(c[3])
1623 mfs.setdefault(c[0], x)
1624 mfs.setdefault(c[0], x)
1624 count[0] += 1
1625 count[0] += 1
1625 self.ui.progress(_('bundling'), count[0],
1626 self.ui.progress(_('bundling'), count[0],
1626 unit=_('changesets'), total=len(csets))
1627 unit=_('changesets'), total=len(csets))
1627 return x
1628 return x
1628 elif revlog == mf:
1629 elif revlog == mf:
1629 clnode = mfs[x]
1630 clnode = mfs[x]
1630 mdata = mf.readfast(x)
1631 mdata = mf.readfast(x)
1631 for f in changedfiles:
1632 for f in changedfiles:
1632 if f in mdata:
1633 if f in mdata:
1633 fnodes.setdefault(f, {}).setdefault(mdata[f], clnode)
1634 fnodes.setdefault(f, {}).setdefault(mdata[f], clnode)
1634 count[0] += 1
1635 count[0] += 1
1635 self.ui.progress(_('bundling'), count[0],
1636 self.ui.progress(_('bundling'), count[0],
1636 unit=_('manifests'), total=len(mfs))
1637 unit=_('manifests'), total=len(mfs))
1637 return mfs[x]
1638 return mfs[x]
1638 else:
1639 else:
1639 self.ui.progress(
1640 self.ui.progress(
1640 _('bundling'), count[0], item=fstate[0],
1641 _('bundling'), count[0], item=fstate[0],
1641 unit=_('files'), total=len(changedfiles))
1642 unit=_('files'), total=len(changedfiles))
1642 return fstate[1][x]
1643 return fstate[1][x]
1643
1644
1644 bundler = changegroup.bundle10(lookup)
1645 bundler = changegroup.bundle10(lookup)
1645 reorder = self.ui.config('bundle', 'reorder', 'auto')
1646 reorder = self.ui.config('bundle', 'reorder', 'auto')
1646 if reorder == 'auto':
1647 if reorder == 'auto':
1647 reorder = None
1648 reorder = None
1648 else:
1649 else:
1649 reorder = util.parsebool(reorder)
1650 reorder = util.parsebool(reorder)
1650
1651
1651 def gengroup():
1652 def gengroup():
1652 # Create a changenode group generator that will call our functions
1653 # Create a changenode group generator that will call our functions
1653 # back to lookup the owning changenode and collect information.
1654 # back to lookup the owning changenode and collect information.
1654 for chunk in cl.group(csets, bundler, reorder=reorder):
1655 for chunk in cl.group(csets, bundler, reorder=reorder):
1655 yield chunk
1656 yield chunk
1656 self.ui.progress(_('bundling'), None)
1657 self.ui.progress(_('bundling'), None)
1657
1658
1658 # Create a generator for the manifestnodes that calls our lookup
1659 # Create a generator for the manifestnodes that calls our lookup
1659 # and data collection functions back.
1660 # and data collection functions back.
1660 count[0] = 0
1661 count[0] = 0
1661 for chunk in mf.group(prune(mf, mfs), bundler, reorder=reorder):
1662 for chunk in mf.group(prune(mf, mfs), bundler, reorder=reorder):
1662 yield chunk
1663 yield chunk
1663 self.ui.progress(_('bundling'), None)
1664 self.ui.progress(_('bundling'), None)
1664
1665
1665 mfs.clear()
1666 mfs.clear()
1666
1667
1667 # Go through all our files in order sorted by name.
1668 # Go through all our files in order sorted by name.
1668 count[0] = 0
1669 count[0] = 0
1669 for fname in sorted(changedfiles):
1670 for fname in sorted(changedfiles):
1670 filerevlog = self.file(fname)
1671 filerevlog = self.file(fname)
1671 if not len(filerevlog):
1672 if not len(filerevlog):
1672 raise util.Abort(_("empty or missing revlog for %s") % fname)
1673 raise util.Abort(_("empty or missing revlog for %s") % fname)
1673 fstate[0] = fname
1674 fstate[0] = fname
1674 fstate[1] = fnodes.pop(fname, {})
1675 fstate[1] = fnodes.pop(fname, {})
1675
1676
1676 nodelist = prune(filerevlog, fstate[1])
1677 nodelist = prune(filerevlog, fstate[1])
1677 if nodelist:
1678 if nodelist:
1678 count[0] += 1
1679 count[0] += 1
1679 yield bundler.fileheader(fname)
1680 yield bundler.fileheader(fname)
1680 for chunk in filerevlog.group(nodelist, bundler, reorder):
1681 for chunk in filerevlog.group(nodelist, bundler, reorder):
1681 yield chunk
1682 yield chunk
1682
1683
1683 # Signal that no more groups are left.
1684 # Signal that no more groups are left.
1684 yield bundler.close()
1685 yield bundler.close()
1685 self.ui.progress(_('bundling'), None)
1686 self.ui.progress(_('bundling'), None)
1686
1687
1687 if csets:
1688 if csets:
1688 self.hook('outgoing', node=hex(csets[0]), source=source)
1689 self.hook('outgoing', node=hex(csets[0]), source=source)
1689
1690
1690 return changegroup.unbundle10(util.chunkbuffer(gengroup()), 'UN')
1691 return changegroup.unbundle10(util.chunkbuffer(gengroup()), 'UN')
1691
1692
1692 def changegroup(self, basenodes, source):
1693 def changegroup(self, basenodes, source):
1693 # to avoid a race we use changegroupsubset() (issue1320)
1694 # to avoid a race we use changegroupsubset() (issue1320)
1694 return self.changegroupsubset(basenodes, self.heads(), source)
1695 return self.changegroupsubset(basenodes, self.heads(), source)
1695
1696
1696 def _changegroup(self, nodes, source):
1697 def _changegroup(self, nodes, source):
1697 """Compute the changegroup of all nodes that we have that a recipient
1698 """Compute the changegroup of all nodes that we have that a recipient
1698 doesn't. Return a chunkbuffer object whose read() method will return
1699 doesn't. Return a chunkbuffer object whose read() method will return
1699 successive changegroup chunks.
1700 successive changegroup chunks.
1700
1701
1701 This is much easier than the previous function as we can assume that
1702 This is much easier than the previous function as we can assume that
1702 the recipient has any changenode we aren't sending them.
1703 the recipient has any changenode we aren't sending them.
1703
1704
1704 nodes is the set of nodes to send"""
1705 nodes is the set of nodes to send"""
1705
1706
1706 cl = self.changelog
1707 cl = self.changelog
1707 mf = self.manifest
1708 mf = self.manifest
1708 mfs = {}
1709 mfs = {}
1709 changedfiles = set()
1710 changedfiles = set()
1710 fstate = ['']
1711 fstate = ['']
1711 count = [0]
1712 count = [0]
1712
1713
1713 self.hook('preoutgoing', throw=True, source=source)
1714 self.hook('preoutgoing', throw=True, source=source)
1714 self.changegroupinfo(nodes, source)
1715 self.changegroupinfo(nodes, source)
1715
1716
1716 revset = set([cl.rev(n) for n in nodes])
1717 revset = set([cl.rev(n) for n in nodes])
1717
1718
1718 def gennodelst(log):
1719 def gennodelst(log):
1719 return [log.node(r) for r in log if log.linkrev(r) in revset]
1720 return [log.node(r) for r in log if log.linkrev(r) in revset]
1720
1721
1721 def lookup(revlog, x):
1722 def lookup(revlog, x):
1722 if revlog == cl:
1723 if revlog == cl:
1723 c = cl.read(x)
1724 c = cl.read(x)
1724 changedfiles.update(c[3])
1725 changedfiles.update(c[3])
1725 mfs.setdefault(c[0], x)
1726 mfs.setdefault(c[0], x)
1726 count[0] += 1
1727 count[0] += 1
1727 self.ui.progress(_('bundling'), count[0],
1728 self.ui.progress(_('bundling'), count[0],
1728 unit=_('changesets'), total=len(nodes))
1729 unit=_('changesets'), total=len(nodes))
1729 return x
1730 return x
1730 elif revlog == mf:
1731 elif revlog == mf:
1731 count[0] += 1
1732 count[0] += 1
1732 self.ui.progress(_('bundling'), count[0],
1733 self.ui.progress(_('bundling'), count[0],
1733 unit=_('manifests'), total=len(mfs))
1734 unit=_('manifests'), total=len(mfs))
1734 return cl.node(revlog.linkrev(revlog.rev(x)))
1735 return cl.node(revlog.linkrev(revlog.rev(x)))
1735 else:
1736 else:
1736 self.ui.progress(
1737 self.ui.progress(
1737 _('bundling'), count[0], item=fstate[0],
1738 _('bundling'), count[0], item=fstate[0],
1738 total=len(changedfiles), unit=_('files'))
1739 total=len(changedfiles), unit=_('files'))
1739 return cl.node(revlog.linkrev(revlog.rev(x)))
1740 return cl.node(revlog.linkrev(revlog.rev(x)))
1740
1741
1741 bundler = changegroup.bundle10(lookup)
1742 bundler = changegroup.bundle10(lookup)
1742 reorder = self.ui.config('bundle', 'reorder', 'auto')
1743 reorder = self.ui.config('bundle', 'reorder', 'auto')
1743 if reorder == 'auto':
1744 if reorder == 'auto':
1744 reorder = None
1745 reorder = None
1745 else:
1746 else:
1746 reorder = util.parsebool(reorder)
1747 reorder = util.parsebool(reorder)
1747
1748
1748 def gengroup():
1749 def gengroup():
1749 '''yield a sequence of changegroup chunks (strings)'''
1750 '''yield a sequence of changegroup chunks (strings)'''
1750 # construct a list of all changed files
1751 # construct a list of all changed files
1751
1752
1752 for chunk in cl.group(nodes, bundler, reorder=reorder):
1753 for chunk in cl.group(nodes, bundler, reorder=reorder):
1753 yield chunk
1754 yield chunk
1754 self.ui.progress(_('bundling'), None)
1755 self.ui.progress(_('bundling'), None)
1755
1756
1756 count[0] = 0
1757 count[0] = 0
1757 for chunk in mf.group(gennodelst(mf), bundler, reorder=reorder):
1758 for chunk in mf.group(gennodelst(mf), bundler, reorder=reorder):
1758 yield chunk
1759 yield chunk
1759 self.ui.progress(_('bundling'), None)
1760 self.ui.progress(_('bundling'), None)
1760
1761
1761 count[0] = 0
1762 count[0] = 0
1762 for fname in sorted(changedfiles):
1763 for fname in sorted(changedfiles):
1763 filerevlog = self.file(fname)
1764 filerevlog = self.file(fname)
1764 if not len(filerevlog):
1765 if not len(filerevlog):
1765 raise util.Abort(_("empty or missing revlog for %s") % fname)
1766 raise util.Abort(_("empty or missing revlog for %s") % fname)
1766 fstate[0] = fname
1767 fstate[0] = fname
1767 nodelist = gennodelst(filerevlog)
1768 nodelist = gennodelst(filerevlog)
1768 if nodelist:
1769 if nodelist:
1769 count[0] += 1
1770 count[0] += 1
1770 yield bundler.fileheader(fname)
1771 yield bundler.fileheader(fname)
1771 for chunk in filerevlog.group(nodelist, bundler, reorder):
1772 for chunk in filerevlog.group(nodelist, bundler, reorder):
1772 yield chunk
1773 yield chunk
1773 yield bundler.close()
1774 yield bundler.close()
1774 self.ui.progress(_('bundling'), None)
1775 self.ui.progress(_('bundling'), None)
1775
1776
1776 if nodes:
1777 if nodes:
1777 self.hook('outgoing', node=hex(nodes[0]), source=source)
1778 self.hook('outgoing', node=hex(nodes[0]), source=source)
1778
1779
1779 return changegroup.unbundle10(util.chunkbuffer(gengroup()), 'UN')
1780 return changegroup.unbundle10(util.chunkbuffer(gengroup()), 'UN')
1780
1781
1781 def addchangegroup(self, source, srctype, url, emptyok=False, lock=None):
1782 def addchangegroup(self, source, srctype, url, emptyok=False, lock=None):
1782 """Add the changegroup returned by source.read() to this repo.
1783 """Add the changegroup returned by source.read() to this repo.
1783 srctype is a string like 'push', 'pull', or 'unbundle'. url is
1784 srctype is a string like 'push', 'pull', or 'unbundle'. url is
1784 the URL of the repo where this changegroup is coming from.
1785 the URL of the repo where this changegroup is coming from.
1785 If lock is not None, the function takes ownership of the lock
1786 If lock is not None, the function takes ownership of the lock
1786 and releases it after the changegroup is added.
1787 and releases it after the changegroup is added.
1787
1788
1788 Return an integer summarizing the change to this repo:
1789 Return an integer summarizing the change to this repo:
1789 - nothing changed or no source: 0
1790 - nothing changed or no source: 0
1790 - more heads than before: 1+added heads (2..n)
1791 - more heads than before: 1+added heads (2..n)
1791 - fewer heads than before: -1-removed heads (-2..-n)
1792 - fewer heads than before: -1-removed heads (-2..-n)
1792 - number of heads stays the same: 1
1793 - number of heads stays the same: 1
1793 """
1794 """
1794 def csmap(x):
1795 def csmap(x):
1795 self.ui.debug("add changeset %s\n" % short(x))
1796 self.ui.debug("add changeset %s\n" % short(x))
1796 return len(cl)
1797 return len(cl)
1797
1798
1798 def revmap(x):
1799 def revmap(x):
1799 return cl.rev(x)
1800 return cl.rev(x)
1800
1801
1801 if not source:
1802 if not source:
1802 return 0
1803 return 0
1803
1804
1804 self.hook('prechangegroup', throw=True, source=srctype, url=url)
1805 self.hook('prechangegroup', throw=True, source=srctype, url=url)
1805
1806
1806 changesets = files = revisions = 0
1807 changesets = files = revisions = 0
1807 efiles = set()
1808 efiles = set()
1808
1809
1809 # write changelog data to temp files so concurrent readers will not see
1810 # write changelog data to temp files so concurrent readers will not see
1810 # inconsistent view
1811 # inconsistent view
1811 cl = self.changelog
1812 cl = self.changelog
1812 cl.delayupdate()
1813 cl.delayupdate()
1813 oldheads = cl.heads()
1814 oldheads = cl.heads()
1814
1815
1815 tr = self.transaction("\n".join([srctype, util.hidepassword(url)]))
1816 tr = self.transaction("\n".join([srctype, util.hidepassword(url)]))
1816 try:
1817 try:
1817 trp = weakref.proxy(tr)
1818 trp = weakref.proxy(tr)
1818 # pull off the changeset group
1819 # pull off the changeset group
1819 self.ui.status(_("adding changesets\n"))
1820 self.ui.status(_("adding changesets\n"))
1820 clstart = len(cl)
1821 clstart = len(cl)
1821 class prog(object):
1822 class prog(object):
1822 step = _('changesets')
1823 step = _('changesets')
1823 count = 1
1824 count = 1
1824 ui = self.ui
1825 ui = self.ui
1825 total = None
1826 total = None
1826 def __call__(self):
1827 def __call__(self):
1827 self.ui.progress(self.step, self.count, unit=_('chunks'),
1828 self.ui.progress(self.step, self.count, unit=_('chunks'),
1828 total=self.total)
1829 total=self.total)
1829 self.count += 1
1830 self.count += 1
1830 pr = prog()
1831 pr = prog()
1831 source.callback = pr
1832 source.callback = pr
1832
1833
1833 source.changelogheader()
1834 source.changelogheader()
1834 if (cl.addgroup(source, csmap, trp) is None
1835 if (cl.addgroup(source, csmap, trp) is None
1835 and not emptyok):
1836 and not emptyok):
1836 raise util.Abort(_("received changelog group is empty"))
1837 raise util.Abort(_("received changelog group is empty"))
1837 clend = len(cl)
1838 clend = len(cl)
1838 changesets = clend - clstart
1839 changesets = clend - clstart
1839 for c in xrange(clstart, clend):
1840 for c in xrange(clstart, clend):
1840 efiles.update(self[c].files())
1841 efiles.update(self[c].files())
1841 efiles = len(efiles)
1842 efiles = len(efiles)
1842 self.ui.progress(_('changesets'), None)
1843 self.ui.progress(_('changesets'), None)
1843
1844
1844 # pull off the manifest group
1845 # pull off the manifest group
1845 self.ui.status(_("adding manifests\n"))
1846 self.ui.status(_("adding manifests\n"))
1846 pr.step = _('manifests')
1847 pr.step = _('manifests')
1847 pr.count = 1
1848 pr.count = 1
1848 pr.total = changesets # manifests <= changesets
1849 pr.total = changesets # manifests <= changesets
1849 # no need to check for empty manifest group here:
1850 # no need to check for empty manifest group here:
1850 # if the result of the merge of 1 and 2 is the same in 3 and 4,
1851 # if the result of the merge of 1 and 2 is the same in 3 and 4,
1851 # no new manifest will be created and the manifest group will
1852 # no new manifest will be created and the manifest group will
1852 # be empty during the pull
1853 # be empty during the pull
1853 source.manifestheader()
1854 source.manifestheader()
1854 self.manifest.addgroup(source, revmap, trp)
1855 self.manifest.addgroup(source, revmap, trp)
1855 self.ui.progress(_('manifests'), None)
1856 self.ui.progress(_('manifests'), None)
1856
1857
1857 needfiles = {}
1858 needfiles = {}
1858 if self.ui.configbool('server', 'validate', default=False):
1859 if self.ui.configbool('server', 'validate', default=False):
1859 # validate incoming csets have their manifests
1860 # validate incoming csets have their manifests
1860 for cset in xrange(clstart, clend):
1861 for cset in xrange(clstart, clend):
1861 mfest = self.changelog.read(self.changelog.node(cset))[0]
1862 mfest = self.changelog.read(self.changelog.node(cset))[0]
1862 mfest = self.manifest.readdelta(mfest)
1863 mfest = self.manifest.readdelta(mfest)
1863 # store file nodes we must see
1864 # store file nodes we must see
1864 for f, n in mfest.iteritems():
1865 for f, n in mfest.iteritems():
1865 needfiles.setdefault(f, set()).add(n)
1866 needfiles.setdefault(f, set()).add(n)
1866
1867
1867 # process the files
1868 # process the files
1868 self.ui.status(_("adding file changes\n"))
1869 self.ui.status(_("adding file changes\n"))
1869 pr.step = _('files')
1870 pr.step = _('files')
1870 pr.count = 1
1871 pr.count = 1
1871 pr.total = efiles
1872 pr.total = efiles
1872 source.callback = None
1873 source.callback = None
1873
1874
1874 while True:
1875 while True:
1875 chunkdata = source.filelogheader()
1876 chunkdata = source.filelogheader()
1876 if not chunkdata:
1877 if not chunkdata:
1877 break
1878 break
1878 f = chunkdata["filename"]
1879 f = chunkdata["filename"]
1879 self.ui.debug("adding %s revisions\n" % f)
1880 self.ui.debug("adding %s revisions\n" % f)
1880 pr()
1881 pr()
1881 fl = self.file(f)
1882 fl = self.file(f)
1882 o = len(fl)
1883 o = len(fl)
1883 if fl.addgroup(source, revmap, trp) is None:
1884 if fl.addgroup(source, revmap, trp) is None:
1884 raise util.Abort(_("received file revlog group is empty"))
1885 raise util.Abort(_("received file revlog group is empty"))
1885 revisions += len(fl) - o
1886 revisions += len(fl) - o
1886 files += 1
1887 files += 1
1887 if f in needfiles:
1888 if f in needfiles:
1888 needs = needfiles[f]
1889 needs = needfiles[f]
1889 for new in xrange(o, len(fl)):
1890 for new in xrange(o, len(fl)):
1890 n = fl.node(new)
1891 n = fl.node(new)
1891 if n in needs:
1892 if n in needs:
1892 needs.remove(n)
1893 needs.remove(n)
1893 if not needs:
1894 if not needs:
1894 del needfiles[f]
1895 del needfiles[f]
1895 self.ui.progress(_('files'), None)
1896 self.ui.progress(_('files'), None)
1896
1897
1897 for f, needs in needfiles.iteritems():
1898 for f, needs in needfiles.iteritems():
1898 fl = self.file(f)
1899 fl = self.file(f)
1899 for n in needs:
1900 for n in needs:
1900 try:
1901 try:
1901 fl.rev(n)
1902 fl.rev(n)
1902 except error.LookupError:
1903 except error.LookupError:
1903 raise util.Abort(
1904 raise util.Abort(
1904 _('missing file data for %s:%s - run hg verify') %
1905 _('missing file data for %s:%s - run hg verify') %
1905 (f, hex(n)))
1906 (f, hex(n)))
1906
1907
1907 dh = 0
1908 dh = 0
1908 if oldheads:
1909 if oldheads:
1909 heads = cl.heads()
1910 heads = cl.heads()
1910 dh = len(heads) - len(oldheads)
1911 dh = len(heads) - len(oldheads)
1911 for h in heads:
1912 for h in heads:
1912 if h not in oldheads and 'close' in self[h].extra():
1913 if h not in oldheads and 'close' in self[h].extra():
1913 dh -= 1
1914 dh -= 1
1914 htext = ""
1915 htext = ""
1915 if dh:
1916 if dh:
1916 htext = _(" (%+d heads)") % dh
1917 htext = _(" (%+d heads)") % dh
1917
1918
1918 self.ui.status(_("added %d changesets"
1919 self.ui.status(_("added %d changesets"
1919 " with %d changes to %d files%s\n")
1920 " with %d changes to %d files%s\n")
1920 % (changesets, revisions, files, htext))
1921 % (changesets, revisions, files, htext))
1921
1922
1922 if changesets > 0:
1923 if changesets > 0:
1923 p = lambda: cl.writepending() and self.root or ""
1924 p = lambda: cl.writepending() and self.root or ""
1924 self.hook('pretxnchangegroup', throw=True,
1925 self.hook('pretxnchangegroup', throw=True,
1925 node=hex(cl.node(clstart)), source=srctype,
1926 node=hex(cl.node(clstart)), source=srctype,
1926 url=url, pending=p)
1927 url=url, pending=p)
1927
1928
1928 # make changelog see real files again
1929 # make changelog see real files again
1929 cl.finalize(trp)
1930 cl.finalize(trp)
1930
1931
1931 tr.close()
1932 tr.close()
1932 finally:
1933 finally:
1933 tr.release()
1934 tr.release()
1934 if lock:
1935 if lock:
1935 lock.release()
1936 lock.release()
1936
1937
1937 if changesets > 0:
1938 if changesets > 0:
1938 # forcefully update the on-disk branch cache
1939 # forcefully update the on-disk branch cache
1939 self.ui.debug("updating the branch cache\n")
1940 self.ui.debug("updating the branch cache\n")
1940 self.updatebranchcache()
1941 self.updatebranchcache()
1941 self.hook("changegroup", node=hex(cl.node(clstart)),
1942 self.hook("changegroup", node=hex(cl.node(clstart)),
1942 source=srctype, url=url)
1943 source=srctype, url=url)
1943
1944
1944 for i in xrange(clstart, clend):
1945 for i in xrange(clstart, clend):
1945 self.hook("incoming", node=hex(cl.node(i)),
1946 self.hook("incoming", node=hex(cl.node(i)),
1946 source=srctype, url=url)
1947 source=srctype, url=url)
1947
1948
1948 # never return 0 here:
1949 # never return 0 here:
1949 if dh < 0:
1950 if dh < 0:
1950 return dh - 1
1951 return dh - 1
1951 else:
1952 else:
1952 return dh + 1
1953 return dh + 1
1953
1954
1954 def stream_in(self, remote, requirements):
1955 def stream_in(self, remote, requirements):
1955 lock = self.lock()
1956 lock = self.lock()
1956 try:
1957 try:
1957 fp = remote.stream_out()
1958 fp = remote.stream_out()
1958 l = fp.readline()
1959 l = fp.readline()
1959 try:
1960 try:
1960 resp = int(l)
1961 resp = int(l)
1961 except ValueError:
1962 except ValueError:
1962 raise error.ResponseError(
1963 raise error.ResponseError(
1963 _('Unexpected response from remote server:'), l)
1964 _('Unexpected response from remote server:'), l)
1964 if resp == 1:
1965 if resp == 1:
1965 raise util.Abort(_('operation forbidden by server'))
1966 raise util.Abort(_('operation forbidden by server'))
1966 elif resp == 2:
1967 elif resp == 2:
1967 raise util.Abort(_('locking the remote repository failed'))
1968 raise util.Abort(_('locking the remote repository failed'))
1968 elif resp != 0:
1969 elif resp != 0:
1969 raise util.Abort(_('the server sent an unknown error code'))
1970 raise util.Abort(_('the server sent an unknown error code'))
1970 self.ui.status(_('streaming all changes\n'))
1971 self.ui.status(_('streaming all changes\n'))
1971 l = fp.readline()
1972 l = fp.readline()
1972 try:
1973 try:
1973 total_files, total_bytes = map(int, l.split(' ', 1))
1974 total_files, total_bytes = map(int, l.split(' ', 1))
1974 except (ValueError, TypeError):
1975 except (ValueError, TypeError):
1975 raise error.ResponseError(
1976 raise error.ResponseError(
1976 _('Unexpected response from remote server:'), l)
1977 _('Unexpected response from remote server:'), l)
1977 self.ui.status(_('%d files to transfer, %s of data\n') %
1978 self.ui.status(_('%d files to transfer, %s of data\n') %
1978 (total_files, util.bytecount(total_bytes)))
1979 (total_files, util.bytecount(total_bytes)))
1979 start = time.time()
1980 start = time.time()
1980 for i in xrange(total_files):
1981 for i in xrange(total_files):
1981 # XXX doesn't support '\n' or '\r' in filenames
1982 # XXX doesn't support '\n' or '\r' in filenames
1982 l = fp.readline()
1983 l = fp.readline()
1983 try:
1984 try:
1984 name, size = l.split('\0', 1)
1985 name, size = l.split('\0', 1)
1985 size = int(size)
1986 size = int(size)
1986 except (ValueError, TypeError):
1987 except (ValueError, TypeError):
1987 raise error.ResponseError(
1988 raise error.ResponseError(
1988 _('Unexpected response from remote server:'), l)
1989 _('Unexpected response from remote server:'), l)
1989 self.ui.debug('adding %s (%s)\n' % (name, util.bytecount(size)))
1990 self.ui.debug('adding %s (%s)\n' % (name, util.bytecount(size)))
1990 # for backwards compat, name was partially encoded
1991 # for backwards compat, name was partially encoded
1991 ofp = self.sopener(store.decodedir(name), 'w')
1992 ofp = self.sopener(store.decodedir(name), 'w')
1992 for chunk in util.filechunkiter(fp, limit=size):
1993 for chunk in util.filechunkiter(fp, limit=size):
1993 ofp.write(chunk)
1994 ofp.write(chunk)
1994 ofp.close()
1995 ofp.close()
1995 elapsed = time.time() - start
1996 elapsed = time.time() - start
1996 if elapsed <= 0:
1997 if elapsed <= 0:
1997 elapsed = 0.001
1998 elapsed = 0.001
1998 self.ui.status(_('transferred %s in %.1f seconds (%s/sec)\n') %
1999 self.ui.status(_('transferred %s in %.1f seconds (%s/sec)\n') %
1999 (util.bytecount(total_bytes), elapsed,
2000 (util.bytecount(total_bytes), elapsed,
2000 util.bytecount(total_bytes / elapsed)))
2001 util.bytecount(total_bytes / elapsed)))
2001
2002
2002 # new requirements = old non-format requirements + new format-related
2003 # new requirements = old non-format requirements + new format-related
2003 # requirements from the streamed-in repository
2004 # requirements from the streamed-in repository
2004 requirements.update(set(self.requirements) - self.supportedformats)
2005 requirements.update(set(self.requirements) - self.supportedformats)
2005 self._applyrequirements(requirements)
2006 self._applyrequirements(requirements)
2006 self._writerequirements()
2007 self._writerequirements()
2007
2008
2008 self.invalidate()
2009 self.invalidate()
2009 return len(self.heads()) + 1
2010 return len(self.heads()) + 1
2010 finally:
2011 finally:
2011 lock.release()
2012 lock.release()
2012
2013
2013 def clone(self, remote, heads=[], stream=False):
2014 def clone(self, remote, heads=[], stream=False):
2014 '''clone remote repository.
2015 '''clone remote repository.
2015
2016
2016 keyword arguments:
2017 keyword arguments:
2017 heads: list of revs to clone (forces use of pull)
2018 heads: list of revs to clone (forces use of pull)
2018 stream: use streaming clone if possible'''
2019 stream: use streaming clone if possible'''
2019
2020
2020 # now, all clients that can request uncompressed clones can
2021 # now, all clients that can request uncompressed clones can
2021 # read repo formats supported by all servers that can serve
2022 # read repo formats supported by all servers that can serve
2022 # them.
2023 # them.
2023
2024
2024 # if revlog format changes, client will have to check version
2025 # if revlog format changes, client will have to check version
2025 # and format flags on "stream" capability, and use
2026 # and format flags on "stream" capability, and use
2026 # uncompressed only if compatible.
2027 # uncompressed only if compatible.
2027
2028
2028 if stream and not heads:
2029 if stream and not heads:
2029 # 'stream' means remote revlog format is revlogv1 only
2030 # 'stream' means remote revlog format is revlogv1 only
2030 if remote.capable('stream'):
2031 if remote.capable('stream'):
2031 return self.stream_in(remote, set(('revlogv1',)))
2032 return self.stream_in(remote, set(('revlogv1',)))
2032 # otherwise, 'streamreqs' contains the remote revlog format
2033 # otherwise, 'streamreqs' contains the remote revlog format
2033 streamreqs = remote.capable('streamreqs')
2034 streamreqs = remote.capable('streamreqs')
2034 if streamreqs:
2035 if streamreqs:
2035 streamreqs = set(streamreqs.split(','))
2036 streamreqs = set(streamreqs.split(','))
2036 # if we support it, stream in and adjust our requirements
2037 # if we support it, stream in and adjust our requirements
2037 if not streamreqs - self.supportedformats:
2038 if not streamreqs - self.supportedformats:
2038 return self.stream_in(remote, streamreqs)
2039 return self.stream_in(remote, streamreqs)
2039 return self.pull(remote, heads)
2040 return self.pull(remote, heads)
2040
2041
2041 def pushkey(self, namespace, key, old, new):
2042 def pushkey(self, namespace, key, old, new):
2042 self.hook('prepushkey', throw=True, namespace=namespace, key=key,
2043 self.hook('prepushkey', throw=True, namespace=namespace, key=key,
2043 old=old, new=new)
2044 old=old, new=new)
2044 ret = pushkey.push(self, namespace, key, old, new)
2045 ret = pushkey.push(self, namespace, key, old, new)
2045 self.hook('pushkey', namespace=namespace, key=key, old=old, new=new,
2046 self.hook('pushkey', namespace=namespace, key=key, old=old, new=new,
2046 ret=ret)
2047 ret=ret)
2047 return ret
2048 return ret
2048
2049
2049 def listkeys(self, namespace):
2050 def listkeys(self, namespace):
2050 self.hook('prelistkeys', throw=True, namespace=namespace)
2051 self.hook('prelistkeys', throw=True, namespace=namespace)
2051 values = pushkey.list(self, namespace)
2052 values = pushkey.list(self, namespace)
2052 self.hook('listkeys', namespace=namespace, values=values)
2053 self.hook('listkeys', namespace=namespace, values=values)
2053 return values
2054 return values
2054
2055
2055 def debugwireargs(self, one, two, three=None, four=None, five=None):
2056 def debugwireargs(self, one, two, three=None, four=None, five=None):
2056 '''used to test argument passing over the wire'''
2057 '''used to test argument passing over the wire'''
2057 return "%s %s %s %s %s" % (one, two, three, four, five)
2058 return "%s %s %s %s %s" % (one, two, three, four, five)
2058
2059
2059 def savecommitmessage(self, text):
2060 def savecommitmessage(self, text):
2060 fp = self.opener('last-message.txt', 'wb')
2061 fp = self.opener('last-message.txt', 'wb')
2061 try:
2062 try:
2062 fp.write(text)
2063 fp.write(text)
2063 finally:
2064 finally:
2064 fp.close()
2065 fp.close()
2065 return self.pathto(fp.name[len(self.root)+1:])
2066 return self.pathto(fp.name[len(self.root)+1:])
2066
2067
2067 # used to avoid circular references so destructors work
2068 # used to avoid circular references so destructors work
2068 def aftertrans(files):
2069 def aftertrans(files):
2069 renamefiles = [tuple(t) for t in files]
2070 renamefiles = [tuple(t) for t in files]
2070 def a():
2071 def a():
2071 for src, dest in renamefiles:
2072 for src, dest in renamefiles:
2072 util.rename(src, dest)
2073 util.rename(src, dest)
2073 return a
2074 return a
2074
2075
2075 def undoname(fn):
2076 def undoname(fn):
2076 base, name = os.path.split(fn)
2077 base, name = os.path.split(fn)
2077 assert name.startswith('journal')
2078 assert name.startswith('journal')
2078 return os.path.join(base, name.replace('journal', 'undo', 1))
2079 return os.path.join(base, name.replace('journal', 'undo', 1))
2079
2080
2080 def instance(ui, path, create):
2081 def instance(ui, path, create):
2081 return localrepository(ui, util.urllocalpath(path), create)
2082 return localrepository(ui, util.urllocalpath(path), create)
2082
2083
2083 def islocal(path):
2084 def islocal(path):
2084 return True
2085 return True
@@ -1,270 +1,270 b''
1 Show all commands except debug commands
1 Show all commands except debug commands
2 $ hg debugcomplete
2 $ hg debugcomplete
3 add
3 add
4 addremove
4 addremove
5 annotate
5 annotate
6 archive
6 archive
7 backout
7 backout
8 bisect
8 bisect
9 bookmarks
9 bookmarks
10 branch
10 branch
11 branches
11 branches
12 bundle
12 bundle
13 cat
13 cat
14 clone
14 clone
15 commit
15 commit
16 copy
16 copy
17 diff
17 diff
18 export
18 export
19 forget
19 forget
20 graft
20 graft
21 grep
21 grep
22 heads
22 heads
23 help
23 help
24 identify
24 identify
25 import
25 import
26 incoming
26 incoming
27 init
27 init
28 locate
28 locate
29 log
29 log
30 manifest
30 manifest
31 merge
31 merge
32 outgoing
32 outgoing
33 parents
33 parents
34 paths
34 paths
35 pull
35 pull
36 push
36 push
37 recover
37 recover
38 remove
38 remove
39 rename
39 rename
40 resolve
40 resolve
41 revert
41 revert
42 rollback
42 rollback
43 root
43 root
44 serve
44 serve
45 showconfig
45 showconfig
46 status
46 status
47 summary
47 summary
48 tag
48 tag
49 tags
49 tags
50 tip
50 tip
51 unbundle
51 unbundle
52 update
52 update
53 verify
53 verify
54 version
54 version
55
55
56 Show all commands that start with "a"
56 Show all commands that start with "a"
57 $ hg debugcomplete a
57 $ hg debugcomplete a
58 add
58 add
59 addremove
59 addremove
60 annotate
60 annotate
61 archive
61 archive
62
62
63 Do not show debug commands if there are other candidates
63 Do not show debug commands if there are other candidates
64 $ hg debugcomplete d
64 $ hg debugcomplete d
65 diff
65 diff
66
66
67 Show debug commands if there are no other candidates
67 Show debug commands if there are no other candidates
68 $ hg debugcomplete debug
68 $ hg debugcomplete debug
69 debugancestor
69 debugancestor
70 debugbuilddag
70 debugbuilddag
71 debugbundle
71 debugbundle
72 debugcheckstate
72 debugcheckstate
73 debugcommands
73 debugcommands
74 debugcomplete
74 debugcomplete
75 debugconfig
75 debugconfig
76 debugdag
76 debugdag
77 debugdata
77 debugdata
78 debugdate
78 debugdate
79 debugdiscovery
79 debugdiscovery
80 debugfileset
80 debugfileset
81 debugfsinfo
81 debugfsinfo
82 debuggetbundle
82 debuggetbundle
83 debugignore
83 debugignore
84 debugindex
84 debugindex
85 debugindexdot
85 debugindexdot
86 debuginstall
86 debuginstall
87 debugknown
87 debugknown
88 debugpushkey
88 debugpushkey
89 debugrebuildstate
89 debugrebuildstate
90 debugrename
90 debugrename
91 debugrevlog
91 debugrevlog
92 debugrevspec
92 debugrevspec
93 debugsetparents
93 debugsetparents
94 debugstate
94 debugstate
95 debugsub
95 debugsub
96 debugwalk
96 debugwalk
97 debugwireargs
97 debugwireargs
98
98
99 Do not show the alias of a debug command if there are other candidates
99 Do not show the alias of a debug command if there are other candidates
100 (this should hide rawcommit)
100 (this should hide rawcommit)
101 $ hg debugcomplete r
101 $ hg debugcomplete r
102 recover
102 recover
103 remove
103 remove
104 rename
104 rename
105 resolve
105 resolve
106 revert
106 revert
107 rollback
107 rollback
108 root
108 root
109 Show the alias of a debug command if there are no other candidates
109 Show the alias of a debug command if there are no other candidates
110 $ hg debugcomplete rawc
110 $ hg debugcomplete rawc
111
111
112
112
113 Show the global options
113 Show the global options
114 $ hg debugcomplete --options | sort
114 $ hg debugcomplete --options | sort
115 --config
115 --config
116 --cwd
116 --cwd
117 --debug
117 --debug
118 --debugger
118 --debugger
119 --encoding
119 --encoding
120 --encodingmode
120 --encodingmode
121 --help
121 --help
122 --noninteractive
122 --noninteractive
123 --profile
123 --profile
124 --quiet
124 --quiet
125 --repository
125 --repository
126 --time
126 --time
127 --traceback
127 --traceback
128 --verbose
128 --verbose
129 --version
129 --version
130 -R
130 -R
131 -h
131 -h
132 -q
132 -q
133 -v
133 -v
134 -y
134 -y
135
135
136 Show the options for the "serve" command
136 Show the options for the "serve" command
137 $ hg debugcomplete --options serve | sort
137 $ hg debugcomplete --options serve | sort
138 --accesslog
138 --accesslog
139 --address
139 --address
140 --certificate
140 --certificate
141 --cmdserver
141 --cmdserver
142 --config
142 --config
143 --cwd
143 --cwd
144 --daemon
144 --daemon
145 --daemon-pipefds
145 --daemon-pipefds
146 --debug
146 --debug
147 --debugger
147 --debugger
148 --encoding
148 --encoding
149 --encodingmode
149 --encodingmode
150 --errorlog
150 --errorlog
151 --help
151 --help
152 --ipv6
152 --ipv6
153 --name
153 --name
154 --noninteractive
154 --noninteractive
155 --pid-file
155 --pid-file
156 --port
156 --port
157 --prefix
157 --prefix
158 --profile
158 --profile
159 --quiet
159 --quiet
160 --repository
160 --repository
161 --stdio
161 --stdio
162 --style
162 --style
163 --templates
163 --templates
164 --time
164 --time
165 --traceback
165 --traceback
166 --verbose
166 --verbose
167 --version
167 --version
168 --web-conf
168 --web-conf
169 -6
169 -6
170 -A
170 -A
171 -E
171 -E
172 -R
172 -R
173 -a
173 -a
174 -d
174 -d
175 -h
175 -h
176 -n
176 -n
177 -p
177 -p
178 -q
178 -q
179 -t
179 -t
180 -v
180 -v
181 -y
181 -y
182
182
183 Show an error if we use --options with an ambiguous abbreviation
183 Show an error if we use --options with an ambiguous abbreviation
184 $ hg debugcomplete --options s
184 $ hg debugcomplete --options s
185 hg: command 's' is ambiguous:
185 hg: command 's' is ambiguous:
186 serve showconfig status summary
186 serve showconfig status summary
187 [255]
187 [255]
188
188
189 Show all commands + options
189 Show all commands + options
190 $ hg debugcommands
190 $ hg debugcommands
191 add: include, exclude, subrepos, dry-run
191 add: include, exclude, subrepos, dry-run
192 annotate: rev, follow, no-follow, text, user, file, date, number, changeset, line-number, include, exclude
192 annotate: rev, follow, no-follow, text, user, file, date, number, changeset, line-number, include, exclude
193 clone: noupdate, updaterev, rev, branch, pull, uncompressed, ssh, remotecmd, insecure
193 clone: noupdate, updaterev, rev, branch, pull, uncompressed, ssh, remotecmd, insecure
194 commit: addremove, close-branch, include, exclude, message, logfile, date, user
194 commit: addremove, close-branch, include, exclude, message, logfile, date, user, subrepos
195 diff: rev, change, text, git, nodates, show-function, reverse, ignore-all-space, ignore-space-change, ignore-blank-lines, unified, stat, include, exclude, subrepos
195 diff: rev, change, text, git, nodates, show-function, reverse, ignore-all-space, ignore-space-change, ignore-blank-lines, unified, stat, include, exclude, subrepos
196 export: output, switch-parent, rev, text, git, nodates
196 export: output, switch-parent, rev, text, git, nodates
197 forget: include, exclude
197 forget: include, exclude
198 init: ssh, remotecmd, insecure
198 init: ssh, remotecmd, insecure
199 log: follow, follow-first, date, copies, keyword, rev, removed, only-merges, user, only-branch, branch, prune, hidden, patch, git, limit, no-merges, stat, style, template, include, exclude
199 log: follow, follow-first, date, copies, keyword, rev, removed, only-merges, user, only-branch, branch, prune, hidden, patch, git, limit, no-merges, stat, style, template, include, exclude
200 merge: force, rev, preview, tool
200 merge: force, rev, preview, tool
201 pull: update, force, rev, bookmark, branch, ssh, remotecmd, insecure
201 pull: update, force, rev, bookmark, branch, ssh, remotecmd, insecure
202 push: force, rev, bookmark, branch, new-branch, ssh, remotecmd, insecure
202 push: force, rev, bookmark, branch, new-branch, ssh, remotecmd, insecure
203 remove: after, force, include, exclude
203 remove: after, force, include, exclude
204 serve: accesslog, daemon, daemon-pipefds, errorlog, port, address, prefix, name, web-conf, webdir-conf, pid-file, stdio, cmdserver, templates, style, ipv6, certificate
204 serve: accesslog, daemon, daemon-pipefds, errorlog, port, address, prefix, name, web-conf, webdir-conf, pid-file, stdio, cmdserver, templates, style, ipv6, certificate
205 status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, copies, print0, rev, change, include, exclude, subrepos
205 status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, copies, print0, rev, change, include, exclude, subrepos
206 summary: remote
206 summary: remote
207 update: clean, check, date, rev
207 update: clean, check, date, rev
208 addremove: similarity, include, exclude, dry-run
208 addremove: similarity, include, exclude, dry-run
209 archive: no-decode, prefix, rev, type, subrepos, include, exclude
209 archive: no-decode, prefix, rev, type, subrepos, include, exclude
210 backout: merge, parent, rev, tool, include, exclude, message, logfile, date, user
210 backout: merge, parent, rev, tool, include, exclude, message, logfile, date, user
211 bisect: reset, good, bad, skip, extend, command, noupdate
211 bisect: reset, good, bad, skip, extend, command, noupdate
212 bookmarks: force, rev, delete, rename, inactive
212 bookmarks: force, rev, delete, rename, inactive
213 branch: force, clean
213 branch: force, clean
214 branches: active, closed
214 branches: active, closed
215 bundle: force, rev, branch, base, all, type, ssh, remotecmd, insecure
215 bundle: force, rev, branch, base, all, type, ssh, remotecmd, insecure
216 cat: output, rev, decode, include, exclude
216 cat: output, rev, decode, include, exclude
217 copy: after, force, include, exclude, dry-run
217 copy: after, force, include, exclude, dry-run
218 debugancestor:
218 debugancestor:
219 debugbuilddag: mergeable-file, overwritten-file, new-file
219 debugbuilddag: mergeable-file, overwritten-file, new-file
220 debugbundle: all
220 debugbundle: all
221 debugcheckstate:
221 debugcheckstate:
222 debugcommands:
222 debugcommands:
223 debugcomplete: options
223 debugcomplete: options
224 debugdag: tags, branches, dots, spaces
224 debugdag: tags, branches, dots, spaces
225 debugdata: changelog, manifest
225 debugdata: changelog, manifest
226 debugdate: extended
226 debugdate: extended
227 debugdiscovery: old, nonheads, ssh, remotecmd, insecure
227 debugdiscovery: old, nonheads, ssh, remotecmd, insecure
228 debugfileset:
228 debugfileset:
229 debugfsinfo:
229 debugfsinfo:
230 debuggetbundle: head, common, type
230 debuggetbundle: head, common, type
231 debugignore:
231 debugignore:
232 debugindex: changelog, manifest, format
232 debugindex: changelog, manifest, format
233 debugindexdot:
233 debugindexdot:
234 debuginstall:
234 debuginstall:
235 debugknown:
235 debugknown:
236 debugpushkey:
236 debugpushkey:
237 debugrebuildstate: rev
237 debugrebuildstate: rev
238 debugrename: rev
238 debugrename: rev
239 debugrevlog: changelog, manifest, dump
239 debugrevlog: changelog, manifest, dump
240 debugrevspec:
240 debugrevspec:
241 debugsetparents:
241 debugsetparents:
242 debugstate: nodates, datesort
242 debugstate: nodates, datesort
243 debugsub: rev
243 debugsub: rev
244 debugwalk: include, exclude
244 debugwalk: include, exclude
245 debugwireargs: three, four, five, ssh, remotecmd, insecure
245 debugwireargs: three, four, five, ssh, remotecmd, insecure
246 graft: continue, edit, currentdate, currentuser, date, user, tool
246 graft: continue, edit, currentdate, currentuser, date, user, tool
247 grep: print0, all, text, follow, ignore-case, files-with-matches, line-number, rev, user, date, include, exclude
247 grep: print0, all, text, follow, ignore-case, files-with-matches, line-number, rev, user, date, include, exclude
248 heads: rev, topo, active, closed, style, template
248 heads: rev, topo, active, closed, style, template
249 help: extension, command
249 help: extension, command
250 identify: rev, num, id, branch, tags, bookmarks
250 identify: rev, num, id, branch, tags, bookmarks
251 import: strip, base, edit, force, no-commit, bypass, exact, import-branch, message, logfile, date, user, similarity
251 import: strip, base, edit, force, no-commit, bypass, exact, import-branch, message, logfile, date, user, similarity
252 incoming: force, newest-first, bundle, rev, bookmarks, branch, patch, git, limit, no-merges, stat, style, template, ssh, remotecmd, insecure, subrepos
252 incoming: force, newest-first, bundle, rev, bookmarks, branch, patch, git, limit, no-merges, stat, style, template, ssh, remotecmd, insecure, subrepos
253 locate: rev, print0, fullpath, include, exclude
253 locate: rev, print0, fullpath, include, exclude
254 manifest: rev, all
254 manifest: rev, all
255 outgoing: force, rev, newest-first, bookmarks, branch, patch, git, limit, no-merges, stat, style, template, ssh, remotecmd, insecure, subrepos
255 outgoing: force, rev, newest-first, bookmarks, branch, patch, git, limit, no-merges, stat, style, template, ssh, remotecmd, insecure, subrepos
256 parents: rev, style, template
256 parents: rev, style, template
257 paths:
257 paths:
258 recover:
258 recover:
259 rename: after, force, include, exclude, dry-run
259 rename: after, force, include, exclude, dry-run
260 resolve: all, list, mark, unmark, no-status, tool, include, exclude
260 resolve: all, list, mark, unmark, no-status, tool, include, exclude
261 revert: all, date, rev, no-backup, include, exclude, dry-run
261 revert: all, date, rev, no-backup, include, exclude, dry-run
262 rollback: dry-run, force
262 rollback: dry-run, force
263 root:
263 root:
264 showconfig: untrusted
264 showconfig: untrusted
265 tag: force, local, rev, remove, edit, message, date, user
265 tag: force, local, rev, remove, edit, message, date, user
266 tags:
266 tags:
267 tip: patch, git, style, template
267 tip: patch, git, style, template
268 unbundle: update
268 unbundle: update
269 verify:
269 verify:
270 version:
270 version:
@@ -1,361 +1,363 b''
1 $ echo "[ui]" >> $HGRCPATH
2 $ echo "commitsubrepos = Yes" >> $HGRCPATH
1 $ echo "[extensions]" >> $HGRCPATH
3 $ echo "[extensions]" >> $HGRCPATH
2 $ echo "mq=" >> $HGRCPATH
4 $ echo "mq=" >> $HGRCPATH
3 $ echo "record=" >> $HGRCPATH
5 $ echo "record=" >> $HGRCPATH
4 $ echo "[diff]" >> $HGRCPATH
6 $ echo "[diff]" >> $HGRCPATH
5 $ echo "nodates=1" >> $HGRCPATH
7 $ echo "nodates=1" >> $HGRCPATH
6
8
7 $ stdin=`pwd`/stdin.tmp
9 $ stdin=`pwd`/stdin.tmp
8
10
9 fn to create new repository w/dirty subrepo, and cd into it
11 fn to create new repository w/dirty subrepo, and cd into it
10 $ mkrepo() {
12 $ mkrepo() {
11 > hg init $1
13 > hg init $1
12 > cd $1
14 > cd $1
13 > hg qinit
15 > hg qinit
14 > }
16 > }
15
17
16 fn to create dirty subrepo
18 fn to create dirty subrepo
17 $ mksubrepo() {
19 $ mksubrepo() {
18 > hg init $1
20 > hg init $1
19 > cd $1
21 > cd $1
20 > echo a > a
22 > echo a > a
21 > hg add
23 > hg add
22 > cd ..
24 > cd ..
23 > }
25 > }
24
26
25 $ testadd() {
27 $ testadd() {
26 > cat - > "$stdin"
28 > cat - > "$stdin"
27 > mksubrepo sub
29 > mksubrepo sub
28 > echo sub = sub >> .hgsub
30 > echo sub = sub >> .hgsub
29 > hg add .hgsub
31 > hg add .hgsub
30 > echo % abort when adding .hgsub w/dirty subrepo
32 > echo % abort when adding .hgsub w/dirty subrepo
31 > hg status -S
33 > hg status -S
32 > echo '%' $*
34 > echo '%' $*
33 > cat "$stdin" | hg $*
35 > cat "$stdin" | hg $*
34 > echo [$?]
36 > echo [$?]
35 > hg -R sub ci -m0sub
37 > hg -R sub ci -m0sub
36 > echo % update substate when adding .hgsub w/clean updated subrepo
38 > echo % update substate when adding .hgsub w/clean updated subrepo
37 > hg status -S
39 > hg status -S
38 > echo '%' $*
40 > echo '%' $*
39 > cat "$stdin" | hg $*
41 > cat "$stdin" | hg $*
40 > hg debugsub
42 > hg debugsub
41 > }
43 > }
42
44
43 $ testmod() {
45 $ testmod() {
44 > cat - > "$stdin"
46 > cat - > "$stdin"
45 > mksubrepo sub2
47 > mksubrepo sub2
46 > echo sub2 = sub2 >> .hgsub
48 > echo sub2 = sub2 >> .hgsub
47 > echo % abort when modifying .hgsub w/dirty subrepo
49 > echo % abort when modifying .hgsub w/dirty subrepo
48 > hg status -S
50 > hg status -S
49 > echo '%' $*
51 > echo '%' $*
50 > cat "$stdin" | hg $*
52 > cat "$stdin" | hg $*
51 > echo [$?]
53 > echo [$?]
52 > hg -R sub2 ci -m0sub2
54 > hg -R sub2 ci -m0sub2
53 > echo % update substate when modifying .hgsub w/clean updated subrepo
55 > echo % update substate when modifying .hgsub w/clean updated subrepo
54 > hg status -S
56 > hg status -S
55 > echo '%' $*
57 > echo '%' $*
56 > cat "$stdin" | hg $*
58 > cat "$stdin" | hg $*
57 > hg debugsub
59 > hg debugsub
58 > }
60 > }
59
61
60 $ testrm1() {
62 $ testrm1() {
61 > cat - > "$stdin"
63 > cat - > "$stdin"
62 > mksubrepo sub3
64 > mksubrepo sub3
63 > echo sub3 = sub3 >> .hgsub
65 > echo sub3 = sub3 >> .hgsub
64 > hg ci -Aqmsub3
66 > hg ci -Aqmsub3
65 > $EXTRA
67 > $EXTRA
66 > echo b >> sub3/a
68 > echo b >> sub3/a
67 > hg rm .hgsub
69 > hg rm .hgsub
68 > echo % update substate when removing .hgsub w/dirty subrepo
70 > echo % update substate when removing .hgsub w/dirty subrepo
69 > hg status -S
71 > hg status -S
70 > echo '%' $*
72 > echo '%' $*
71 > cat "$stdin" | hg $*
73 > cat "$stdin" | hg $*
72 > echo % debugsub should be empty
74 > echo % debugsub should be empty
73 > hg debugsub
75 > hg debugsub
74 > }
76 > }
75
77
76 $ testrm2() {
78 $ testrm2() {
77 > cat - > "$stdin"
79 > cat - > "$stdin"
78 > mksubrepo sub4
80 > mksubrepo sub4
79 > echo sub4 = sub4 >> .hgsub
81 > echo sub4 = sub4 >> .hgsub
80 > hg ci -Aqmsub4
82 > hg ci -Aqmsub4
81 > $EXTRA
83 > $EXTRA
82 > hg rm .hgsub
84 > hg rm .hgsub
83 > echo % update substate when removing .hgsub w/clean updated subrepo
85 > echo % update substate when removing .hgsub w/clean updated subrepo
84 > hg status -S
86 > hg status -S
85 > echo '%' $*
87 > echo '%' $*
86 > cat "$stdin" | hg $*
88 > cat "$stdin" | hg $*
87 > echo % debugsub should be empty
89 > echo % debugsub should be empty
88 > hg debugsub
90 > hg debugsub
89 > }
91 > }
90
92
91
93
92 handle subrepos safely on qnew
94 handle subrepos safely on qnew
93
95
94 $ mkrepo repo-2499-qnew
96 $ mkrepo repo-2499-qnew
95 $ testadd qnew -m0 0.diff
97 $ testadd qnew -m0 0.diff
96 adding a
98 adding a
97 % abort when adding .hgsub w/dirty subrepo
99 % abort when adding .hgsub w/dirty subrepo
98 A .hgsub
100 A .hgsub
99 A sub/a
101 A sub/a
100 % qnew -m0 0.diff
102 % qnew -m0 0.diff
101 abort: uncommitted changes in subrepository sub
103 abort: uncommitted changes in subrepository sub
102 [255]
104 [255]
103 % update substate when adding .hgsub w/clean updated subrepo
105 % update substate when adding .hgsub w/clean updated subrepo
104 A .hgsub
106 A .hgsub
105 % qnew -m0 0.diff
107 % qnew -m0 0.diff
106 committing subrepository sub
108 committing subrepository sub
107 path sub
109 path sub
108 source sub
110 source sub
109 revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
111 revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
110
112
111 $ testmod qnew -m1 1.diff
113 $ testmod qnew -m1 1.diff
112 adding a
114 adding a
113 % abort when modifying .hgsub w/dirty subrepo
115 % abort when modifying .hgsub w/dirty subrepo
114 M .hgsub
116 M .hgsub
115 A sub2/a
117 A sub2/a
116 % qnew -m1 1.diff
118 % qnew -m1 1.diff
117 abort: uncommitted changes in subrepository sub2
119 abort: uncommitted changes in subrepository sub2
118 [255]
120 [255]
119 % update substate when modifying .hgsub w/clean updated subrepo
121 % update substate when modifying .hgsub w/clean updated subrepo
120 M .hgsub
122 M .hgsub
121 % qnew -m1 1.diff
123 % qnew -m1 1.diff
122 committing subrepository sub2
124 committing subrepository sub2
123 path sub
125 path sub
124 source sub
126 source sub
125 revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
127 revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
126 path sub2
128 path sub2
127 source sub2
129 source sub2
128 revision 1f94c7611cc6b74f5a17b16121a1170d44776845
130 revision 1f94c7611cc6b74f5a17b16121a1170d44776845
129
131
130 $ hg qpop -qa
132 $ hg qpop -qa
131 patch queue now empty
133 patch queue now empty
132 $ testrm1 qnew -m2 2.diff
134 $ testrm1 qnew -m2 2.diff
133 adding a
135 adding a
134 % update substate when removing .hgsub w/dirty subrepo
136 % update substate when removing .hgsub w/dirty subrepo
135 M sub3/a
137 M sub3/a
136 R .hgsub
138 R .hgsub
137 % qnew -m2 2.diff
139 % qnew -m2 2.diff
138 % debugsub should be empty
140 % debugsub should be empty
139
141
140 $ hg qpop -qa
142 $ hg qpop -qa
141 patch queue now empty
143 patch queue now empty
142 $ testrm2 qnew -m3 3.diff
144 $ testrm2 qnew -m3 3.diff
143 adding a
145 adding a
144 % update substate when removing .hgsub w/clean updated subrepo
146 % update substate when removing .hgsub w/clean updated subrepo
145 R .hgsub
147 R .hgsub
146 % qnew -m3 3.diff
148 % qnew -m3 3.diff
147 % debugsub should be empty
149 % debugsub should be empty
148
150
149 $ cd ..
151 $ cd ..
150
152
151
153
152 handle subrepos safely on qrefresh
154 handle subrepos safely on qrefresh
153
155
154 $ mkrepo repo-2499-qrefresh
156 $ mkrepo repo-2499-qrefresh
155 $ hg qnew -m0 0.diff
157 $ hg qnew -m0 0.diff
156 $ testadd qrefresh
158 $ testadd qrefresh
157 adding a
159 adding a
158 % abort when adding .hgsub w/dirty subrepo
160 % abort when adding .hgsub w/dirty subrepo
159 A .hgsub
161 A .hgsub
160 A sub/a
162 A sub/a
161 % qrefresh
163 % qrefresh
162 abort: uncommitted changes in subrepository sub
164 abort: uncommitted changes in subrepository sub
163 [255]
165 [255]
164 % update substate when adding .hgsub w/clean updated subrepo
166 % update substate when adding .hgsub w/clean updated subrepo
165 A .hgsub
167 A .hgsub
166 % qrefresh
168 % qrefresh
167 committing subrepository sub
169 committing subrepository sub
168 path sub
170 path sub
169 source sub
171 source sub
170 revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
172 revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
171
173
172 $ hg qnew -m1 1.diff
174 $ hg qnew -m1 1.diff
173 $ testmod qrefresh
175 $ testmod qrefresh
174 adding a
176 adding a
175 % abort when modifying .hgsub w/dirty subrepo
177 % abort when modifying .hgsub w/dirty subrepo
176 M .hgsub
178 M .hgsub
177 A sub2/a
179 A sub2/a
178 % qrefresh
180 % qrefresh
179 abort: uncommitted changes in subrepository sub2
181 abort: uncommitted changes in subrepository sub2
180 [255]
182 [255]
181 % update substate when modifying .hgsub w/clean updated subrepo
183 % update substate when modifying .hgsub w/clean updated subrepo
182 M .hgsub
184 M .hgsub
183 % qrefresh
185 % qrefresh
184 committing subrepository sub2
186 committing subrepository sub2
185 path sub
187 path sub
186 source sub
188 source sub
187 revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
189 revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
188 path sub2
190 path sub2
189 source sub2
191 source sub2
190 revision 1f94c7611cc6b74f5a17b16121a1170d44776845
192 revision 1f94c7611cc6b74f5a17b16121a1170d44776845
191
193
192 $ hg qpop -qa
194 $ hg qpop -qa
193 patch queue now empty
195 patch queue now empty
194 $ EXTRA='hg qnew -m2 2.diff'
196 $ EXTRA='hg qnew -m2 2.diff'
195 $ testrm1 qrefresh
197 $ testrm1 qrefresh
196 adding a
198 adding a
197 % update substate when removing .hgsub w/dirty subrepo
199 % update substate when removing .hgsub w/dirty subrepo
198 M sub3/a
200 M sub3/a
199 R .hgsub
201 R .hgsub
200 % qrefresh
202 % qrefresh
201 % debugsub should be empty
203 % debugsub should be empty
202
204
203 $ hg qpop -qa
205 $ hg qpop -qa
204 patch queue now empty
206 patch queue now empty
205 $ EXTRA='hg qnew -m3 3.diff'
207 $ EXTRA='hg qnew -m3 3.diff'
206 $ testrm2 qrefresh
208 $ testrm2 qrefresh
207 adding a
209 adding a
208 % update substate when removing .hgsub w/clean updated subrepo
210 % update substate when removing .hgsub w/clean updated subrepo
209 R .hgsub
211 R .hgsub
210 % qrefresh
212 % qrefresh
211 % debugsub should be empty
213 % debugsub should be empty
212 $ EXTRA=
214 $ EXTRA=
213
215
214 $ cd ..
216 $ cd ..
215
217
216
218
217 handle subrepos safely on qpush/qpop
219 handle subrepos safely on qpush/qpop
218
220
219 $ mkrepo repo-2499-qpush
221 $ mkrepo repo-2499-qpush
220 $ mksubrepo sub
222 $ mksubrepo sub
221 adding a
223 adding a
222 $ hg -R sub ci -m0sub
224 $ hg -R sub ci -m0sub
223 $ echo sub = sub > .hgsub
225 $ echo sub = sub > .hgsub
224 $ hg add .hgsub
226 $ hg add .hgsub
225 $ hg qnew -m0 0.diff
227 $ hg qnew -m0 0.diff
226 committing subrepository sub
228 committing subrepository sub
227 $ hg debugsub
229 $ hg debugsub
228 path sub
230 path sub
229 source sub
231 source sub
230 revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
232 revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
231
233
232 qpop
234 qpop
233 $ hg qpop
235 $ hg qpop
234 popping 0.diff
236 popping 0.diff
235 patch queue now empty
237 patch queue now empty
236 $ hg status -AS
238 $ hg status -AS
237 $ hg debugsub
239 $ hg debugsub
238
240
239 qpush
241 qpush
240 $ hg qpush
242 $ hg qpush
241 applying 0.diff
243 applying 0.diff
242 now at: 0.diff
244 now at: 0.diff
243 $ hg status -AS
245 $ hg status -AS
244 C .hgsub
246 C .hgsub
245 C .hgsubstate
247 C .hgsubstate
246 C sub/a
248 C sub/a
247 $ hg debugsub
249 $ hg debugsub
248 path sub
250 path sub
249 source sub
251 source sub
250 revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
252 revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
251
253
252 $ cd ..
254 $ cd ..
253
255
254
256
255 handle subrepos safely on qrecord
257 handle subrepos safely on qrecord
256
258
257 $ mkrepo repo-2499-qrecord
259 $ mkrepo repo-2499-qrecord
258 $ testadd qrecord --config ui.interactive=1 -m0 0.diff <<EOF
260 $ testadd qrecord --config ui.interactive=1 -m0 0.diff <<EOF
259 > y
261 > y
260 > y
262 > y
261 > EOF
263 > EOF
262 adding a
264 adding a
263 % abort when adding .hgsub w/dirty subrepo
265 % abort when adding .hgsub w/dirty subrepo
264 A .hgsub
266 A .hgsub
265 A sub/a
267 A sub/a
266 % qrecord --config ui.interactive=1 -m0 0.diff
268 % qrecord --config ui.interactive=1 -m0 0.diff
267 diff --git a/.hgsub b/.hgsub
269 diff --git a/.hgsub b/.hgsub
268 new file mode 100644
270 new file mode 100644
269 examine changes to '.hgsub'? [Ynsfdaq?]
271 examine changes to '.hgsub'? [Ynsfdaq?]
270 abort: uncommitted changes in subrepository sub
272 abort: uncommitted changes in subrepository sub
271 [255]
273 [255]
272 % update substate when adding .hgsub w/clean updated subrepo
274 % update substate when adding .hgsub w/clean updated subrepo
273 A .hgsub
275 A .hgsub
274 % qrecord --config ui.interactive=1 -m0 0.diff
276 % qrecord --config ui.interactive=1 -m0 0.diff
275 diff --git a/.hgsub b/.hgsub
277 diff --git a/.hgsub b/.hgsub
276 new file mode 100644
278 new file mode 100644
277 examine changes to '.hgsub'? [Ynsfdaq?]
279 examine changes to '.hgsub'? [Ynsfdaq?]
278 committing subrepository sub
280 committing subrepository sub
279 path sub
281 path sub
280 source sub
282 source sub
281 revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
283 revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
282
284
283 $ testmod qrecord --config ui.interactive=1 -m1 1.diff <<EOF
285 $ testmod qrecord --config ui.interactive=1 -m1 1.diff <<EOF
284 > y
286 > y
285 > y
287 > y
286 > EOF
288 > EOF
287 adding a
289 adding a
288 % abort when modifying .hgsub w/dirty subrepo
290 % abort when modifying .hgsub w/dirty subrepo
289 M .hgsub
291 M .hgsub
290 A sub2/a
292 A sub2/a
291 % qrecord --config ui.interactive=1 -m1 1.diff
293 % qrecord --config ui.interactive=1 -m1 1.diff
292 diff --git a/.hgsub b/.hgsub
294 diff --git a/.hgsub b/.hgsub
293 1 hunks, 1 lines changed
295 1 hunks, 1 lines changed
294 examine changes to '.hgsub'? [Ynsfdaq?]
296 examine changes to '.hgsub'? [Ynsfdaq?]
295 @@ -1,1 +1,2 @@
297 @@ -1,1 +1,2 @@
296 sub = sub
298 sub = sub
297 +sub2 = sub2
299 +sub2 = sub2
298 record this change to '.hgsub'? [Ynsfdaq?]
300 record this change to '.hgsub'? [Ynsfdaq?]
299 abort: uncommitted changes in subrepository sub2
301 abort: uncommitted changes in subrepository sub2
300 [255]
302 [255]
301 % update substate when modifying .hgsub w/clean updated subrepo
303 % update substate when modifying .hgsub w/clean updated subrepo
302 M .hgsub
304 M .hgsub
303 % qrecord --config ui.interactive=1 -m1 1.diff
305 % qrecord --config ui.interactive=1 -m1 1.diff
304 diff --git a/.hgsub b/.hgsub
306 diff --git a/.hgsub b/.hgsub
305 1 hunks, 1 lines changed
307 1 hunks, 1 lines changed
306 examine changes to '.hgsub'? [Ynsfdaq?]
308 examine changes to '.hgsub'? [Ynsfdaq?]
307 @@ -1,1 +1,2 @@
309 @@ -1,1 +1,2 @@
308 sub = sub
310 sub = sub
309 +sub2 = sub2
311 +sub2 = sub2
310 record this change to '.hgsub'? [Ynsfdaq?]
312 record this change to '.hgsub'? [Ynsfdaq?]
311 committing subrepository sub2
313 committing subrepository sub2
312 path sub
314 path sub
313 source sub
315 source sub
314 revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
316 revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
315 path sub2
317 path sub2
316 source sub2
318 source sub2
317 revision 1f94c7611cc6b74f5a17b16121a1170d44776845
319 revision 1f94c7611cc6b74f5a17b16121a1170d44776845
318
320
319 $ hg qpop -qa
321 $ hg qpop -qa
320 patch queue now empty
322 patch queue now empty
321 $ testrm1 qrecord --config ui.interactive=1 -m2 2.diff <<EOF
323 $ testrm1 qrecord --config ui.interactive=1 -m2 2.diff <<EOF
322 > y
324 > y
323 > y
325 > y
324 > EOF
326 > EOF
325 adding a
327 adding a
326 % update substate when removing .hgsub w/dirty subrepo
328 % update substate when removing .hgsub w/dirty subrepo
327 M sub3/a
329 M sub3/a
328 R .hgsub
330 R .hgsub
329 % qrecord --config ui.interactive=1 -m2 2.diff
331 % qrecord --config ui.interactive=1 -m2 2.diff
330 diff --git a/.hgsub b/.hgsub
332 diff --git a/.hgsub b/.hgsub
331 deleted file mode 100644
333 deleted file mode 100644
332 examine changes to '.hgsub'? [Ynsfdaq?]
334 examine changes to '.hgsub'? [Ynsfdaq?]
333 % debugsub should be empty
335 % debugsub should be empty
334
336
335 $ hg qpop -qa
337 $ hg qpop -qa
336 patch queue now empty
338 patch queue now empty
337 $ testrm2 qrecord --config ui.interactive=1 -m3 3.diff <<EOF
339 $ testrm2 qrecord --config ui.interactive=1 -m3 3.diff <<EOF
338 > y
340 > y
339 > y
341 > y
340 > EOF
342 > EOF
341 adding a
343 adding a
342 % update substate when removing .hgsub w/clean updated subrepo
344 % update substate when removing .hgsub w/clean updated subrepo
343 R .hgsub
345 R .hgsub
344 % qrecord --config ui.interactive=1 -m3 3.diff
346 % qrecord --config ui.interactive=1 -m3 3.diff
345 diff --git a/.hgsub b/.hgsub
347 diff --git a/.hgsub b/.hgsub
346 deleted file mode 100644
348 deleted file mode 100644
347 examine changes to '.hgsub'? [Ynsfdaq?]
349 examine changes to '.hgsub'? [Ynsfdaq?]
348 % debugsub should be empty
350 % debugsub should be empty
349
351
350 $ cd ..
352 $ cd ..
351
353
352
354
353 correctly handle subrepos with patch queues
355 correctly handle subrepos with patch queues
354 $ mkrepo repo-subrepo-with-queue
356 $ mkrepo repo-subrepo-with-queue
355 $ mksubrepo sub
357 $ mksubrepo sub
356 adding a
358 adding a
357 $ hg -R sub qnew sub0.diff
359 $ hg -R sub qnew sub0.diff
358 $ echo sub = sub >> .hgsub
360 $ echo sub = sub >> .hgsub
359 $ hg add .hgsub
361 $ hg add .hgsub
360 $ hg qnew 0.diff
362 $ hg qnew 0.diff
361 committing subrepository sub
363 committing subrepository sub
@@ -1,396 +1,397 b''
1 Create configuration
1 Create configuration
2
2
3 $ echo "[ui]" >> $HGRCPATH
3 $ echo "[ui]" >> $HGRCPATH
4 $ echo "interactive=true" >> $HGRCPATH
4 $ echo "interactive=true" >> $HGRCPATH
5
5
6 help record (no record)
6 help record (no record)
7
7
8 $ hg help record
8 $ hg help record
9 record extension - commands to interactively select changes for commit/qrefresh
9 record extension - commands to interactively select changes for commit/qrefresh
10
10
11 use "hg help extensions" for information on enabling extensions
11 use "hg help extensions" for information on enabling extensions
12
12
13 help qrecord (no record)
13 help qrecord (no record)
14
14
15 $ hg help qrecord
15 $ hg help qrecord
16 'qrecord' is provided by the following extension:
16 'qrecord' is provided by the following extension:
17
17
18 record commands to interactively select changes for commit/qrefresh
18 record commands to interactively select changes for commit/qrefresh
19
19
20 use "hg help extensions" for information on enabling extensions
20 use "hg help extensions" for information on enabling extensions
21
21
22 $ echo "[extensions]" >> $HGRCPATH
22 $ echo "[extensions]" >> $HGRCPATH
23 $ echo "record=" >> $HGRCPATH
23 $ echo "record=" >> $HGRCPATH
24
24
25 help record (record)
25 help record (record)
26
26
27 $ hg help record
27 $ hg help record
28 hg record [OPTION]... [FILE]...
28 hg record [OPTION]... [FILE]...
29
29
30 interactively select changes to commit
30 interactively select changes to commit
31
31
32 If a list of files is omitted, all changes reported by "hg status" will be
32 If a list of files is omitted, all changes reported by "hg status" will be
33 candidates for recording.
33 candidates for recording.
34
34
35 See "hg help dates" for a list of formats valid for -d/--date.
35 See "hg help dates" for a list of formats valid for -d/--date.
36
36
37 You will be prompted for whether to record changes to each modified file,
37 You will be prompted for whether to record changes to each modified file,
38 and for files with multiple changes, for each change to use. For each
38 and for files with multiple changes, for each change to use. For each
39 query, the following responses are possible:
39 query, the following responses are possible:
40
40
41 y - record this change
41 y - record this change
42 n - skip this change
42 n - skip this change
43
43
44 s - skip remaining changes to this file
44 s - skip remaining changes to this file
45 f - record remaining changes to this file
45 f - record remaining changes to this file
46
46
47 d - done, skip remaining changes and files
47 d - done, skip remaining changes and files
48 a - record all changes to all remaining files
48 a - record all changes to all remaining files
49 q - quit, recording no changes
49 q - quit, recording no changes
50
50
51 ? - display help
51 ? - display help
52
52
53 This command is not available when committing a merge.
53 This command is not available when committing a merge.
54
54
55 options:
55 options:
56
56
57 -A --addremove mark new/missing files as added/removed before
57 -A --addremove mark new/missing files as added/removed before
58 committing
58 committing
59 --close-branch mark a branch as closed, hiding it from the branch
59 --close-branch mark a branch as closed, hiding it from the branch
60 list
60 list
61 -I --include PATTERN [+] include names matching the given patterns
61 -I --include PATTERN [+] include names matching the given patterns
62 -X --exclude PATTERN [+] exclude names matching the given patterns
62 -X --exclude PATTERN [+] exclude names matching the given patterns
63 -m --message TEXT use text as commit message
63 -m --message TEXT use text as commit message
64 -l --logfile FILE read commit message from file
64 -l --logfile FILE read commit message from file
65 -d --date DATE record the specified date as commit date
65 -d --date DATE record the specified date as commit date
66 -u --user USER record the specified user as committer
66 -u --user USER record the specified user as committer
67 -S --subrepos recurse into subrepositories
67 -w --ignore-all-space ignore white space when comparing lines
68 -w --ignore-all-space ignore white space when comparing lines
68 -b --ignore-space-change ignore changes in the amount of white space
69 -b --ignore-space-change ignore changes in the amount of white space
69 -B --ignore-blank-lines ignore changes whose lines are all blank
70 -B --ignore-blank-lines ignore changes whose lines are all blank
70
71
71 [+] marked option can be specified multiple times
72 [+] marked option can be specified multiple times
72
73
73 use "hg -v help record" to show more info
74 use "hg -v help record" to show more info
74
75
75 help (no mq, so no qrecord)
76 help (no mq, so no qrecord)
76
77
77 $ hg help qrecord
78 $ hg help qrecord
78 hg qrecord [OPTION]... PATCH [FILE]...
79 hg qrecord [OPTION]... PATCH [FILE]...
79
80
80 interactively record a new patch
81 interactively record a new patch
81
82
82 See "hg help qnew" & "hg help record" for more information and usage.
83 See "hg help qnew" & "hg help record" for more information and usage.
83
84
84 use "hg -v help qrecord" to show more info
85 use "hg -v help qrecord" to show more info
85
86
86 $ hg init a
87 $ hg init a
87
88
88 qrecord (mq not present)
89 qrecord (mq not present)
89
90
90 $ hg -R a qrecord
91 $ hg -R a qrecord
91 hg qrecord: invalid arguments
92 hg qrecord: invalid arguments
92 hg qrecord [OPTION]... PATCH [FILE]...
93 hg qrecord [OPTION]... PATCH [FILE]...
93
94
94 interactively record a new patch
95 interactively record a new patch
95
96
96 use "hg help qrecord" to show the full help text
97 use "hg help qrecord" to show the full help text
97 [255]
98 [255]
98
99
99 qrecord patch (mq not present)
100 qrecord patch (mq not present)
100
101
101 $ hg -R a qrecord patch
102 $ hg -R a qrecord patch
102 abort: 'mq' extension not loaded
103 abort: 'mq' extension not loaded
103 [255]
104 [255]
104
105
105 help (bad mq)
106 help (bad mq)
106
107
107 $ echo "mq=nonexistant" >> $HGRCPATH
108 $ echo "mq=nonexistant" >> $HGRCPATH
108 $ hg help qrecord
109 $ hg help qrecord
109 *** failed to import extension mq from nonexistant: [Errno 2] No such file or directory
110 *** failed to import extension mq from nonexistant: [Errno 2] No such file or directory
110 hg qrecord [OPTION]... PATCH [FILE]...
111 hg qrecord [OPTION]... PATCH [FILE]...
111
112
112 interactively record a new patch
113 interactively record a new patch
113
114
114 See "hg help qnew" & "hg help record" for more information and usage.
115 See "hg help qnew" & "hg help record" for more information and usage.
115
116
116 use "hg -v help qrecord" to show more info
117 use "hg -v help qrecord" to show more info
117
118
118 help (mq present)
119 help (mq present)
119
120
120 $ sed 's/mq=nonexistant/mq=/' $HGRCPATH > hgrc.tmp
121 $ sed 's/mq=nonexistant/mq=/' $HGRCPATH > hgrc.tmp
121 $ mv hgrc.tmp $HGRCPATH
122 $ mv hgrc.tmp $HGRCPATH
122
123
123 $ hg help qrecord
124 $ hg help qrecord
124 hg qrecord [OPTION]... PATCH [FILE]...
125 hg qrecord [OPTION]... PATCH [FILE]...
125
126
126 interactively record a new patch
127 interactively record a new patch
127
128
128 See "hg help qnew" & "hg help record" for more information and usage.
129 See "hg help qnew" & "hg help record" for more information and usage.
129
130
130 options:
131 options:
131
132
132 -e --edit edit commit message
133 -e --edit edit commit message
133 -g --git use git extended diff format
134 -g --git use git extended diff format
134 -U --currentuser add "From: <current user>" to patch
135 -U --currentuser add "From: <current user>" to patch
135 -u --user USER add "From: <USER>" to patch
136 -u --user USER add "From: <USER>" to patch
136 -D --currentdate add "Date: <current date>" to patch
137 -D --currentdate add "Date: <current date>" to patch
137 -d --date DATE add "Date: <DATE>" to patch
138 -d --date DATE add "Date: <DATE>" to patch
138 -I --include PATTERN [+] include names matching the given patterns
139 -I --include PATTERN [+] include names matching the given patterns
139 -X --exclude PATTERN [+] exclude names matching the given patterns
140 -X --exclude PATTERN [+] exclude names matching the given patterns
140 -m --message TEXT use text as commit message
141 -m --message TEXT use text as commit message
141 -l --logfile FILE read commit message from file
142 -l --logfile FILE read commit message from file
142 -w --ignore-all-space ignore white space when comparing lines
143 -w --ignore-all-space ignore white space when comparing lines
143 -b --ignore-space-change ignore changes in the amount of white space
144 -b --ignore-space-change ignore changes in the amount of white space
144 -B --ignore-blank-lines ignore changes whose lines are all blank
145 -B --ignore-blank-lines ignore changes whose lines are all blank
145 --mq operate on patch repository
146 --mq operate on patch repository
146
147
147 [+] marked option can be specified multiple times
148 [+] marked option can be specified multiple times
148
149
149 use "hg -v help qrecord" to show more info
150 use "hg -v help qrecord" to show more info
150
151
151 $ cd a
152 $ cd a
152
153
153 Base commit
154 Base commit
154
155
155 $ cat > 1.txt <<EOF
156 $ cat > 1.txt <<EOF
156 > 1
157 > 1
157 > 2
158 > 2
158 > 3
159 > 3
159 > 4
160 > 4
160 > 5
161 > 5
161 > EOF
162 > EOF
162 $ cat > 2.txt <<EOF
163 $ cat > 2.txt <<EOF
163 > a
164 > a
164 > b
165 > b
165 > c
166 > c
166 > d
167 > d
167 > e
168 > e
168 > f
169 > f
169 > EOF
170 > EOF
170
171
171 $ mkdir dir
172 $ mkdir dir
172 $ cat > dir/a.txt <<EOF
173 $ cat > dir/a.txt <<EOF
173 > hello world
174 > hello world
174 >
175 >
175 > someone
176 > someone
176 > up
177 > up
177 > there
178 > there
178 > loves
179 > loves
179 > me
180 > me
180 > EOF
181 > EOF
181
182
182 $ hg add 1.txt 2.txt dir/a.txt
183 $ hg add 1.txt 2.txt dir/a.txt
183 $ hg commit -m 'initial checkin'
184 $ hg commit -m 'initial checkin'
184
185
185 Changing files
186 Changing files
186
187
187 $ sed -e 's/2/2 2/;s/4/4 4/' 1.txt > 1.txt.new
188 $ sed -e 's/2/2 2/;s/4/4 4/' 1.txt > 1.txt.new
188 $ sed -e 's/b/b b/' 2.txt > 2.txt.new
189 $ sed -e 's/b/b b/' 2.txt > 2.txt.new
189 $ sed -e 's/hello world/hello world!/' dir/a.txt > dir/a.txt.new
190 $ sed -e 's/hello world/hello world!/' dir/a.txt > dir/a.txt.new
190
191
191 $ mv -f 1.txt.new 1.txt
192 $ mv -f 1.txt.new 1.txt
192 $ mv -f 2.txt.new 2.txt
193 $ mv -f 2.txt.new 2.txt
193 $ mv -f dir/a.txt.new dir/a.txt
194 $ mv -f dir/a.txt.new dir/a.txt
194
195
195 Whole diff
196 Whole diff
196
197
197 $ hg diff --nodates
198 $ hg diff --nodates
198 diff -r 1057167b20ef 1.txt
199 diff -r 1057167b20ef 1.txt
199 --- a/1.txt
200 --- a/1.txt
200 +++ b/1.txt
201 +++ b/1.txt
201 @@ -1,5 +1,5 @@
202 @@ -1,5 +1,5 @@
202 1
203 1
203 -2
204 -2
204 +2 2
205 +2 2
205 3
206 3
206 -4
207 -4
207 +4 4
208 +4 4
208 5
209 5
209 diff -r 1057167b20ef 2.txt
210 diff -r 1057167b20ef 2.txt
210 --- a/2.txt
211 --- a/2.txt
211 +++ b/2.txt
212 +++ b/2.txt
212 @@ -1,5 +1,5 @@
213 @@ -1,5 +1,5 @@
213 a
214 a
214 -b
215 -b
215 +b b
216 +b b
216 c
217 c
217 d
218 d
218 e
219 e
219 diff -r 1057167b20ef dir/a.txt
220 diff -r 1057167b20ef dir/a.txt
220 --- a/dir/a.txt
221 --- a/dir/a.txt
221 +++ b/dir/a.txt
222 +++ b/dir/a.txt
222 @@ -1,4 +1,4 @@
223 @@ -1,4 +1,4 @@
223 -hello world
224 -hello world
224 +hello world!
225 +hello world!
225
226
226 someone
227 someone
227 up
228 up
228
229
229 qrecord with bad patch name, should abort before prompting
230 qrecord with bad patch name, should abort before prompting
230
231
231 $ hg qrecord .hg
232 $ hg qrecord .hg
232 abort: patch name cannot begin with ".hg"
233 abort: patch name cannot begin with ".hg"
233 [255]
234 [255]
234
235
235 qrecord a.patch
236 qrecord a.patch
236
237
237 $ hg qrecord -d '0 0' -m aaa a.patch <<EOF
238 $ hg qrecord -d '0 0' -m aaa a.patch <<EOF
238 > y
239 > y
239 > y
240 > y
240 > n
241 > n
241 > y
242 > y
242 > y
243 > y
243 > n
244 > n
244 > EOF
245 > EOF
245 diff --git a/1.txt b/1.txt
246 diff --git a/1.txt b/1.txt
246 2 hunks, 2 lines changed
247 2 hunks, 2 lines changed
247 examine changes to '1.txt'? [Ynsfdaq?]
248 examine changes to '1.txt'? [Ynsfdaq?]
248 @@ -1,3 +1,3 @@
249 @@ -1,3 +1,3 @@
249 1
250 1
250 -2
251 -2
251 +2 2
252 +2 2
252 3
253 3
253 record change 1/4 to '1.txt'? [Ynsfdaq?]
254 record change 1/4 to '1.txt'? [Ynsfdaq?]
254 @@ -3,3 +3,3 @@
255 @@ -3,3 +3,3 @@
255 3
256 3
256 -4
257 -4
257 +4 4
258 +4 4
258 5
259 5
259 record change 2/4 to '1.txt'? [Ynsfdaq?]
260 record change 2/4 to '1.txt'? [Ynsfdaq?]
260 diff --git a/2.txt b/2.txt
261 diff --git a/2.txt b/2.txt
261 1 hunks, 1 lines changed
262 1 hunks, 1 lines changed
262 examine changes to '2.txt'? [Ynsfdaq?]
263 examine changes to '2.txt'? [Ynsfdaq?]
263 @@ -1,5 +1,5 @@
264 @@ -1,5 +1,5 @@
264 a
265 a
265 -b
266 -b
266 +b b
267 +b b
267 c
268 c
268 d
269 d
269 e
270 e
270 record change 3/4 to '2.txt'? [Ynsfdaq?]
271 record change 3/4 to '2.txt'? [Ynsfdaq?]
271 diff --git a/dir/a.txt b/dir/a.txt
272 diff --git a/dir/a.txt b/dir/a.txt
272 1 hunks, 1 lines changed
273 1 hunks, 1 lines changed
273 examine changes to 'dir/a.txt'? [Ynsfdaq?]
274 examine changes to 'dir/a.txt'? [Ynsfdaq?]
274
275
275 After qrecord a.patch 'tip'"
276 After qrecord a.patch 'tip'"
276
277
277 $ hg tip -p
278 $ hg tip -p
278 changeset: 1:5d1ca63427ee
279 changeset: 1:5d1ca63427ee
279 tag: a.patch
280 tag: a.patch
280 tag: qbase
281 tag: qbase
281 tag: qtip
282 tag: qtip
282 tag: tip
283 tag: tip
283 user: test
284 user: test
284 date: Thu Jan 01 00:00:00 1970 +0000
285 date: Thu Jan 01 00:00:00 1970 +0000
285 summary: aaa
286 summary: aaa
286
287
287 diff -r 1057167b20ef -r 5d1ca63427ee 1.txt
288 diff -r 1057167b20ef -r 5d1ca63427ee 1.txt
288 --- a/1.txt Thu Jan 01 00:00:00 1970 +0000
289 --- a/1.txt Thu Jan 01 00:00:00 1970 +0000
289 +++ b/1.txt Thu Jan 01 00:00:00 1970 +0000
290 +++ b/1.txt Thu Jan 01 00:00:00 1970 +0000
290 @@ -1,5 +1,5 @@
291 @@ -1,5 +1,5 @@
291 1
292 1
292 -2
293 -2
293 +2 2
294 +2 2
294 3
295 3
295 4
296 4
296 5
297 5
297 diff -r 1057167b20ef -r 5d1ca63427ee 2.txt
298 diff -r 1057167b20ef -r 5d1ca63427ee 2.txt
298 --- a/2.txt Thu Jan 01 00:00:00 1970 +0000
299 --- a/2.txt Thu Jan 01 00:00:00 1970 +0000
299 +++ b/2.txt Thu Jan 01 00:00:00 1970 +0000
300 +++ b/2.txt Thu Jan 01 00:00:00 1970 +0000
300 @@ -1,5 +1,5 @@
301 @@ -1,5 +1,5 @@
301 a
302 a
302 -b
303 -b
303 +b b
304 +b b
304 c
305 c
305 d
306 d
306 e
307 e
307
308
308
309
309 After qrecord a.patch 'diff'"
310 After qrecord a.patch 'diff'"
310
311
311 $ hg diff --nodates
312 $ hg diff --nodates
312 diff -r 5d1ca63427ee 1.txt
313 diff -r 5d1ca63427ee 1.txt
313 --- a/1.txt
314 --- a/1.txt
314 +++ b/1.txt
315 +++ b/1.txt
315 @@ -1,5 +1,5 @@
316 @@ -1,5 +1,5 @@
316 1
317 1
317 2 2
318 2 2
318 3
319 3
319 -4
320 -4
320 +4 4
321 +4 4
321 5
322 5
322 diff -r 5d1ca63427ee dir/a.txt
323 diff -r 5d1ca63427ee dir/a.txt
323 --- a/dir/a.txt
324 --- a/dir/a.txt
324 +++ b/dir/a.txt
325 +++ b/dir/a.txt
325 @@ -1,4 +1,4 @@
326 @@ -1,4 +1,4 @@
326 -hello world
327 -hello world
327 +hello world!
328 +hello world!
328
329
329 someone
330 someone
330 up
331 up
331
332
332 qrecord b.patch
333 qrecord b.patch
333
334
334 $ hg qrecord -d '0 0' -m bbb b.patch <<EOF
335 $ hg qrecord -d '0 0' -m bbb b.patch <<EOF
335 > y
336 > y
336 > y
337 > y
337 > y
338 > y
338 > y
339 > y
339 > EOF
340 > EOF
340 diff --git a/1.txt b/1.txt
341 diff --git a/1.txt b/1.txt
341 1 hunks, 1 lines changed
342 1 hunks, 1 lines changed
342 examine changes to '1.txt'? [Ynsfdaq?]
343 examine changes to '1.txt'? [Ynsfdaq?]
343 @@ -1,5 +1,5 @@
344 @@ -1,5 +1,5 @@
344 1
345 1
345 2 2
346 2 2
346 3
347 3
347 -4
348 -4
348 +4 4
349 +4 4
349 5
350 5
350 record change 1/2 to '1.txt'? [Ynsfdaq?]
351 record change 1/2 to '1.txt'? [Ynsfdaq?]
351 diff --git a/dir/a.txt b/dir/a.txt
352 diff --git a/dir/a.txt b/dir/a.txt
352 1 hunks, 1 lines changed
353 1 hunks, 1 lines changed
353 examine changes to 'dir/a.txt'? [Ynsfdaq?]
354 examine changes to 'dir/a.txt'? [Ynsfdaq?]
354 @@ -1,4 +1,4 @@
355 @@ -1,4 +1,4 @@
355 -hello world
356 -hello world
356 +hello world!
357 +hello world!
357
358
358 someone
359 someone
359 up
360 up
360 record change 2/2 to 'dir/a.txt'? [Ynsfdaq?]
361 record change 2/2 to 'dir/a.txt'? [Ynsfdaq?]
361
362
362 After qrecord b.patch 'tip'
363 After qrecord b.patch 'tip'
363
364
364 $ hg tip -p
365 $ hg tip -p
365 changeset: 2:b056198bf878
366 changeset: 2:b056198bf878
366 tag: b.patch
367 tag: b.patch
367 tag: qtip
368 tag: qtip
368 tag: tip
369 tag: tip
369 user: test
370 user: test
370 date: Thu Jan 01 00:00:00 1970 +0000
371 date: Thu Jan 01 00:00:00 1970 +0000
371 summary: bbb
372 summary: bbb
372
373
373 diff -r 5d1ca63427ee -r b056198bf878 1.txt
374 diff -r 5d1ca63427ee -r b056198bf878 1.txt
374 --- a/1.txt Thu Jan 01 00:00:00 1970 +0000
375 --- a/1.txt Thu Jan 01 00:00:00 1970 +0000
375 +++ b/1.txt Thu Jan 01 00:00:00 1970 +0000
376 +++ b/1.txt Thu Jan 01 00:00:00 1970 +0000
376 @@ -1,5 +1,5 @@
377 @@ -1,5 +1,5 @@
377 1
378 1
378 2 2
379 2 2
379 3
380 3
380 -4
381 -4
381 +4 4
382 +4 4
382 5
383 5
383 diff -r 5d1ca63427ee -r b056198bf878 dir/a.txt
384 diff -r 5d1ca63427ee -r b056198bf878 dir/a.txt
384 --- a/dir/a.txt Thu Jan 01 00:00:00 1970 +0000
385 --- a/dir/a.txt Thu Jan 01 00:00:00 1970 +0000
385 +++ b/dir/a.txt Thu Jan 01 00:00:00 1970 +0000
386 +++ b/dir/a.txt Thu Jan 01 00:00:00 1970 +0000
386 @@ -1,4 +1,4 @@
387 @@ -1,4 +1,4 @@
387 -hello world
388 -hello world
388 +hello world!
389 +hello world!
389
390
390 someone
391 someone
391 up
392 up
392
393
393
394
394 After qrecord b.patch 'diff'
395 After qrecord b.patch 'diff'
395
396
396 $ hg diff --nodates
397 $ hg diff --nodates
@@ -1,102 +1,102 b''
1 Preparing the subrepository 'sub2'
1 Preparing the subrepository 'sub2'
2
2
3 $ hg init sub2
3 $ hg init sub2
4 $ echo sub2 > sub2/sub2
4 $ echo sub2 > sub2/sub2
5 $ hg add -R sub2
5 $ hg add -R sub2
6 adding sub2/sub2
6 adding sub2/sub2
7 $ hg commit -R sub2 -m "sub2 import"
7 $ hg commit -R sub2 -m "sub2 import"
8
8
9 Preparing the 'sub1' repo which depends on the subrepo 'sub2'
9 Preparing the 'sub1' repo which depends on the subrepo 'sub2'
10
10
11 $ hg init sub1
11 $ hg init sub1
12 $ echo sub1 > sub1/sub1
12 $ echo sub1 > sub1/sub1
13 $ echo "sub2 = ../sub2" > sub1/.hgsub
13 $ echo "sub2 = ../sub2" > sub1/.hgsub
14 $ hg clone sub2 sub1/sub2
14 $ hg clone sub2 sub1/sub2
15 updating to branch default
15 updating to branch default
16 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
16 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
17 $ hg add -R sub1
17 $ hg add -R sub1
18 adding sub1/.hgsub
18 adding sub1/.hgsub
19 adding sub1/sub1
19 adding sub1/sub1
20 $ hg commit -R sub1 -m "sub1 import"
20 $ hg commit -R sub1 -m "sub1 import"
21 committing subrepository sub2
21 committing subrepository sub2
22
22
23 Preparing the 'main' repo which depends on the subrepo 'sub1'
23 Preparing the 'main' repo which depends on the subrepo 'sub1'
24
24
25 $ hg init main
25 $ hg init main
26 $ echo main > main/main
26 $ echo main > main/main
27 $ echo "sub1 = ../sub1" > main/.hgsub
27 $ echo "sub1 = ../sub1" > main/.hgsub
28 $ hg clone sub1 main/sub1
28 $ hg clone sub1 main/sub1
29 updating to branch default
29 updating to branch default
30 cloning subrepo sub2 from $TESTTMP/sub2
30 cloning subrepo sub2 from $TESTTMP/sub2
31 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
31 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
32 $ hg add -R main
32 $ hg add -R main
33 adding main/.hgsub
33 adding main/.hgsub
34 adding main/main
34 adding main/main
35 $ hg commit -R main -m "main import"
35 $ hg commit -R main -m "main import"
36 committing subrepository sub1
36 committing subrepository sub1
37
37
38 Cleaning both repositories, just as a clone -U
38 Cleaning both repositories, just as a clone -U
39
39
40 $ hg up -C -R sub2 null
40 $ hg up -C -R sub2 null
41 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
41 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
42 $ hg up -C -R sub1 null
42 $ hg up -C -R sub1 null
43 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
43 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
44 $ hg up -C -R main null
44 $ hg up -C -R main null
45 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
45 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
46 $ rm -rf main/sub1
46 $ rm -rf main/sub1
47 $ rm -rf sub1/sub2
47 $ rm -rf sub1/sub2
48
48
49 Clone main
49 Clone main
50
50
51 $ hg clone main cloned
51 $ hg clone main cloned
52 updating to branch default
52 updating to branch default
53 cloning subrepo sub1 from $TESTTMP/sub1
53 cloning subrepo sub1 from $TESTTMP/sub1
54 cloning subrepo sub1/sub2 from $TESTTMP/sub2
54 cloning subrepo sub1/sub2 from $TESTTMP/sub2
55 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
55 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
56
56
57 Checking cloned repo ids
57 Checking cloned repo ids
58
58
59 $ printf "cloned " ; hg id -R cloned
59 $ printf "cloned " ; hg id -R cloned
60 cloned 7f491f53a367 tip
60 cloned 7f491f53a367 tip
61 $ printf "cloned/sub1 " ; hg id -R cloned/sub1
61 $ printf "cloned/sub1 " ; hg id -R cloned/sub1
62 cloned/sub1 fc3b4ce2696f tip
62 cloned/sub1 fc3b4ce2696f tip
63 $ printf "cloned/sub1/sub2 " ; hg id -R cloned/sub1/sub2
63 $ printf "cloned/sub1/sub2 " ; hg id -R cloned/sub1/sub2
64 cloned/sub1/sub2 c57a0840e3ba tip
64 cloned/sub1/sub2 c57a0840e3ba tip
65
65
66 debugsub output for main and sub1
66 debugsub output for main and sub1
67
67
68 $ hg debugsub -R cloned
68 $ hg debugsub -R cloned
69 path sub1
69 path sub1
70 source ../sub1
70 source ../sub1
71 revision fc3b4ce2696f7741438c79207583768f2ce6b0dd
71 revision fc3b4ce2696f7741438c79207583768f2ce6b0dd
72 $ hg debugsub -R cloned/sub1
72 $ hg debugsub -R cloned/sub1
73 path sub2
73 path sub2
74 source ../sub2
74 source ../sub2
75 revision c57a0840e3badd667ef3c3ef65471609acb2ba3c
75 revision c57a0840e3badd667ef3c3ef65471609acb2ba3c
76
76
77 Modifying deeply nested 'sub2'
77 Modifying deeply nested 'sub2'
78
78
79 $ echo modified > cloned/sub1/sub2/sub2
79 $ echo modified > cloned/sub1/sub2/sub2
80 $ hg commit -m "deep nested modif should trigger a commit" -R cloned
80 $ hg commit --subrepos -m "deep nested modif should trigger a commit" -R cloned
81 committing subrepository sub1
81 committing subrepository sub1
82 committing subrepository sub1/sub2
82 committing subrepository sub1/sub2
83
83
84 Checking modified node ids
84 Checking modified node ids
85
85
86 $ printf "cloned " ; hg id -R cloned
86 $ printf "cloned " ; hg id -R cloned
87 cloned ffe6649062fe tip
87 cloned ffe6649062fe tip
88 $ printf "cloned/sub1 " ; hg id -R cloned/sub1
88 $ printf "cloned/sub1 " ; hg id -R cloned/sub1
89 cloned/sub1 2ecb03bf44a9 tip
89 cloned/sub1 2ecb03bf44a9 tip
90 $ printf "cloned/sub1/sub2 " ; hg id -R cloned/sub1/sub2
90 $ printf "cloned/sub1/sub2 " ; hg id -R cloned/sub1/sub2
91 cloned/sub1/sub2 53dd3430bcaf tip
91 cloned/sub1/sub2 53dd3430bcaf tip
92
92
93 debugsub output for main and sub1
93 debugsub output for main and sub1
94
94
95 $ hg debugsub -R cloned
95 $ hg debugsub -R cloned
96 path sub1
96 path sub1
97 source ../sub1
97 source ../sub1
98 revision 2ecb03bf44a94e749e8669481dd9069526ce7cb9
98 revision 2ecb03bf44a94e749e8669481dd9069526ce7cb9
99 $ hg debugsub -R cloned/sub1
99 $ hg debugsub -R cloned/sub1
100 path sub2
100 path sub2
101 source ../sub2
101 source ../sub2
102 revision 53dd3430bcaf5ab4a7c48262bcad6d441f510487
102 revision 53dd3430bcaf5ab4a7c48262bcad6d441f510487
@@ -1,501 +1,501 b''
1 $ "$TESTDIR/hghave" git || exit 80
1 $ "$TESTDIR/hghave" git || exit 80
2
2
3 make git commits repeatable
3 make git commits repeatable
4
4
5 $ GIT_AUTHOR_NAME='test'; export GIT_AUTHOR_NAME
5 $ GIT_AUTHOR_NAME='test'; export GIT_AUTHOR_NAME
6 $ GIT_AUTHOR_EMAIL='test@example.org'; export GIT_AUTHOR_EMAIL
6 $ GIT_AUTHOR_EMAIL='test@example.org'; export GIT_AUTHOR_EMAIL
7 $ GIT_AUTHOR_DATE='1234567891 +0000'; export GIT_AUTHOR_DATE
7 $ GIT_AUTHOR_DATE='1234567891 +0000'; export GIT_AUTHOR_DATE
8 $ GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME"; export GIT_COMMITTER_NAME
8 $ GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME"; export GIT_COMMITTER_NAME
9 $ GIT_COMMITTER_EMAIL="$GIT_AUTHOR_EMAIL"; export GIT_COMMITTER_EMAIL
9 $ GIT_COMMITTER_EMAIL="$GIT_AUTHOR_EMAIL"; export GIT_COMMITTER_EMAIL
10 $ GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"; export GIT_COMMITTER_DATE
10 $ GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"; export GIT_COMMITTER_DATE
11
11
12 root hg repo
12 root hg repo
13
13
14 $ hg init t
14 $ hg init t
15 $ cd t
15 $ cd t
16 $ echo a > a
16 $ echo a > a
17 $ hg add a
17 $ hg add a
18 $ hg commit -m a
18 $ hg commit -m a
19 $ cd ..
19 $ cd ..
20
20
21 new external git repo
21 new external git repo
22
22
23 $ mkdir gitroot
23 $ mkdir gitroot
24 $ cd gitroot
24 $ cd gitroot
25 $ git init -q
25 $ git init -q
26 $ echo g > g
26 $ echo g > g
27 $ git add g
27 $ git add g
28 $ git commit -q -m g
28 $ git commit -q -m g
29
29
30 add subrepo clone
30 add subrepo clone
31
31
32 $ cd ../t
32 $ cd ../t
33 $ echo 's = [git]../gitroot' > .hgsub
33 $ echo 's = [git]../gitroot' > .hgsub
34 $ git clone -q ../gitroot s
34 $ git clone -q ../gitroot s
35 $ hg add .hgsub
35 $ hg add .hgsub
36 $ hg commit -m 'new git subrepo'
36 $ hg commit -m 'new git subrepo'
37 committing subrepository s
37 committing subrepository s
38 $ hg debugsub
38 $ hg debugsub
39 path s
39 path s
40 source ../gitroot
40 source ../gitroot
41 revision da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
41 revision da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
42
42
43 record a new commit from upstream from a different branch
43 record a new commit from upstream from a different branch
44
44
45 $ cd ../gitroot
45 $ cd ../gitroot
46 $ git checkout -q -b testing
46 $ git checkout -q -b testing
47 $ echo gg >> g
47 $ echo gg >> g
48 $ git commit -q -a -m gg
48 $ git commit -q -a -m gg
49
49
50 $ cd ../t/s
50 $ cd ../t/s
51 $ git pull -q >/dev/null 2>/dev/null
51 $ git pull -q >/dev/null 2>/dev/null
52 $ git checkout -q -b testing origin/testing >/dev/null
52 $ git checkout -q -b testing origin/testing >/dev/null
53
53
54 $ cd ..
54 $ cd ..
55 $ hg status --subrepos
55 $ hg status --subrepos
56 M s/g
56 M s/g
57 $ hg commit -m 'update git subrepo'
57 $ hg commit -m 'update git subrepo'
58 committing subrepository s
58 committing subrepository s
59 $ hg debugsub
59 $ hg debugsub
60 path s
60 path s
61 source ../gitroot
61 source ../gitroot
62 revision 126f2a14290cd5ce061fdedc430170e8d39e1c5a
62 revision 126f2a14290cd5ce061fdedc430170e8d39e1c5a
63
63
64 make $GITROOT pushable, by replacing it with a clone with nothing checked out
64 make $GITROOT pushable, by replacing it with a clone with nothing checked out
65
65
66 $ cd ..
66 $ cd ..
67 $ git clone gitroot gitrootbare --bare -q
67 $ git clone gitroot gitrootbare --bare -q
68 $ rm -rf gitroot
68 $ rm -rf gitroot
69 $ mv gitrootbare gitroot
69 $ mv gitrootbare gitroot
70
70
71 clone root
71 clone root
72
72
73 $ cd t
73 $ cd t
74 $ hg clone . ../tc
74 $ hg clone . ../tc
75 updating to branch default
75 updating to branch default
76 cloning subrepo s from $TESTTMP/gitroot
76 cloning subrepo s from $TESTTMP/gitroot
77 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
77 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
78 $ cd ../tc
78 $ cd ../tc
79 $ hg debugsub
79 $ hg debugsub
80 path s
80 path s
81 source ../gitroot
81 source ../gitroot
82 revision 126f2a14290cd5ce061fdedc430170e8d39e1c5a
82 revision 126f2a14290cd5ce061fdedc430170e8d39e1c5a
83
83
84 update to previous substate
84 update to previous substate
85
85
86 $ hg update 1 -q
86 $ hg update 1 -q
87 $ cat s/g
87 $ cat s/g
88 g
88 g
89 $ hg debugsub
89 $ hg debugsub
90 path s
90 path s
91 source ../gitroot
91 source ../gitroot
92 revision da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
92 revision da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
93
93
94 clone root, make local change
94 clone root, make local change
95
95
96 $ cd ../t
96 $ cd ../t
97 $ hg clone . ../ta
97 $ hg clone . ../ta
98 updating to branch default
98 updating to branch default
99 cloning subrepo s from $TESTTMP/gitroot
99 cloning subrepo s from $TESTTMP/gitroot
100 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
100 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
101
101
102 $ cd ../ta
102 $ cd ../ta
103 $ echo ggg >> s/g
103 $ echo ggg >> s/g
104 $ hg status --subrepos
104 $ hg status --subrepos
105 M s/g
105 M s/g
106 $ hg commit -m ggg
106 $ hg commit --subrepos -m ggg
107 committing subrepository s
107 committing subrepository s
108 $ hg debugsub
108 $ hg debugsub
109 path s
109 path s
110 source ../gitroot
110 source ../gitroot
111 revision 79695940086840c99328513acbe35f90fcd55e57
111 revision 79695940086840c99328513acbe35f90fcd55e57
112
112
113 clone root separately, make different local change
113 clone root separately, make different local change
114
114
115 $ cd ../t
115 $ cd ../t
116 $ hg clone . ../tb
116 $ hg clone . ../tb
117 updating to branch default
117 updating to branch default
118 cloning subrepo s from $TESTTMP/gitroot
118 cloning subrepo s from $TESTTMP/gitroot
119 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
119 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
120
120
121 $ cd ../tb/s
121 $ cd ../tb/s
122 $ echo f > f
122 $ echo f > f
123 $ git add f
123 $ git add f
124 $ cd ..
124 $ cd ..
125
125
126 $ hg status --subrepos
126 $ hg status --subrepos
127 A s/f
127 A s/f
128 $ hg commit -m f
128 $ hg commit --subrepos -m f
129 committing subrepository s
129 committing subrepository s
130 $ hg debugsub
130 $ hg debugsub
131 path s
131 path s
132 source ../gitroot
132 source ../gitroot
133 revision aa84837ccfbdfedcdcdeeedc309d73e6eb069edc
133 revision aa84837ccfbdfedcdcdeeedc309d73e6eb069edc
134
134
135 user b push changes
135 user b push changes
136
136
137 $ hg push 2>/dev/null
137 $ hg push 2>/dev/null
138 pushing to $TESTTMP/t
138 pushing to $TESTTMP/t
139 pushing branch testing of subrepo s
139 pushing branch testing of subrepo s
140 searching for changes
140 searching for changes
141 adding changesets
141 adding changesets
142 adding manifests
142 adding manifests
143 adding file changes
143 adding file changes
144 added 1 changesets with 1 changes to 1 files
144 added 1 changesets with 1 changes to 1 files
145
145
146 user a pulls, merges, commits
146 user a pulls, merges, commits
147
147
148 $ cd ../ta
148 $ cd ../ta
149 $ hg pull
149 $ hg pull
150 pulling from $TESTTMP/t
150 pulling from $TESTTMP/t
151 searching for changes
151 searching for changes
152 adding changesets
152 adding changesets
153 adding manifests
153 adding manifests
154 adding file changes
154 adding file changes
155 added 1 changesets with 1 changes to 1 files (+1 heads)
155 added 1 changesets with 1 changes to 1 files (+1 heads)
156 (run 'hg heads' to see heads, 'hg merge' to merge)
156 (run 'hg heads' to see heads, 'hg merge' to merge)
157 $ hg merge 2>/dev/null
157 $ hg merge 2>/dev/null
158 pulling subrepo s from $TESTTMP/gitroot
158 pulling subrepo s from $TESTTMP/gitroot
159 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
159 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
160 (branch merge, don't forget to commit)
160 (branch merge, don't forget to commit)
161 $ cat s/f
161 $ cat s/f
162 f
162 f
163 $ cat s/g
163 $ cat s/g
164 g
164 g
165 gg
165 gg
166 ggg
166 ggg
167 $ hg commit -m 'merge'
167 $ hg commit --subrepos -m 'merge'
168 committing subrepository s
168 committing subrepository s
169 $ hg status --subrepos --rev 1:5
169 $ hg status --subrepos --rev 1:5
170 M .hgsubstate
170 M .hgsubstate
171 M s/g
171 M s/g
172 A s/f
172 A s/f
173 $ hg debugsub
173 $ hg debugsub
174 path s
174 path s
175 source ../gitroot
175 source ../gitroot
176 revision f47b465e1bce645dbf37232a00574aa1546ca8d3
176 revision f47b465e1bce645dbf37232a00574aa1546ca8d3
177 $ hg push 2>/dev/null
177 $ hg push 2>/dev/null
178 pushing to $TESTTMP/t
178 pushing to $TESTTMP/t
179 pushing branch testing of subrepo s
179 pushing branch testing of subrepo s
180 searching for changes
180 searching for changes
181 adding changesets
181 adding changesets
182 adding manifests
182 adding manifests
183 adding file changes
183 adding file changes
184 added 2 changesets with 2 changes to 1 files
184 added 2 changesets with 2 changes to 1 files
185
185
186 make upstream git changes
186 make upstream git changes
187
187
188 $ cd ..
188 $ cd ..
189 $ git clone -q gitroot gitclone
189 $ git clone -q gitroot gitclone
190 $ cd gitclone
190 $ cd gitclone
191 $ echo ff >> f
191 $ echo ff >> f
192 $ git commit -q -a -m ff
192 $ git commit -q -a -m ff
193 $ echo fff >> f
193 $ echo fff >> f
194 $ git commit -q -a -m fff
194 $ git commit -q -a -m fff
195 $ git push origin testing 2>/dev/null
195 $ git push origin testing 2>/dev/null
196
196
197 make and push changes to hg without updating the subrepo
197 make and push changes to hg without updating the subrepo
198
198
199 $ cd ../t
199 $ cd ../t
200 $ hg clone . ../td
200 $ hg clone . ../td
201 updating to branch default
201 updating to branch default
202 cloning subrepo s from $TESTTMP/gitroot
202 cloning subrepo s from $TESTTMP/gitroot
203 checking out detached HEAD in subrepo s
203 checking out detached HEAD in subrepo s
204 check out a git branch if you intend to make changes
204 check out a git branch if you intend to make changes
205 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
205 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
206 $ cd ../td
206 $ cd ../td
207 $ echo aa >> a
207 $ echo aa >> a
208 $ hg commit -m aa
208 $ hg commit -m aa
209 $ hg push
209 $ hg push
210 pushing to $TESTTMP/t
210 pushing to $TESTTMP/t
211 searching for changes
211 searching for changes
212 adding changesets
212 adding changesets
213 adding manifests
213 adding manifests
214 adding file changes
214 adding file changes
215 added 1 changesets with 1 changes to 1 files
215 added 1 changesets with 1 changes to 1 files
216
216
217 sync to upstream git, distribute changes
217 sync to upstream git, distribute changes
218
218
219 $ cd ../ta
219 $ cd ../ta
220 $ hg pull -u -q
220 $ hg pull -u -q
221 $ cd s
221 $ cd s
222 $ git pull -q >/dev/null 2>/dev/null
222 $ git pull -q >/dev/null 2>/dev/null
223 $ cd ..
223 $ cd ..
224 $ hg commit -m 'git upstream sync'
224 $ hg commit -m 'git upstream sync'
225 committing subrepository s
225 committing subrepository s
226 $ hg debugsub
226 $ hg debugsub
227 path s
227 path s
228 source ../gitroot
228 source ../gitroot
229 revision 32a343883b74769118bb1d3b4b1fbf9156f4dddc
229 revision 32a343883b74769118bb1d3b4b1fbf9156f4dddc
230 $ hg push -q
230 $ hg push -q
231
231
232 $ cd ../tb
232 $ cd ../tb
233 $ hg pull -q
233 $ hg pull -q
234 $ hg update 2>/dev/null
234 $ hg update 2>/dev/null
235 pulling subrepo s from $TESTTMP/gitroot
235 pulling subrepo s from $TESTTMP/gitroot
236 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
236 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
237 $ hg debugsub
237 $ hg debugsub
238 path s
238 path s
239 source ../gitroot
239 source ../gitroot
240 revision 32a343883b74769118bb1d3b4b1fbf9156f4dddc
240 revision 32a343883b74769118bb1d3b4b1fbf9156f4dddc
241
241
242 update to a revision without the subrepo, keeping the local git repository
242 update to a revision without the subrepo, keeping the local git repository
243
243
244 $ cd ../t
244 $ cd ../t
245 $ hg up 0
245 $ hg up 0
246 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
246 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
247 $ ls -a s
247 $ ls -a s
248 .
248 .
249 ..
249 ..
250 .git
250 .git
251
251
252 $ hg up 2
252 $ hg up 2
253 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
253 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
254 $ ls -a s
254 $ ls -a s
255 .
255 .
256 ..
256 ..
257 .git
257 .git
258 g
258 g
259
259
260 archive subrepos
260 archive subrepos
261
261
262 $ cd ../tc
262 $ cd ../tc
263 $ hg pull -q
263 $ hg pull -q
264 $ hg archive --subrepos -r 5 ../archive 2>/dev/null
264 $ hg archive --subrepos -r 5 ../archive 2>/dev/null
265 pulling subrepo s from $TESTTMP/gitroot
265 pulling subrepo s from $TESTTMP/gitroot
266 $ cd ../archive
266 $ cd ../archive
267 $ cat s/f
267 $ cat s/f
268 f
268 f
269 $ cat s/g
269 $ cat s/g
270 g
270 g
271 gg
271 gg
272 ggg
272 ggg
273
273
274 create nested repo
274 create nested repo
275
275
276 $ cd ..
276 $ cd ..
277 $ hg init outer
277 $ hg init outer
278 $ cd outer
278 $ cd outer
279 $ echo b>b
279 $ echo b>b
280 $ hg add b
280 $ hg add b
281 $ hg commit -m b
281 $ hg commit -m b
282
282
283 $ hg clone ../t inner
283 $ hg clone ../t inner
284 updating to branch default
284 updating to branch default
285 cloning subrepo s from $TESTTMP/gitroot
285 cloning subrepo s from $TESTTMP/gitroot
286 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
286 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
287 $ echo inner = inner > .hgsub
287 $ echo inner = inner > .hgsub
288 $ hg add .hgsub
288 $ hg add .hgsub
289 $ hg commit -m 'nested sub'
289 $ hg commit -m 'nested sub'
290 committing subrepository inner
290 committing subrepository inner
291
291
292 nested commit
292 nested commit
293
293
294 $ echo ffff >> inner/s/f
294 $ echo ffff >> inner/s/f
295 $ hg status --subrepos
295 $ hg status --subrepos
296 M inner/s/f
296 M inner/s/f
297 $ hg commit -m nested
297 $ hg commit --subrepos -m nested
298 committing subrepository inner
298 committing subrepository inner
299 committing subrepository inner/s
299 committing subrepository inner/s
300
300
301 nested archive
301 nested archive
302
302
303 $ hg archive --subrepos ../narchive
303 $ hg archive --subrepos ../narchive
304 $ ls ../narchive/inner/s | grep -v pax_global_header
304 $ ls ../narchive/inner/s | grep -v pax_global_header
305 f
305 f
306 g
306 g
307
307
308 relative source expansion
308 relative source expansion
309
309
310 $ cd ..
310 $ cd ..
311 $ mkdir d
311 $ mkdir d
312 $ hg clone t d/t
312 $ hg clone t d/t
313 updating to branch default
313 updating to branch default
314 cloning subrepo s from $TESTTMP/gitroot
314 cloning subrepo s from $TESTTMP/gitroot
315 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
315 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
316
316
317 Don't crash if the subrepo is missing
317 Don't crash if the subrepo is missing
318
318
319 $ hg clone t missing -q
319 $ hg clone t missing -q
320 $ cd missing
320 $ cd missing
321 $ rm -rf s
321 $ rm -rf s
322 $ hg status -S
322 $ hg status -S
323 $ hg sum | grep commit
323 $ hg sum | grep commit
324 commit: 1 subrepos
324 commit: 1 subrepos
325 $ hg push -q
325 $ hg push -q
326 abort: subrepo s is missing
326 abort: subrepo s is missing
327 [255]
327 [255]
328 $ hg commit -qm missing
328 $ hg commit --subrepos -qm missing
329 abort: subrepo s is missing
329 abort: subrepo s is missing
330 [255]
330 [255]
331 $ hg update -C
331 $ hg update -C
332 cloning subrepo s from $TESTTMP/gitroot
332 cloning subrepo s from $TESTTMP/gitroot
333 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
333 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
334 $ hg sum | grep commit
334 $ hg sum | grep commit
335 commit: (clean)
335 commit: (clean)
336
336
337 Don't crash if the .hgsubstate entry is missing
337 Don't crash if the .hgsubstate entry is missing
338
338
339 $ hg update 1 -q
339 $ hg update 1 -q
340 $ hg rm .hgsubstate
340 $ hg rm .hgsubstate
341 $ hg commit .hgsubstate -m 'no substate'
341 $ hg commit .hgsubstate -m 'no substate'
342 created new head
342 created new head
343 $ hg tag -l nosubstate
343 $ hg tag -l nosubstate
344 $ hg manifest
344 $ hg manifest
345 .hgsub
345 .hgsub
346 a
346 a
347
347
348 $ hg status -S
348 $ hg status -S
349 $ hg sum | grep commit
349 $ hg sum | grep commit
350 commit: 1 subrepos
350 commit: 1 subrepos
351
351
352 $ hg commit -m 'restore substate'
352 $ hg commit -m 'restore substate'
353 committing subrepository s
353 committing subrepository s
354 $ hg manifest
354 $ hg manifest
355 .hgsub
355 .hgsub
356 .hgsubstate
356 .hgsubstate
357 a
357 a
358 $ hg sum | grep commit
358 $ hg sum | grep commit
359 commit: (clean)
359 commit: (clean)
360
360
361 $ hg update -qC nosubstate
361 $ hg update -qC nosubstate
362 $ ls s
362 $ ls s
363
363
364 Check hg update --clean
364 Check hg update --clean
365 $ cd $TESTTMP/ta
365 $ cd $TESTTMP/ta
366 $ echo > s/g
366 $ echo > s/g
367 $ cd s
367 $ cd s
368 $ echo c1 > f1
368 $ echo c1 > f1
369 $ echo c1 > f2
369 $ echo c1 > f2
370 $ git add f1
370 $ git add f1
371 $ cd ..
371 $ cd ..
372 $ hg status -S
372 $ hg status -S
373 M s/g
373 M s/g
374 A s/f1
374 A s/f1
375 $ ls s
375 $ ls s
376 f
376 f
377 f1
377 f1
378 f2
378 f2
379 g
379 g
380 $ hg update --clean
380 $ hg update --clean
381 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
381 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
382 $ hg status -S
382 $ hg status -S
383 $ ls s
383 $ ls s
384 f
384 f
385 f1
385 f1
386 f2
386 f2
387 g
387 g
388
388
389 Sticky subrepositories, no changes
389 Sticky subrepositories, no changes
390 $ cd $TESTTMP/ta
390 $ cd $TESTTMP/ta
391 $ hg id -n
391 $ hg id -n
392 7
392 7
393 $ cd s
393 $ cd s
394 $ git rev-parse HEAD
394 $ git rev-parse HEAD
395 32a343883b74769118bb1d3b4b1fbf9156f4dddc
395 32a343883b74769118bb1d3b4b1fbf9156f4dddc
396 $ cd ..
396 $ cd ..
397 $ hg update 1 > /dev/null 2>&1
397 $ hg update 1 > /dev/null 2>&1
398 $ hg id -n
398 $ hg id -n
399 1
399 1
400 $ cd s
400 $ cd s
401 $ git rev-parse HEAD
401 $ git rev-parse HEAD
402 da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
402 da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
403 $ cd ..
403 $ cd ..
404
404
405 Sticky subrepositorys, file changes
405 Sticky subrepositorys, file changes
406 $ touch s/f1
406 $ touch s/f1
407 $ cd s
407 $ cd s
408 $ git add f1
408 $ git add f1
409 $ cd ..
409 $ cd ..
410 $ hg id -n
410 $ hg id -n
411 1
411 1
412 $ cd s
412 $ cd s
413 $ git rev-parse HEAD
413 $ git rev-parse HEAD
414 da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
414 da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
415 $ cd ..
415 $ cd ..
416 $ hg update 4
416 $ hg update 4
417 subrepository sources for s differ
417 subrepository sources for s differ
418 use (l)ocal source (da5f5b1) or (r)emote source (aa84837)?
418 use (l)ocal source (da5f5b1) or (r)emote source (aa84837)?
419 l
419 l
420 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
420 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
421 $ hg id -n
421 $ hg id -n
422 4+
422 4+
423 $ cd s
423 $ cd s
424 $ git rev-parse HEAD
424 $ git rev-parse HEAD
425 da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
425 da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
426 $ cd ..
426 $ cd ..
427 $ hg update --clean tip > /dev/null 2>&1
427 $ hg update --clean tip > /dev/null 2>&1
428
428
429 Sticky subrepository, revision updates
429 Sticky subrepository, revision updates
430 $ hg id -n
430 $ hg id -n
431 7
431 7
432 $ cd s
432 $ cd s
433 $ git rev-parse HEAD
433 $ git rev-parse HEAD
434 32a343883b74769118bb1d3b4b1fbf9156f4dddc
434 32a343883b74769118bb1d3b4b1fbf9156f4dddc
435 $ cd ..
435 $ cd ..
436 $ cd s
436 $ cd s
437 $ git checkout aa84837ccfbdfedcdcdeeedc309d73e6eb069edc
437 $ git checkout aa84837ccfbdfedcdcdeeedc309d73e6eb069edc
438 Previous HEAD position was 32a3438... fff
438 Previous HEAD position was 32a3438... fff
439 HEAD is now at aa84837... f
439 HEAD is now at aa84837... f
440 $ cd ..
440 $ cd ..
441 $ hg update 1
441 $ hg update 1
442 subrepository sources for s differ (in checked out version)
442 subrepository sources for s differ (in checked out version)
443 use (l)ocal source (32a3438) or (r)emote source (da5f5b1)?
443 use (l)ocal source (32a3438) or (r)emote source (da5f5b1)?
444 l
444 l
445 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
445 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
446 $ hg id -n
446 $ hg id -n
447 1+
447 1+
448 $ cd s
448 $ cd s
449 $ git rev-parse HEAD
449 $ git rev-parse HEAD
450 aa84837ccfbdfedcdcdeeedc309d73e6eb069edc
450 aa84837ccfbdfedcdcdeeedc309d73e6eb069edc
451 $ cd ..
451 $ cd ..
452
452
453 Sticky subrepository, file changes and revision updates
453 Sticky subrepository, file changes and revision updates
454 $ touch s/f1
454 $ touch s/f1
455 $ cd s
455 $ cd s
456 $ git add f1
456 $ git add f1
457 $ git rev-parse HEAD
457 $ git rev-parse HEAD
458 aa84837ccfbdfedcdcdeeedc309d73e6eb069edc
458 aa84837ccfbdfedcdcdeeedc309d73e6eb069edc
459 $ cd ..
459 $ cd ..
460 $ hg id -n
460 $ hg id -n
461 1+
461 1+
462 $ hg update 7
462 $ hg update 7
463 subrepository sources for s differ
463 subrepository sources for s differ
464 use (l)ocal source (32a3438) or (r)emote source (32a3438)?
464 use (l)ocal source (32a3438) or (r)emote source (32a3438)?
465 l
465 l
466 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
466 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
467 $ hg id -n
467 $ hg id -n
468 7
468 7
469 $ cd s
469 $ cd s
470 $ git rev-parse HEAD
470 $ git rev-parse HEAD
471 aa84837ccfbdfedcdcdeeedc309d73e6eb069edc
471 aa84837ccfbdfedcdcdeeedc309d73e6eb069edc
472 $ cd ..
472 $ cd ..
473
473
474 Sticky repository, update --clean
474 Sticky repository, update --clean
475 $ hg update --clean tip
475 $ hg update --clean tip
476 Previous HEAD position was aa84837... f
476 Previous HEAD position was aa84837... f
477 HEAD is now at 32a3438... fff
477 HEAD is now at 32a3438... fff
478 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
478 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
479 $ hg id -n
479 $ hg id -n
480 7
480 7
481 $ cd s
481 $ cd s
482 $ git rev-parse HEAD
482 $ git rev-parse HEAD
483 32a343883b74769118bb1d3b4b1fbf9156f4dddc
483 32a343883b74769118bb1d3b4b1fbf9156f4dddc
484 $ cd ..
484 $ cd ..
485
485
486 Test subrepo already at intended revision:
486 Test subrepo already at intended revision:
487 $ cd s
487 $ cd s
488 $ git checkout 32a343883b74769118bb1d3b4b1fbf9156f4dddc
488 $ git checkout 32a343883b74769118bb1d3b4b1fbf9156f4dddc
489 HEAD is now at 32a3438... fff
489 HEAD is now at 32a3438... fff
490 $ cd ..
490 $ cd ..
491 $ hg update 1
491 $ hg update 1
492 Previous HEAD position was 32a3438... fff
492 Previous HEAD position was 32a3438... fff
493 HEAD is now at da5f5b1... g
493 HEAD is now at da5f5b1... g
494 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
494 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
495 $ hg id -n
495 $ hg id -n
496 1
496 1
497 $ cd s
497 $ cd s
498 $ git rev-parse HEAD
498 $ git rev-parse HEAD
499 da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
499 da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
500 $ cd ..
500 $ cd ..
501
501
@@ -1,470 +1,477 b''
1 Create test repository:
1 Create test repository:
2
2
3 $ hg init repo
3 $ hg init repo
4 $ cd repo
4 $ cd repo
5 $ echo x1 > x.txt
5 $ echo x1 > x.txt
6
6
7 $ hg init foo
7 $ hg init foo
8 $ cd foo
8 $ cd foo
9 $ echo y1 > y.txt
9 $ echo y1 > y.txt
10
10
11 $ hg init bar
11 $ hg init bar
12 $ cd bar
12 $ cd bar
13 $ echo z1 > z.txt
13 $ echo z1 > z.txt
14
14
15 $ cd ..
15 $ cd ..
16 $ echo 'bar = bar' > .hgsub
16 $ echo 'bar = bar' > .hgsub
17
17
18 $ cd ..
18 $ cd ..
19 $ echo 'foo = foo' > .hgsub
19 $ echo 'foo = foo' > .hgsub
20
20
21 Add files --- .hgsub files must go first to trigger subrepos:
21 Add files --- .hgsub files must go first to trigger subrepos:
22
22
23 $ hg add -S .hgsub
23 $ hg add -S .hgsub
24 $ hg add -S foo/.hgsub
24 $ hg add -S foo/.hgsub
25 $ hg add -S foo/bar
25 $ hg add -S foo/bar
26 adding foo/bar/z.txt
26 adding foo/bar/z.txt
27 $ hg add -S
27 $ hg add -S
28 adding x.txt
28 adding x.txt
29 adding foo/y.txt
29 adding foo/y.txt
30
30
31 Test recursive status without committing anything:
31 Test recursive status without committing anything:
32
32
33 $ hg status -S
33 $ hg status -S
34 A .hgsub
34 A .hgsub
35 A foo/.hgsub
35 A foo/.hgsub
36 A foo/bar/z.txt
36 A foo/bar/z.txt
37 A foo/y.txt
37 A foo/y.txt
38 A x.txt
38 A x.txt
39
39
40 Test recursive diff without committing anything:
40 Test recursive diff without committing anything:
41
41
42 $ hg diff --nodates -S foo
42 $ hg diff --nodates -S foo
43 diff -r 000000000000 foo/.hgsub
43 diff -r 000000000000 foo/.hgsub
44 --- /dev/null
44 --- /dev/null
45 +++ b/foo/.hgsub
45 +++ b/foo/.hgsub
46 @@ -0,0 +1,1 @@
46 @@ -0,0 +1,1 @@
47 +bar = bar
47 +bar = bar
48 diff -r 000000000000 foo/y.txt
48 diff -r 000000000000 foo/y.txt
49 --- /dev/null
49 --- /dev/null
50 +++ b/foo/y.txt
50 +++ b/foo/y.txt
51 @@ -0,0 +1,1 @@
51 @@ -0,0 +1,1 @@
52 +y1
52 +y1
53 diff -r 000000000000 foo/bar/z.txt
53 diff -r 000000000000 foo/bar/z.txt
54 --- /dev/null
54 --- /dev/null
55 +++ b/foo/bar/z.txt
55 +++ b/foo/bar/z.txt
56 @@ -0,0 +1,1 @@
56 @@ -0,0 +1,1 @@
57 +z1
57 +z1
58
58
59 Commits:
59 Commits:
60
60
61 $ hg commit -m 0-0-0
61 $ hg commit -m fails
62 abort: uncommitted changes in subrepo foo
63 (use --subrepos for recursive commit)
64 [255]
65
66 The --subrepos flag overwrite the config setting:
67
68 $ hg commit -m 0-0-0 --config ui.commitsubrepos=No --subrepos
62 committing subrepository foo
69 committing subrepository foo
63 committing subrepository foo/bar
70 committing subrepository foo/bar
64
71
65 $ cd foo
72 $ cd foo
66 $ echo y2 >> y.txt
73 $ echo y2 >> y.txt
67 $ hg commit -m 0-1-0
74 $ hg commit -m 0-1-0
68
75
69 $ cd bar
76 $ cd bar
70 $ echo z2 >> z.txt
77 $ echo z2 >> z.txt
71 $ hg commit -m 0-1-1
78 $ hg commit -m 0-1-1
72
79
73 $ cd ..
80 $ cd ..
74 $ hg commit -m 0-2-1
81 $ hg commit -m 0-2-1
75 committing subrepository bar
82 committing subrepository bar
76
83
77 $ cd ..
84 $ cd ..
78 $ hg commit -m 1-2-1
85 $ hg commit -m 1-2-1
79 committing subrepository foo
86 committing subrepository foo
80
87
81 Change working directory:
88 Change working directory:
82
89
83 $ echo y3 >> foo/y.txt
90 $ echo y3 >> foo/y.txt
84 $ echo z3 >> foo/bar/z.txt
91 $ echo z3 >> foo/bar/z.txt
85 $ hg status -S
92 $ hg status -S
86 M foo/bar/z.txt
93 M foo/bar/z.txt
87 M foo/y.txt
94 M foo/y.txt
88 $ hg diff --nodates -S
95 $ hg diff --nodates -S
89 diff -r d254738c5f5e foo/y.txt
96 diff -r d254738c5f5e foo/y.txt
90 --- a/foo/y.txt
97 --- a/foo/y.txt
91 +++ b/foo/y.txt
98 +++ b/foo/y.txt
92 @@ -1,2 +1,3 @@
99 @@ -1,2 +1,3 @@
93 y1
100 y1
94 y2
101 y2
95 +y3
102 +y3
96 diff -r 9647f22de499 foo/bar/z.txt
103 diff -r 9647f22de499 foo/bar/z.txt
97 --- a/foo/bar/z.txt
104 --- a/foo/bar/z.txt
98 +++ b/foo/bar/z.txt
105 +++ b/foo/bar/z.txt
99 @@ -1,2 +1,3 @@
106 @@ -1,2 +1,3 @@
100 z1
107 z1
101 z2
108 z2
102 +z3
109 +z3
103
110
104 Status call crossing repository boundaries:
111 Status call crossing repository boundaries:
105
112
106 $ hg status -S foo/bar/z.txt
113 $ hg status -S foo/bar/z.txt
107 M foo/bar/z.txt
114 M foo/bar/z.txt
108 $ hg status -S -I 'foo/?.txt'
115 $ hg status -S -I 'foo/?.txt'
109 M foo/y.txt
116 M foo/y.txt
110 $ hg status -S -I '**/?.txt'
117 $ hg status -S -I '**/?.txt'
111 M foo/bar/z.txt
118 M foo/bar/z.txt
112 M foo/y.txt
119 M foo/y.txt
113 $ hg diff --nodates -S -I '**/?.txt'
120 $ hg diff --nodates -S -I '**/?.txt'
114 diff -r d254738c5f5e foo/y.txt
121 diff -r d254738c5f5e foo/y.txt
115 --- a/foo/y.txt
122 --- a/foo/y.txt
116 +++ b/foo/y.txt
123 +++ b/foo/y.txt
117 @@ -1,2 +1,3 @@
124 @@ -1,2 +1,3 @@
118 y1
125 y1
119 y2
126 y2
120 +y3
127 +y3
121 diff -r 9647f22de499 foo/bar/z.txt
128 diff -r 9647f22de499 foo/bar/z.txt
122 --- a/foo/bar/z.txt
129 --- a/foo/bar/z.txt
123 +++ b/foo/bar/z.txt
130 +++ b/foo/bar/z.txt
124 @@ -1,2 +1,3 @@
131 @@ -1,2 +1,3 @@
125 z1
132 z1
126 z2
133 z2
127 +z3
134 +z3
128
135
129 Status from within a subdirectory:
136 Status from within a subdirectory:
130
137
131 $ mkdir dir
138 $ mkdir dir
132 $ cd dir
139 $ cd dir
133 $ echo a1 > a.txt
140 $ echo a1 > a.txt
134 $ hg status -S
141 $ hg status -S
135 M foo/bar/z.txt
142 M foo/bar/z.txt
136 M foo/y.txt
143 M foo/y.txt
137 ? dir/a.txt
144 ? dir/a.txt
138 $ hg diff --nodates -S
145 $ hg diff --nodates -S
139 diff -r d254738c5f5e foo/y.txt
146 diff -r d254738c5f5e foo/y.txt
140 --- a/foo/y.txt
147 --- a/foo/y.txt
141 +++ b/foo/y.txt
148 +++ b/foo/y.txt
142 @@ -1,2 +1,3 @@
149 @@ -1,2 +1,3 @@
143 y1
150 y1
144 y2
151 y2
145 +y3
152 +y3
146 diff -r 9647f22de499 foo/bar/z.txt
153 diff -r 9647f22de499 foo/bar/z.txt
147 --- a/foo/bar/z.txt
154 --- a/foo/bar/z.txt
148 +++ b/foo/bar/z.txt
155 +++ b/foo/bar/z.txt
149 @@ -1,2 +1,3 @@
156 @@ -1,2 +1,3 @@
150 z1
157 z1
151 z2
158 z2
152 +z3
159 +z3
153
160
154 Status with relative path:
161 Status with relative path:
155
162
156 $ hg status -S ..
163 $ hg status -S ..
157 M ../foo/bar/z.txt
164 M ../foo/bar/z.txt
158 M ../foo/y.txt
165 M ../foo/y.txt
159 ? a.txt
166 ? a.txt
160 $ hg diff --nodates -S ..
167 $ hg diff --nodates -S ..
161 diff -r d254738c5f5e foo/y.txt
168 diff -r d254738c5f5e foo/y.txt
162 --- a/foo/y.txt
169 --- a/foo/y.txt
163 +++ b/foo/y.txt
170 +++ b/foo/y.txt
164 @@ -1,2 +1,3 @@
171 @@ -1,2 +1,3 @@
165 y1
172 y1
166 y2
173 y2
167 +y3
174 +y3
168 diff -r 9647f22de499 foo/bar/z.txt
175 diff -r 9647f22de499 foo/bar/z.txt
169 --- a/foo/bar/z.txt
176 --- a/foo/bar/z.txt
170 +++ b/foo/bar/z.txt
177 +++ b/foo/bar/z.txt
171 @@ -1,2 +1,3 @@
178 @@ -1,2 +1,3 @@
172 z1
179 z1
173 z2
180 z2
174 +z3
181 +z3
175 $ cd ..
182 $ cd ..
176
183
177 Cleanup and final commit:
184 Cleanup and final commit:
178
185
179 $ rm -r dir
186 $ rm -r dir
180 $ hg commit -m 2-3-2
187 $ hg commit --subrepos -m 2-3-2
181 committing subrepository foo
188 committing subrepository foo
182 committing subrepository foo/bar
189 committing subrepository foo/bar
183
190
184 Log with the relationships between repo and its subrepo:
191 Log with the relationships between repo and its subrepo:
185
192
186 $ hg log --template '{rev}:{node|short} {desc}\n'
193 $ hg log --template '{rev}:{node|short} {desc}\n'
187 2:1326fa26d0c0 2-3-2
194 2:1326fa26d0c0 2-3-2
188 1:4b3c9ff4f66b 1-2-1
195 1:4b3c9ff4f66b 1-2-1
189 0:23376cbba0d8 0-0-0
196 0:23376cbba0d8 0-0-0
190
197
191 $ hg -R foo log --template '{rev}:{node|short} {desc}\n'
198 $ hg -R foo log --template '{rev}:{node|short} {desc}\n'
192 3:65903cebad86 2-3-2
199 3:65903cebad86 2-3-2
193 2:d254738c5f5e 0-2-1
200 2:d254738c5f5e 0-2-1
194 1:8629ce7dcc39 0-1-0
201 1:8629ce7dcc39 0-1-0
195 0:af048e97ade2 0-0-0
202 0:af048e97ade2 0-0-0
196
203
197 $ hg -R foo/bar log --template '{rev}:{node|short} {desc}\n'
204 $ hg -R foo/bar log --template '{rev}:{node|short} {desc}\n'
198 2:31ecbdafd357 2-3-2
205 2:31ecbdafd357 2-3-2
199 1:9647f22de499 0-1-1
206 1:9647f22de499 0-1-1
200 0:4904098473f9 0-0-0
207 0:4904098473f9 0-0-0
201
208
202 Status between revisions:
209 Status between revisions:
203
210
204 $ hg status -S
211 $ hg status -S
205 $ hg status -S --rev 0:1
212 $ hg status -S --rev 0:1
206 M .hgsubstate
213 M .hgsubstate
207 M foo/.hgsubstate
214 M foo/.hgsubstate
208 M foo/bar/z.txt
215 M foo/bar/z.txt
209 M foo/y.txt
216 M foo/y.txt
210 $ hg diff --nodates -S -I '**/?.txt' --rev 0:1
217 $ hg diff --nodates -S -I '**/?.txt' --rev 0:1
211 diff -r af048e97ade2 -r d254738c5f5e foo/y.txt
218 diff -r af048e97ade2 -r d254738c5f5e foo/y.txt
212 --- a/foo/y.txt
219 --- a/foo/y.txt
213 +++ b/foo/y.txt
220 +++ b/foo/y.txt
214 @@ -1,1 +1,2 @@
221 @@ -1,1 +1,2 @@
215 y1
222 y1
216 +y2
223 +y2
217 diff -r 4904098473f9 -r 9647f22de499 foo/bar/z.txt
224 diff -r 4904098473f9 -r 9647f22de499 foo/bar/z.txt
218 --- a/foo/bar/z.txt
225 --- a/foo/bar/z.txt
219 +++ b/foo/bar/z.txt
226 +++ b/foo/bar/z.txt
220 @@ -1,1 +1,2 @@
227 @@ -1,1 +1,2 @@
221 z1
228 z1
222 +z2
229 +z2
223
230
224 Enable progress extension for archive tests:
231 Enable progress extension for archive tests:
225
232
226 $ cp $HGRCPATH $HGRCPATH.no-progress
233 $ cp $HGRCPATH $HGRCPATH.no-progress
227 $ cat >> $HGRCPATH <<EOF
234 $ cat >> $HGRCPATH <<EOF
228 > [extensions]
235 > [extensions]
229 > progress =
236 > progress =
230 > [progress]
237 > [progress]
231 > assume-tty = 1
238 > assume-tty = 1
232 > delay = 0
239 > delay = 0
233 > format = topic bar number
240 > format = topic bar number
234 > refresh = 0
241 > refresh = 0
235 > width = 60
242 > width = 60
236 > EOF
243 > EOF
237
244
238 Test archiving to a directory tree (the doubled lines in the output
245 Test archiving to a directory tree (the doubled lines in the output
239 only show up in the test output, not in real usage):
246 only show up in the test output, not in real usage):
240
247
241 $ hg archive --subrepos ../archive 2>&1 | $TESTDIR/filtercr.py
248 $ hg archive --subrepos ../archive 2>&1 | $TESTDIR/filtercr.py
242
249
243 archiving [ ] 0/3
250 archiving [ ] 0/3
244 archiving [ ] 0/3
251 archiving [ ] 0/3
245 archiving [=============> ] 1/3
252 archiving [=============> ] 1/3
246 archiving [=============> ] 1/3
253 archiving [=============> ] 1/3
247 archiving [===========================> ] 2/3
254 archiving [===========================> ] 2/3
248 archiving [===========================> ] 2/3
255 archiving [===========================> ] 2/3
249 archiving [==========================================>] 3/3
256 archiving [==========================================>] 3/3
250 archiving [==========================================>] 3/3
257 archiving [==========================================>] 3/3
251
258
252 archiving (foo) [ ] 0/3
259 archiving (foo) [ ] 0/3
253 archiving (foo) [ ] 0/3
260 archiving (foo) [ ] 0/3
254 archiving (foo) [===========> ] 1/3
261 archiving (foo) [===========> ] 1/3
255 archiving (foo) [===========> ] 1/3
262 archiving (foo) [===========> ] 1/3
256 archiving (foo) [=======================> ] 2/3
263 archiving (foo) [=======================> ] 2/3
257 archiving (foo) [=======================> ] 2/3
264 archiving (foo) [=======================> ] 2/3
258 archiving (foo) [====================================>] 3/3
265 archiving (foo) [====================================>] 3/3
259 archiving (foo) [====================================>] 3/3
266 archiving (foo) [====================================>] 3/3
260
267
261 archiving (foo/bar) [ ] 0/1
268 archiving (foo/bar) [ ] 0/1
262 archiving (foo/bar) [ ] 0/1
269 archiving (foo/bar) [ ] 0/1
263 archiving (foo/bar) [================================>] 1/1
270 archiving (foo/bar) [================================>] 1/1
264 archiving (foo/bar) [================================>] 1/1
271 archiving (foo/bar) [================================>] 1/1
265 \r (esc)
272 \r (esc)
266 $ find ../archive | sort
273 $ find ../archive | sort
267 ../archive
274 ../archive
268 ../archive/.hg_archival.txt
275 ../archive/.hg_archival.txt
269 ../archive/.hgsub
276 ../archive/.hgsub
270 ../archive/.hgsubstate
277 ../archive/.hgsubstate
271 ../archive/foo
278 ../archive/foo
272 ../archive/foo/.hgsub
279 ../archive/foo/.hgsub
273 ../archive/foo/.hgsubstate
280 ../archive/foo/.hgsubstate
274 ../archive/foo/bar
281 ../archive/foo/bar
275 ../archive/foo/bar/z.txt
282 ../archive/foo/bar/z.txt
276 ../archive/foo/y.txt
283 ../archive/foo/y.txt
277 ../archive/x.txt
284 ../archive/x.txt
278
285
279 Test archiving to zip file (unzip output is unstable):
286 Test archiving to zip file (unzip output is unstable):
280
287
281 $ hg archive --subrepos ../archive.zip 2>&1 | $TESTDIR/filtercr.py
288 $ hg archive --subrepos ../archive.zip 2>&1 | $TESTDIR/filtercr.py
282
289
283 archiving [ ] 0/3
290 archiving [ ] 0/3
284 archiving [ ] 0/3
291 archiving [ ] 0/3
285 archiving [=============> ] 1/3
292 archiving [=============> ] 1/3
286 archiving [=============> ] 1/3
293 archiving [=============> ] 1/3
287 archiving [===========================> ] 2/3
294 archiving [===========================> ] 2/3
288 archiving [===========================> ] 2/3
295 archiving [===========================> ] 2/3
289 archiving [==========================================>] 3/3
296 archiving [==========================================>] 3/3
290 archiving [==========================================>] 3/3
297 archiving [==========================================>] 3/3
291
298
292 archiving (foo) [ ] 0/3
299 archiving (foo) [ ] 0/3
293 archiving (foo) [ ] 0/3
300 archiving (foo) [ ] 0/3
294 archiving (foo) [===========> ] 1/3
301 archiving (foo) [===========> ] 1/3
295 archiving (foo) [===========> ] 1/3
302 archiving (foo) [===========> ] 1/3
296 archiving (foo) [=======================> ] 2/3
303 archiving (foo) [=======================> ] 2/3
297 archiving (foo) [=======================> ] 2/3
304 archiving (foo) [=======================> ] 2/3
298 archiving (foo) [====================================>] 3/3
305 archiving (foo) [====================================>] 3/3
299 archiving (foo) [====================================>] 3/3
306 archiving (foo) [====================================>] 3/3
300
307
301 archiving (foo/bar) [ ] 0/1
308 archiving (foo/bar) [ ] 0/1
302 archiving (foo/bar) [ ] 0/1
309 archiving (foo/bar) [ ] 0/1
303 archiving (foo/bar) [================================>] 1/1
310 archiving (foo/bar) [================================>] 1/1
304 archiving (foo/bar) [================================>] 1/1
311 archiving (foo/bar) [================================>] 1/1
305 \r (esc)
312 \r (esc)
306
313
307 Test archiving a revision that references a subrepo that is not yet
314 Test archiving a revision that references a subrepo that is not yet
308 cloned:
315 cloned:
309
316
310 $ hg clone -U . ../empty
317 $ hg clone -U . ../empty
311 $ cd ../empty
318 $ cd ../empty
312 $ hg archive --subrepos -r tip ../archive.tar.gz 2>&1 | $TESTDIR/filtercr.py
319 $ hg archive --subrepos -r tip ../archive.tar.gz 2>&1 | $TESTDIR/filtercr.py
313
320
314 archiving [ ] 0/3
321 archiving [ ] 0/3
315 archiving [ ] 0/3
322 archiving [ ] 0/3
316 archiving [=============> ] 1/3
323 archiving [=============> ] 1/3
317 archiving [=============> ] 1/3
324 archiving [=============> ] 1/3
318 archiving [===========================> ] 2/3
325 archiving [===========================> ] 2/3
319 archiving [===========================> ] 2/3
326 archiving [===========================> ] 2/3
320 archiving [==========================================>] 3/3
327 archiving [==========================================>] 3/3
321 archiving [==========================================>] 3/3
328 archiving [==========================================>] 3/3
322
329
323 archiving (foo) [ ] 0/3
330 archiving (foo) [ ] 0/3
324 archiving (foo) [ ] 0/3
331 archiving (foo) [ ] 0/3
325 archiving (foo) [===========> ] 1/3
332 archiving (foo) [===========> ] 1/3
326 archiving (foo) [===========> ] 1/3
333 archiving (foo) [===========> ] 1/3
327 archiving (foo) [=======================> ] 2/3
334 archiving (foo) [=======================> ] 2/3
328 archiving (foo) [=======================> ] 2/3
335 archiving (foo) [=======================> ] 2/3
329 archiving (foo) [====================================>] 3/3
336 archiving (foo) [====================================>] 3/3
330 archiving (foo) [====================================>] 3/3
337 archiving (foo) [====================================>] 3/3
331
338
332 archiving (foo/bar) [ ] 0/1
339 archiving (foo/bar) [ ] 0/1
333 archiving (foo/bar) [ ] 0/1
340 archiving (foo/bar) [ ] 0/1
334 archiving (foo/bar) [================================>] 1/1
341 archiving (foo/bar) [================================>] 1/1
335 archiving (foo/bar) [================================>] 1/1
342 archiving (foo/bar) [================================>] 1/1
336
343
337 cloning subrepo foo from $TESTTMP/repo/foo
344 cloning subrepo foo from $TESTTMP/repo/foo
338 cloning subrepo foo/bar from $TESTTMP/repo/foo/bar
345 cloning subrepo foo/bar from $TESTTMP/repo/foo/bar
339
346
340 The newly cloned subrepos contain no working copy:
347 The newly cloned subrepos contain no working copy:
341
348
342 $ hg -R foo summary
349 $ hg -R foo summary
343 parent: -1:000000000000 (no revision checked out)
350 parent: -1:000000000000 (no revision checked out)
344 branch: default
351 branch: default
345 commit: (clean)
352 commit: (clean)
346 update: 4 new changesets (update)
353 update: 4 new changesets (update)
347
354
348 Disable progress extension and cleanup:
355 Disable progress extension and cleanup:
349
356
350 $ mv $HGRCPATH.no-progress $HGRCPATH
357 $ mv $HGRCPATH.no-progress $HGRCPATH
351
358
352 Test archiving when there is a directory in the way for a subrepo
359 Test archiving when there is a directory in the way for a subrepo
353 created by archive:
360 created by archive:
354
361
355 $ hg clone -U . ../almost-empty
362 $ hg clone -U . ../almost-empty
356 $ cd ../almost-empty
363 $ cd ../almost-empty
357 $ mkdir foo
364 $ mkdir foo
358 $ echo f > foo/f
365 $ echo f > foo/f
359 $ hg archive --subrepos -r tip archive
366 $ hg archive --subrepos -r tip archive
360 cloning subrepo foo from $TESTTMP/empty/foo
367 cloning subrepo foo from $TESTTMP/empty/foo
361 abort: destination '$TESTTMP/almost-empty/foo' is not empty
368 abort: destination '$TESTTMP/almost-empty/foo' is not empty
362 [255]
369 [255]
363
370
364 Clone and test outgoing:
371 Clone and test outgoing:
365
372
366 $ cd ..
373 $ cd ..
367 $ hg clone repo repo2
374 $ hg clone repo repo2
368 updating to branch default
375 updating to branch default
369 cloning subrepo foo from $TESTTMP/repo/foo
376 cloning subrepo foo from $TESTTMP/repo/foo
370 cloning subrepo foo/bar from $TESTTMP/repo/foo/bar
377 cloning subrepo foo/bar from $TESTTMP/repo/foo/bar
371 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
378 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
372 $ cd repo2
379 $ cd repo2
373 $ hg outgoing -S
380 $ hg outgoing -S
374 comparing with $TESTTMP/repo
381 comparing with $TESTTMP/repo
375 searching for changes
382 searching for changes
376 no changes found
383 no changes found
377 comparing with $TESTTMP/repo/foo
384 comparing with $TESTTMP/repo/foo
378 searching for changes
385 searching for changes
379 no changes found
386 no changes found
380 comparing with $TESTTMP/repo/foo/bar
387 comparing with $TESTTMP/repo/foo/bar
381 searching for changes
388 searching for changes
382 no changes found
389 no changes found
383 [1]
390 [1]
384
391
385 Make nested change:
392 Make nested change:
386
393
387 $ echo y4 >> foo/y.txt
394 $ echo y4 >> foo/y.txt
388 $ hg diff --nodates -S
395 $ hg diff --nodates -S
389 diff -r 65903cebad86 foo/y.txt
396 diff -r 65903cebad86 foo/y.txt
390 --- a/foo/y.txt
397 --- a/foo/y.txt
391 +++ b/foo/y.txt
398 +++ b/foo/y.txt
392 @@ -1,3 +1,4 @@
399 @@ -1,3 +1,4 @@
393 y1
400 y1
394 y2
401 y2
395 y3
402 y3
396 +y4
403 +y4
397 $ hg commit -m 3-4-2
404 $ hg commit --subrepos -m 3-4-2
398 committing subrepository foo
405 committing subrepository foo
399 $ hg outgoing -S
406 $ hg outgoing -S
400 comparing with $TESTTMP/repo
407 comparing with $TESTTMP/repo
401 searching for changes
408 searching for changes
402 changeset: 3:2655b8ecc4ee
409 changeset: 3:2655b8ecc4ee
403 tag: tip
410 tag: tip
404 user: test
411 user: test
405 date: Thu Jan 01 00:00:00 1970 +0000
412 date: Thu Jan 01 00:00:00 1970 +0000
406 summary: 3-4-2
413 summary: 3-4-2
407
414
408 comparing with $TESTTMP/repo/foo
415 comparing with $TESTTMP/repo/foo
409 searching for changes
416 searching for changes
410 changeset: 4:e96193d6cb36
417 changeset: 4:e96193d6cb36
411 tag: tip
418 tag: tip
412 user: test
419 user: test
413 date: Thu Jan 01 00:00:00 1970 +0000
420 date: Thu Jan 01 00:00:00 1970 +0000
414 summary: 3-4-2
421 summary: 3-4-2
415
422
416 comparing with $TESTTMP/repo/foo/bar
423 comparing with $TESTTMP/repo/foo/bar
417 searching for changes
424 searching for changes
418 no changes found
425 no changes found
419
426
420
427
421 Switch to original repo and setup default path:
428 Switch to original repo and setup default path:
422
429
423 $ cd ../repo
430 $ cd ../repo
424 $ echo '[paths]' >> .hg/hgrc
431 $ echo '[paths]' >> .hg/hgrc
425 $ echo 'default = ../repo2' >> .hg/hgrc
432 $ echo 'default = ../repo2' >> .hg/hgrc
426
433
427 Test incoming:
434 Test incoming:
428
435
429 $ hg incoming -S
436 $ hg incoming -S
430 comparing with $TESTTMP/repo2
437 comparing with $TESTTMP/repo2
431 searching for changes
438 searching for changes
432 changeset: 3:2655b8ecc4ee
439 changeset: 3:2655b8ecc4ee
433 tag: tip
440 tag: tip
434 user: test
441 user: test
435 date: Thu Jan 01 00:00:00 1970 +0000
442 date: Thu Jan 01 00:00:00 1970 +0000
436 summary: 3-4-2
443 summary: 3-4-2
437
444
438 comparing with $TESTTMP/repo2/foo
445 comparing with $TESTTMP/repo2/foo
439 searching for changes
446 searching for changes
440 changeset: 4:e96193d6cb36
447 changeset: 4:e96193d6cb36
441 tag: tip
448 tag: tip
442 user: test
449 user: test
443 date: Thu Jan 01 00:00:00 1970 +0000
450 date: Thu Jan 01 00:00:00 1970 +0000
444 summary: 3-4-2
451 summary: 3-4-2
445
452
446 comparing with $TESTTMP/repo2/foo/bar
453 comparing with $TESTTMP/repo2/foo/bar
447 searching for changes
454 searching for changes
448 no changes found
455 no changes found
449
456
450 $ hg incoming -S --bundle incoming.hg
457 $ hg incoming -S --bundle incoming.hg
451 abort: cannot combine --bundle and --subrepos
458 abort: cannot combine --bundle and --subrepos
452 [255]
459 [255]
453
460
454 Test missing subrepo:
461 Test missing subrepo:
455
462
456 $ rm -r foo
463 $ rm -r foo
457 $ hg status -S
464 $ hg status -S
458 warning: error "unknown revision '65903cebad86f1a84bd4f1134f62fa7dcb7a1c98'" in subrepository "foo"
465 warning: error "unknown revision '65903cebad86f1a84bd4f1134f62fa7dcb7a1c98'" in subrepository "foo"
459
466
460 Issue2619: IndexError: list index out of range on hg add with subrepos
467 Issue2619: IndexError: list index out of range on hg add with subrepos
461 The subrepo must sorts after the explicit filename.
468 The subrepo must sorts after the explicit filename.
462
469
463 $ cd ..
470 $ cd ..
464 $ hg init test
471 $ hg init test
465 $ cd test
472 $ cd test
466 $ hg init x
473 $ hg init x
467 $ echo "x = x" >> .hgsub
474 $ echo "x = x" >> .hgsub
468 $ hg add .hgsub
475 $ hg add .hgsub
469 $ touch a x/a
476 $ touch a x/a
470 $ hg add a x/a
477 $ hg add a x/a
@@ -1,585 +1,585 b''
1 $ "$TESTDIR/hghave" svn || exit 80
1 $ "$TESTDIR/hghave" svn || exit 80
2
2
3 $ fix_path()
3 $ fix_path()
4 > {
4 > {
5 > tr '\\' /
5 > tr '\\' /
6 > }
6 > }
7
7
8 SVN wants all paths to start with a slash. Unfortunately, Windows ones
8 SVN wants all paths to start with a slash. Unfortunately, Windows ones
9 don't. Handle that.
9 don't. Handle that.
10
10
11 $ escapedwd=`pwd | fix_path`
11 $ escapedwd=`pwd | fix_path`
12 $ expr "$escapedwd" : '\/' > /dev/null || escapedwd="/$escapedwd"
12 $ expr "$escapedwd" : '\/' > /dev/null || escapedwd="/$escapedwd"
13 $ escapedwd=`python -c "import urllib, sys; sys.stdout.write(urllib.quote(sys.argv[1]))" "$escapedwd"`
13 $ escapedwd=`python -c "import urllib, sys; sys.stdout.write(urllib.quote(sys.argv[1]))" "$escapedwd"`
14
14
15 create subversion repo
15 create subversion repo
16
16
17 $ SVNREPO="file://$escapedwd/svn-repo"
17 $ SVNREPO="file://$escapedwd/svn-repo"
18 $ WCROOT="`pwd`/svn-wc"
18 $ WCROOT="`pwd`/svn-wc"
19 $ svnadmin create svn-repo
19 $ svnadmin create svn-repo
20 $ svn co "$SVNREPO" svn-wc
20 $ svn co "$SVNREPO" svn-wc
21 Checked out revision 0.
21 Checked out revision 0.
22 $ cd svn-wc
22 $ cd svn-wc
23 $ mkdir src
23 $ mkdir src
24 $ echo alpha > src/alpha
24 $ echo alpha > src/alpha
25 $ svn add src
25 $ svn add src
26 A src
26 A src
27 A src/alpha
27 A src/alpha
28 $ mkdir externals
28 $ mkdir externals
29 $ echo other > externals/other
29 $ echo other > externals/other
30 $ svn add externals
30 $ svn add externals
31 A externals
31 A externals
32 A externals/other
32 A externals/other
33 $ svn ci -m 'Add alpha'
33 $ svn ci -m 'Add alpha'
34 Adding externals
34 Adding externals
35 Adding externals/other
35 Adding externals/other
36 Adding src
36 Adding src
37 Adding src/alpha
37 Adding src/alpha
38 Transmitting file data ..
38 Transmitting file data ..
39 Committed revision 1.
39 Committed revision 1.
40 $ svn up
40 $ svn up
41 At revision 1.
41 At revision 1.
42 $ echo "externals -r1 $SVNREPO/externals" > extdef
42 $ echo "externals -r1 $SVNREPO/externals" > extdef
43 $ svn propset -F extdef svn:externals src
43 $ svn propset -F extdef svn:externals src
44 property 'svn:externals' set on 'src'
44 property 'svn:externals' set on 'src'
45 $ svn ci -m 'Setting externals'
45 $ svn ci -m 'Setting externals'
46 Sending src
46 Sending src
47
47
48 Committed revision 2.
48 Committed revision 2.
49 $ cd ..
49 $ cd ..
50
50
51 create hg repo
51 create hg repo
52
52
53 $ mkdir sub
53 $ mkdir sub
54 $ cd sub
54 $ cd sub
55 $ hg init t
55 $ hg init t
56 $ cd t
56 $ cd t
57
57
58 first revision, no sub
58 first revision, no sub
59
59
60 $ echo a > a
60 $ echo a > a
61 $ hg ci -Am0
61 $ hg ci -Am0
62 adding a
62 adding a
63
63
64 add first svn sub with leading whitespaces
64 add first svn sub with leading whitespaces
65
65
66 $ echo "s = [svn] $SVNREPO/src" >> .hgsub
66 $ echo "s = [svn] $SVNREPO/src" >> .hgsub
67 $ echo "subdir/s = [svn] $SVNREPO/src" >> .hgsub
67 $ echo "subdir/s = [svn] $SVNREPO/src" >> .hgsub
68 $ svn co --quiet "$SVNREPO"/src s
68 $ svn co --quiet "$SVNREPO"/src s
69 $ mkdir subdir
69 $ mkdir subdir
70 $ svn co --quiet "$SVNREPO"/src subdir/s
70 $ svn co --quiet "$SVNREPO"/src subdir/s
71 $ hg add .hgsub
71 $ hg add .hgsub
72 $ hg ci -m1
72 $ hg ci -m1
73 committing subrepository s
73 committing subrepository s
74 committing subrepository subdir/s
74 committing subrepository subdir/s
75
75
76 make sure we avoid empty commits (issue2445)
76 make sure we avoid empty commits (issue2445)
77
77
78 $ hg sum
78 $ hg sum
79 parent: 1:* tip (glob)
79 parent: 1:* tip (glob)
80 1
80 1
81 branch: default
81 branch: default
82 commit: (clean)
82 commit: (clean)
83 update: (current)
83 update: (current)
84 $ hg ci -moops
84 $ hg ci -moops
85 nothing changed
85 nothing changed
86 [1]
86 [1]
87
87
88 debugsub
88 debugsub
89
89
90 $ hg debugsub
90 $ hg debugsub
91 path s
91 path s
92 source file://*/svn-repo/src (glob)
92 source file://*/svn-repo/src (glob)
93 revision 2
93 revision 2
94 path subdir/s
94 path subdir/s
95 source file://*/svn-repo/src (glob)
95 source file://*/svn-repo/src (glob)
96 revision 2
96 revision 2
97
97
98 change file in svn and hg, commit
98 change file in svn and hg, commit
99
99
100 $ echo a >> a
100 $ echo a >> a
101 $ echo alpha >> s/alpha
101 $ echo alpha >> s/alpha
102 $ hg sum
102 $ hg sum
103 parent: 1:* tip (glob)
103 parent: 1:* tip (glob)
104 1
104 1
105 branch: default
105 branch: default
106 commit: 1 modified, 1 subrepos
106 commit: 1 modified, 1 subrepos
107 update: (current)
107 update: (current)
108 $ hg commit -m 'Message!'
108 $ hg commit --subrepos -m 'Message!'
109 committing subrepository s
109 committing subrepository s
110 Sending*s/alpha (glob)
110 Sending*s/alpha (glob)
111 Transmitting file data .
111 Transmitting file data .
112 Committed revision 3.
112 Committed revision 3.
113
113
114 Fetching external item into '$TESTTMP/sub/t/s/externals'
114 Fetching external item into '$TESTTMP/sub/t/s/externals'
115 External at revision 1.
115 External at revision 1.
116
116
117 At revision 3.
117 At revision 3.
118 $ hg debugsub
118 $ hg debugsub
119 path s
119 path s
120 source file://*/svn-repo/src (glob)
120 source file://*/svn-repo/src (glob)
121 revision 3
121 revision 3
122 path subdir/s
122 path subdir/s
123 source file://*/svn-repo/src (glob)
123 source file://*/svn-repo/src (glob)
124 revision 2
124 revision 2
125
125
126 add an unrelated revision in svn and update the subrepo to without
126 add an unrelated revision in svn and update the subrepo to without
127 bringing any changes.
127 bringing any changes.
128
128
129 $ svn mkdir "$SVNREPO/unrelated" -m 'create unrelated'
129 $ svn mkdir "$SVNREPO/unrelated" -m 'create unrelated'
130
130
131 Committed revision 4.
131 Committed revision 4.
132 $ svn up s
132 $ svn up s
133
133
134 Fetching external item into 's/externals'
134 Fetching external item into 's/externals'
135 External at revision 1.
135 External at revision 1.
136
136
137 At revision 4.
137 At revision 4.
138 $ hg sum
138 $ hg sum
139 parent: 2:* tip (glob)
139 parent: 2:* tip (glob)
140 Message!
140 Message!
141 branch: default
141 branch: default
142 commit: (clean)
142 commit: (clean)
143 update: (current)
143 update: (current)
144
144
145 $ echo a > s/a
145 $ echo a > s/a
146
146
147 should be empty despite change to s/a
147 should be empty despite change to s/a
148
148
149 $ hg st
149 $ hg st
150
150
151 add a commit from svn
151 add a commit from svn
152
152
153 $ cd "$WCROOT"/src
153 $ cd "$WCROOT"/src
154 $ svn up
154 $ svn up
155 U alpha
155 U alpha
156
156
157 Fetching external item into 'externals'
157 Fetching external item into 'externals'
158 A externals/other
158 A externals/other
159 Updated external to revision 1.
159 Updated external to revision 1.
160
160
161 Updated to revision 4.
161 Updated to revision 4.
162 $ echo xyz >> alpha
162 $ echo xyz >> alpha
163 $ svn propset svn:mime-type 'text/xml' alpha
163 $ svn propset svn:mime-type 'text/xml' alpha
164 property 'svn:mime-type' set on 'alpha'
164 property 'svn:mime-type' set on 'alpha'
165 $ svn ci -m 'amend a from svn'
165 $ svn ci -m 'amend a from svn'
166 Sending src/alpha
166 Sending src/alpha
167 Transmitting file data .
167 Transmitting file data .
168 Committed revision 5.
168 Committed revision 5.
169 $ cd ../../sub/t
169 $ cd ../../sub/t
170
170
171 this commit from hg will fail
171 this commit from hg will fail
172
172
173 $ echo zzz >> s/alpha
173 $ echo zzz >> s/alpha
174 $ hg ci -m 'amend alpha from hg'
174 $ hg ci --subrepos -m 'amend alpha from hg'
175 committing subrepository s
175 committing subrepository s
176 abort: svn: Commit failed (details follow):
176 abort: svn: Commit failed (details follow):
177 svn: (Out of date)?.*/src/alpha.*(is out of date)? (re)
177 svn: (Out of date)?.*/src/alpha.*(is out of date)? (re)
178 [255]
178 [255]
179 $ svn revert -q s/alpha
179 $ svn revert -q s/alpha
180
180
181 this commit fails because of meta changes
181 this commit fails because of meta changes
182
182
183 $ svn propset svn:mime-type 'text/html' s/alpha
183 $ svn propset svn:mime-type 'text/html' s/alpha
184 property 'svn:mime-type' set on 's/alpha'
184 property 'svn:mime-type' set on 's/alpha'
185 $ hg ci -m 'amend alpha from hg'
185 $ hg ci --subrepos -m 'amend alpha from hg'
186 committing subrepository s
186 committing subrepository s
187 abort: svn: Commit failed (details follow):
187 abort: svn: Commit failed (details follow):
188 svn: (Out of date)?.*/src/alpha.*(is out of date)? (re)
188 svn: (Out of date)?.*/src/alpha.*(is out of date)? (re)
189 [255]
189 [255]
190 $ svn revert -q s/alpha
190 $ svn revert -q s/alpha
191
191
192 this commit fails because of externals changes
192 this commit fails because of externals changes
193
193
194 $ echo zzz > s/externals/other
194 $ echo zzz > s/externals/other
195 $ hg ci -m 'amend externals from hg'
195 $ hg ci --subrepos -m 'amend externals from hg'
196 committing subrepository s
196 committing subrepository s
197 abort: cannot commit svn externals
197 abort: cannot commit svn externals
198 [255]
198 [255]
199 $ hg diff --subrepos -r 1:2 | grep -v diff
199 $ hg diff --subrepos -r 1:2 | grep -v diff
200 --- a/.hgsubstate Thu Jan 01 00:00:00 1970 +0000
200 --- a/.hgsubstate Thu Jan 01 00:00:00 1970 +0000
201 +++ b/.hgsubstate Thu Jan 01 00:00:00 1970 +0000
201 +++ b/.hgsubstate Thu Jan 01 00:00:00 1970 +0000
202 @@ -1,2 +1,2 @@
202 @@ -1,2 +1,2 @@
203 -2 s
203 -2 s
204 +3 s
204 +3 s
205 2 subdir/s
205 2 subdir/s
206 --- a/a Thu Jan 01 00:00:00 1970 +0000
206 --- a/a Thu Jan 01 00:00:00 1970 +0000
207 +++ b/a Thu Jan 01 00:00:00 1970 +0000
207 +++ b/a Thu Jan 01 00:00:00 1970 +0000
208 @@ -1,1 +1,2 @@
208 @@ -1,1 +1,2 @@
209 a
209 a
210 +a
210 +a
211 $ svn revert -q s/externals/other
211 $ svn revert -q s/externals/other
212
212
213 this commit fails because of externals meta changes
213 this commit fails because of externals meta changes
214
214
215 $ svn propset svn:mime-type 'text/html' s/externals/other
215 $ svn propset svn:mime-type 'text/html' s/externals/other
216 property 'svn:mime-type' set on 's/externals/other'
216 property 'svn:mime-type' set on 's/externals/other'
217 $ hg ci -m 'amend externals from hg'
217 $ hg ci --subrepos -m 'amend externals from hg'
218 committing subrepository s
218 committing subrepository s
219 abort: cannot commit svn externals
219 abort: cannot commit svn externals
220 [255]
220 [255]
221 $ svn revert -q s/externals/other
221 $ svn revert -q s/externals/other
222
222
223 clone
223 clone
224
224
225 $ cd ..
225 $ cd ..
226 $ hg clone t tc | fix_path
226 $ hg clone t tc | fix_path
227 updating to branch default
227 updating to branch default
228 A tc/s/alpha
228 A tc/s/alpha
229 U tc/s
229 U tc/s
230
230
231 Fetching external item into 'tc/s/externals'
231 Fetching external item into 'tc/s/externals'
232 A tc/s/externals/other
232 A tc/s/externals/other
233 Checked out external at revision 1.
233 Checked out external at revision 1.
234
234
235 Checked out revision 3.
235 Checked out revision 3.
236 A tc/subdir/s/alpha
236 A tc/subdir/s/alpha
237 U tc/subdir/s
237 U tc/subdir/s
238
238
239 Fetching external item into 'tc/subdir/s/externals'
239 Fetching external item into 'tc/subdir/s/externals'
240 A tc/subdir/s/externals/other
240 A tc/subdir/s/externals/other
241 Checked out external at revision 1.
241 Checked out external at revision 1.
242
242
243 Checked out revision 2.
243 Checked out revision 2.
244 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
244 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
245 $ cd tc
245 $ cd tc
246
246
247 debugsub in clone
247 debugsub in clone
248
248
249 $ hg debugsub
249 $ hg debugsub
250 path s
250 path s
251 source file://*/svn-repo/src (glob)
251 source file://*/svn-repo/src (glob)
252 revision 3
252 revision 3
253 path subdir/s
253 path subdir/s
254 source file://*/svn-repo/src (glob)
254 source file://*/svn-repo/src (glob)
255 revision 2
255 revision 2
256
256
257 verify subrepo is contained within the repo directory
257 verify subrepo is contained within the repo directory
258
258
259 $ python -c "import os.path; print os.path.exists('s')"
259 $ python -c "import os.path; print os.path.exists('s')"
260 True
260 True
261
261
262 update to nullrev (must delete the subrepo)
262 update to nullrev (must delete the subrepo)
263
263
264 $ hg up null
264 $ hg up null
265 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
265 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
266 $ ls
266 $ ls
267
267
268 Check hg update --clean
268 Check hg update --clean
269 $ cd $TESTTMP/sub/t
269 $ cd $TESTTMP/sub/t
270 $ cd s
270 $ cd s
271 $ echo c0 > alpha
271 $ echo c0 > alpha
272 $ echo c1 > f1
272 $ echo c1 > f1
273 $ echo c1 > f2
273 $ echo c1 > f2
274 $ svn add f1 -q
274 $ svn add f1 -q
275 $ svn status
275 $ svn status
276 ? * a (glob)
276 ? * a (glob)
277 X * externals (glob)
277 X * externals (glob)
278 ? * f2 (glob)
278 ? * f2 (glob)
279 M * alpha (glob)
279 M * alpha (glob)
280 A * f1 (glob)
280 A * f1 (glob)
281
281
282 Performing status on external item at 'externals'
282 Performing status on external item at 'externals'
283 $ cd ../..
283 $ cd ../..
284 $ hg -R t update -C
284 $ hg -R t update -C
285
285
286 Fetching external item into 't/s/externals'
286 Fetching external item into 't/s/externals'
287 Checked out external at revision 1.
287 Checked out external at revision 1.
288
288
289 Checked out revision 3.
289 Checked out revision 3.
290 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
290 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
291 $ cd t/s
291 $ cd t/s
292 $ svn status
292 $ svn status
293 ? * a (glob)
293 ? * a (glob)
294 X * externals (glob)
294 X * externals (glob)
295 ? * f1 (glob)
295 ? * f1 (glob)
296 ? * f2 (glob)
296 ? * f2 (glob)
297
297
298 Performing status on external item at 'externals'
298 Performing status on external item at 'externals'
299
299
300 Sticky subrepositories, no changes
300 Sticky subrepositories, no changes
301 $ cd $TESTTMP/sub/t
301 $ cd $TESTTMP/sub/t
302 $ hg id -n
302 $ hg id -n
303 2
303 2
304 $ cd s
304 $ cd s
305 $ svnversion
305 $ svnversion
306 3
306 3
307 $ cd ..
307 $ cd ..
308 $ hg update 1
308 $ hg update 1
309 U $TESTTMP/sub/t/s/alpha
309 U $TESTTMP/sub/t/s/alpha
310
310
311 Fetching external item into '$TESTTMP/sub/t/s/externals'
311 Fetching external item into '$TESTTMP/sub/t/s/externals'
312 Checked out external at revision 1.
312 Checked out external at revision 1.
313
313
314 Checked out revision 2.
314 Checked out revision 2.
315 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
315 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
316 $ hg id -n
316 $ hg id -n
317 1
317 1
318 $ cd s
318 $ cd s
319 $ svnversion
319 $ svnversion
320 2
320 2
321 $ cd ..
321 $ cd ..
322
322
323 Sticky subrepositorys, file changes
323 Sticky subrepositorys, file changes
324 $ touch s/f1
324 $ touch s/f1
325 $ cd s
325 $ cd s
326 $ svn add f1
326 $ svn add f1
327 A f1
327 A f1
328 $ cd ..
328 $ cd ..
329 $ hg id -n
329 $ hg id -n
330 1
330 1
331 $ cd s
331 $ cd s
332 $ svnversion
332 $ svnversion
333 2M
333 2M
334 $ cd ..
334 $ cd ..
335 $ hg update tip
335 $ hg update tip
336 subrepository sources for s differ
336 subrepository sources for s differ
337 use (l)ocal source (2) or (r)emote source (3)?
337 use (l)ocal source (2) or (r)emote source (3)?
338 l
338 l
339 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
339 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
340 $ hg id -n
340 $ hg id -n
341 2+
341 2+
342 $ cd s
342 $ cd s
343 $ svnversion
343 $ svnversion
344 2M
344 2M
345 $ cd ..
345 $ cd ..
346 $ hg update --clean tip
346 $ hg update --clean tip
347 U $TESTTMP/sub/t/s/alpha
347 U $TESTTMP/sub/t/s/alpha
348
348
349 Fetching external item into '$TESTTMP/sub/t/s/externals'
349 Fetching external item into '$TESTTMP/sub/t/s/externals'
350 Checked out external at revision 1.
350 Checked out external at revision 1.
351
351
352 Checked out revision 3.
352 Checked out revision 3.
353 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
353 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
354
354
355 Sticky subrepository, revision updates
355 Sticky subrepository, revision updates
356 $ hg id -n
356 $ hg id -n
357 2
357 2
358 $ cd s
358 $ cd s
359 $ svnversion
359 $ svnversion
360 3
360 3
361 $ cd ..
361 $ cd ..
362 $ cd s
362 $ cd s
363 $ svn update -r 1
363 $ svn update -r 1
364 U alpha
364 U alpha
365 U .
365 U .
366
366
367 Fetching external item into 'externals'
367 Fetching external item into 'externals'
368 Updated external to revision 1.
368 Updated external to revision 1.
369
369
370 Updated to revision 1.
370 Updated to revision 1.
371 $ cd ..
371 $ cd ..
372 $ hg update 1
372 $ hg update 1
373 subrepository sources for s differ (in checked out version)
373 subrepository sources for s differ (in checked out version)
374 use (l)ocal source (1) or (r)emote source (2)?
374 use (l)ocal source (1) or (r)emote source (2)?
375 l
375 l
376 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
376 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
377 $ hg id -n
377 $ hg id -n
378 1+
378 1+
379 $ cd s
379 $ cd s
380 $ svnversion
380 $ svnversion
381 1
381 1
382 $ cd ..
382 $ cd ..
383
383
384 Sticky subrepository, file changes and revision updates
384 Sticky subrepository, file changes and revision updates
385 $ touch s/f1
385 $ touch s/f1
386 $ cd s
386 $ cd s
387 $ svn add f1
387 $ svn add f1
388 A f1
388 A f1
389 $ svnversion
389 $ svnversion
390 1M
390 1M
391 $ cd ..
391 $ cd ..
392 $ hg id -n
392 $ hg id -n
393 1+
393 1+
394 $ hg update tip
394 $ hg update tip
395 subrepository sources for s differ
395 subrepository sources for s differ
396 use (l)ocal source (1) or (r)emote source (3)?
396 use (l)ocal source (1) or (r)emote source (3)?
397 l
397 l
398 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
398 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
399 $ hg id -n
399 $ hg id -n
400 2
400 2
401 $ cd s
401 $ cd s
402 $ svnversion
402 $ svnversion
403 1M
403 1M
404 $ cd ..
404 $ cd ..
405
405
406 Sticky repository, update --clean
406 Sticky repository, update --clean
407 $ hg update --clean tip
407 $ hg update --clean tip
408 U $TESTTMP/sub/t/s/alpha
408 U $TESTTMP/sub/t/s/alpha
409 U $TESTTMP/sub/t/s
409 U $TESTTMP/sub/t/s
410
410
411 Fetching external item into '$TESTTMP/sub/t/s/externals'
411 Fetching external item into '$TESTTMP/sub/t/s/externals'
412 Checked out external at revision 1.
412 Checked out external at revision 1.
413
413
414 Checked out revision 3.
414 Checked out revision 3.
415 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
415 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
416 $ hg id -n
416 $ hg id -n
417 2
417 2
418 $ cd s
418 $ cd s
419 $ svnversion
419 $ svnversion
420 3
420 3
421 $ cd ..
421 $ cd ..
422
422
423 Test subrepo already at intended revision:
423 Test subrepo already at intended revision:
424 $ cd s
424 $ cd s
425 $ svn update -r 2
425 $ svn update -r 2
426 U alpha
426 U alpha
427
427
428 Fetching external item into 'externals'
428 Fetching external item into 'externals'
429 Updated external to revision 1.
429 Updated external to revision 1.
430
430
431 Updated to revision 2.
431 Updated to revision 2.
432 $ cd ..
432 $ cd ..
433 $ hg update 1
433 $ hg update 1
434 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
434 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
435 $ hg id -n
435 $ hg id -n
436 1+
436 1+
437 $ cd s
437 $ cd s
438 $ svnversion
438 $ svnversion
439 2
439 2
440 $ cd ..
440 $ cd ..
441
441
442 Test case where subversion would fail to update the subrepo because there
442 Test case where subversion would fail to update the subrepo because there
443 are unknown directories being replaced by tracked ones (happens with rebase).
443 are unknown directories being replaced by tracked ones (happens with rebase).
444
444
445 $ cd $WCROOT/src
445 $ cd $WCROOT/src
446 $ mkdir dir
446 $ mkdir dir
447 $ echo epsilon.py > dir/epsilon.py
447 $ echo epsilon.py > dir/epsilon.py
448 $ svn add dir
448 $ svn add dir
449 A dir
449 A dir
450 A dir/epsilon.py
450 A dir/epsilon.py
451 $ svn ci -m 'Add dir/epsilon.py'
451 $ svn ci -m 'Add dir/epsilon.py'
452 Adding src/dir
452 Adding src/dir
453 Adding src/dir/epsilon.py
453 Adding src/dir/epsilon.py
454 Transmitting file data .
454 Transmitting file data .
455 Committed revision 6.
455 Committed revision 6.
456 $ cd ../..
456 $ cd ../..
457 $ hg init rebaserepo
457 $ hg init rebaserepo
458 $ cd rebaserepo
458 $ cd rebaserepo
459 $ svn co -r5 --quiet "$SVNREPO"/src s
459 $ svn co -r5 --quiet "$SVNREPO"/src s
460 $ echo "s = [svn] $SVNREPO/src" >> .hgsub
460 $ echo "s = [svn] $SVNREPO/src" >> .hgsub
461 $ hg add .hgsub
461 $ hg add .hgsub
462 $ hg ci -m addsub
462 $ hg ci -m addsub
463 committing subrepository s
463 committing subrepository s
464 $ echo a > a
464 $ echo a > a
465 $ hg ci -Am adda
465 $ hg ci -Am adda
466 adding a
466 adding a
467 $ hg up 0
467 $ hg up 0
468 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
468 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
469 $ svn up -r6 s
469 $ svn up -r6 s
470 A s/dir
470 A s/dir
471 A s/dir/epsilon.py
471 A s/dir/epsilon.py
472
472
473 Fetching external item into 's/externals'
473 Fetching external item into 's/externals'
474 Updated external to revision 1.
474 Updated external to revision 1.
475
475
476 Updated to revision 6.
476 Updated to revision 6.
477 $ hg ci -m updatesub
477 $ hg ci -m updatesub
478 committing subrepository s
478 committing subrepository s
479 created new head
479 created new head
480 $ echo pyc > s/dir/epsilon.pyc
480 $ echo pyc > s/dir/epsilon.pyc
481 $ hg up 1
481 $ hg up 1
482 D $TESTTMP/rebaserepo/s/dir
482 D $TESTTMP/rebaserepo/s/dir
483
483
484 Fetching external item into '$TESTTMP/rebaserepo/s/externals'
484 Fetching external item into '$TESTTMP/rebaserepo/s/externals'
485 Checked out external at revision 1.
485 Checked out external at revision 1.
486
486
487 Checked out revision 5.
487 Checked out revision 5.
488 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
488 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
489 $ if "$TESTDIR/hghave" -q svn15; then
489 $ if "$TESTDIR/hghave" -q svn15; then
490 > hg up 2 >/dev/null 2>&1 || echo update failed
490 > hg up 2 >/dev/null 2>&1 || echo update failed
491 > fi
491 > fi
492
492
493 Modify one of the externals to point to a different path so we can
493 Modify one of the externals to point to a different path so we can
494 test having obstructions when switching branches on checkout:
494 test having obstructions when switching branches on checkout:
495 $ hg checkout tip
495 $ hg checkout tip
496 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
496 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
497 $ echo "obstruct = [svn] $SVNREPO/externals" >> .hgsub
497 $ echo "obstruct = [svn] $SVNREPO/externals" >> .hgsub
498 $ svn co -r5 --quiet "$SVNREPO"/externals obstruct
498 $ svn co -r5 --quiet "$SVNREPO"/externals obstruct
499 $ hg commit -m 'Start making obstructed wc'
499 $ hg commit -m 'Start making obstructed wc'
500 committing subrepository obstruct
500 committing subrepository obstruct
501 $ hg book other
501 $ hg book other
502 $ hg co -r 'p1(tip)'
502 $ hg co -r 'p1(tip)'
503 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
503 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
504 $ echo "obstruct = [svn] $SVNREPO/src" >> .hgsub
504 $ echo "obstruct = [svn] $SVNREPO/src" >> .hgsub
505 $ svn co -r5 --quiet "$SVNREPO"/src obstruct
505 $ svn co -r5 --quiet "$SVNREPO"/src obstruct
506 $ hg commit -m 'Other branch which will be obstructed'
506 $ hg commit -m 'Other branch which will be obstructed'
507 committing subrepository obstruct
507 committing subrepository obstruct
508 created new head
508 created new head
509
509
510 Switching back to the head where we have another path mapped to the
510 Switching back to the head where we have another path mapped to the
511 same subrepo should work if the subrepo is clean.
511 same subrepo should work if the subrepo is clean.
512 $ hg co other
512 $ hg co other
513 A $TESTTMP/rebaserepo/obstruct/other
513 A $TESTTMP/rebaserepo/obstruct/other
514 Checked out revision 1.
514 Checked out revision 1.
515 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
515 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
516
516
517 This is surprising, but is also correct based on the current code:
517 This is surprising, but is also correct based on the current code:
518 $ echo "updating should (maybe) fail" > obstruct/other
518 $ echo "updating should (maybe) fail" > obstruct/other
519 $ hg co tip
519 $ hg co tip
520 abort: crosses branches (merge branches or use --clean to discard changes)
520 abort: crosses branches (merge branches or use --clean to discard changes)
521 [255]
521 [255]
522
522
523 Point to a Subversion branch which has since been deleted and recreated
523 Point to a Subversion branch which has since been deleted and recreated
524 First, create that condition in the repository.
524 First, create that condition in the repository.
525
525
526 $ hg ci -m cleanup
526 $ hg ci --subrepos -m cleanup
527 committing subrepository obstruct
527 committing subrepository obstruct
528 Sending obstruct/other
528 Sending obstruct/other
529 Transmitting file data .
529 Transmitting file data .
530 Committed revision 7.
530 Committed revision 7.
531 At revision 7.
531 At revision 7.
532 $ svn mkdir -m "baseline" $SVNREPO/trunk
532 $ svn mkdir -m "baseline" $SVNREPO/trunk
533
533
534 Committed revision 8.
534 Committed revision 8.
535 $ svn copy -m "initial branch" $SVNREPO/trunk $SVNREPO/branch
535 $ svn copy -m "initial branch" $SVNREPO/trunk $SVNREPO/branch
536
536
537 Committed revision 9.
537 Committed revision 9.
538 $ svn co --quiet "$SVNREPO"/branch tempwc
538 $ svn co --quiet "$SVNREPO"/branch tempwc
539 $ cd tempwc
539 $ cd tempwc
540 $ echo "something old" > somethingold
540 $ echo "something old" > somethingold
541 $ svn add somethingold
541 $ svn add somethingold
542 A somethingold
542 A somethingold
543 $ svn ci -m 'Something old'
543 $ svn ci -m 'Something old'
544 Adding somethingold
544 Adding somethingold
545 Transmitting file data .
545 Transmitting file data .
546 Committed revision 10.
546 Committed revision 10.
547 $ svn rm -m "remove branch" $SVNREPO/branch
547 $ svn rm -m "remove branch" $SVNREPO/branch
548
548
549 Committed revision 11.
549 Committed revision 11.
550 $ svn copy -m "recreate branch" $SVNREPO/trunk $SVNREPO/branch
550 $ svn copy -m "recreate branch" $SVNREPO/trunk $SVNREPO/branch
551
551
552 Committed revision 12.
552 Committed revision 12.
553 $ svn up
553 $ svn up
554 D somethingold
554 D somethingold
555 Updated to revision 12.
555 Updated to revision 12.
556 $ echo "something new" > somethingnew
556 $ echo "something new" > somethingnew
557 $ svn add somethingnew
557 $ svn add somethingnew
558 A somethingnew
558 A somethingnew
559 $ svn ci -m 'Something new'
559 $ svn ci -m 'Something new'
560 Adding somethingnew
560 Adding somethingnew
561 Transmitting file data .
561 Transmitting file data .
562 Committed revision 13.
562 Committed revision 13.
563 $ cd ..
563 $ cd ..
564 $ rm -rf tempwc
564 $ rm -rf tempwc
565 $ svn co "$SVNREPO/branch"@10 recreated
565 $ svn co "$SVNREPO/branch"@10 recreated
566 A recreated/somethingold
566 A recreated/somethingold
567 Checked out revision 10.
567 Checked out revision 10.
568 $ echo "recreated = [svn] $SVNREPO/branch" >> .hgsub
568 $ echo "recreated = [svn] $SVNREPO/branch" >> .hgsub
569 $ hg ci -m addsub
569 $ hg ci -m addsub
570 committing subrepository recreated
570 committing subrepository recreated
571 $ cd recreated
571 $ cd recreated
572 $ svn up
572 $ svn up
573 D somethingold
573 D somethingold
574 A somethingnew
574 A somethingnew
575 Updated to revision 13.
575 Updated to revision 13.
576 $ cd ..
576 $ cd ..
577 $ hg ci -m updatesub
577 $ hg ci -m updatesub
578 committing subrepository recreated
578 committing subrepository recreated
579 $ hg up -r-2
579 $ hg up -r-2
580 D $TESTTMP/rebaserepo/recreated/somethingnew
580 D $TESTTMP/rebaserepo/recreated/somethingnew
581 A $TESTTMP/rebaserepo/recreated/somethingold
581 A $TESTTMP/rebaserepo/recreated/somethingold
582 Checked out revision 10.
582 Checked out revision 10.
583 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
583 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
584 $ test -f recreated/somethingold
584 $ test -f recreated/somethingold
585
585
@@ -1,879 +1,885 b''
1 Let commit recurse into subrepos by default to match pre-2.0 behavior:
2
3 $ echo "[ui]" >> $HGRCPATH
4 $ echo "commitsubrepos = Yes" >> $HGRCPATH
5
1 $ rm -rf sub
6 $ rm -rf sub
2 $ mkdir sub
7 $ mkdir sub
3 $ cd sub
8 $ cd sub
4 $ hg init t
9 $ hg init t
5 $ cd t
10 $ cd t
6
11
7 first revision, no sub
12 first revision, no sub
8
13
9 $ echo a > a
14 $ echo a > a
10 $ hg ci -Am0
15 $ hg ci -Am0
11 adding a
16 adding a
12
17
13 add first sub
18 add first sub
14
19
15 $ echo s = s > .hgsub
20 $ echo s = s > .hgsub
16 $ hg add .hgsub
21 $ hg add .hgsub
17 $ hg init s
22 $ hg init s
18 $ echo a > s/a
23 $ echo a > s/a
19
24
20 Issue2232: committing a subrepo without .hgsub
25 Issue2232: committing a subrepo without .hgsub
21
26
22 $ hg ci -mbad s
27 $ hg ci -mbad s
23 abort: can't commit subrepos without .hgsub
28 abort: can't commit subrepos without .hgsub
24 [255]
29 [255]
25
30
26 $ hg -R s ci -Ams0
31 $ hg -R s ci -Ams0
27 adding a
32 adding a
28 $ hg sum
33 $ hg sum
29 parent: 0:f7b1eb17ad24 tip
34 parent: 0:f7b1eb17ad24 tip
30 0
35 0
31 branch: default
36 branch: default
32 commit: 1 added, 1 subrepos
37 commit: 1 added, 1 subrepos
33 update: (current)
38 update: (current)
34 $ hg ci -m1
39 $ hg ci -m1
35 committing subrepository s
40 committing subrepository s
36
41
37 Revert can't (yet) revert subrepos:
42 Revert can't (yet) revert subrepos:
38
43
39 $ echo b > s/a
44 $ echo b > s/a
40 $ hg revert s
45 $ hg revert s
41 s: reverting subrepos is unsupported
46 s: reverting subrepos is unsupported
42
47
43 Revert currently ignores subrepos by default
48 Revert currently ignores subrepos by default
44
49
45 $ hg revert -a
50 $ hg revert -a
46 $ hg revert -R s -a -C
51 $ hg revert -R s -a -C
47 reverting s/a
52 reverting s/a
48
53
49 Issue2022: update -C
54 Issue2022: update -C
50
55
51 $ echo b > s/a
56 $ echo b > s/a
52 $ hg sum
57 $ hg sum
53 parent: 1:7cf8cfea66e4 tip
58 parent: 1:7cf8cfea66e4 tip
54 1
59 1
55 branch: default
60 branch: default
56 commit: 1 subrepos
61 commit: 1 subrepos
57 update: (current)
62 update: (current)
58 $ hg co -C 1
63 $ hg co -C 1
59 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
60 $ hg sum
65 $ hg sum
61 parent: 1:7cf8cfea66e4 tip
66 parent: 1:7cf8cfea66e4 tip
62 1
67 1
63 branch: default
68 branch: default
64 commit: (clean)
69 commit: (clean)
65 update: (current)
70 update: (current)
66
71
67 commands that require a clean repo should respect subrepos
72 commands that require a clean repo should respect subrepos
68
73
69 $ echo b >> s/a
74 $ echo b >> s/a
70 $ hg backout tip
75 $ hg backout tip
71 abort: uncommitted changes in subrepo s
76 abort: uncommitted changes in subrepo s
72 [255]
77 [255]
73 $ hg revert -C -R s s/a
78 $ hg revert -C -R s s/a
74
79
75 add sub sub
80 add sub sub
76
81
77 $ echo ss = ss > s/.hgsub
82 $ echo ss = ss > s/.hgsub
78 $ hg init s/ss
83 $ hg init s/ss
79 $ echo a > s/ss/a
84 $ echo a > s/ss/a
80 $ hg -R s add s/.hgsub
85 $ hg -R s add s/.hgsub
81 $ hg -R s/ss add s/ss/a
86 $ hg -R s/ss add s/ss/a
82 $ hg sum
87 $ hg sum
83 parent: 1:7cf8cfea66e4 tip
88 parent: 1:7cf8cfea66e4 tip
84 1
89 1
85 branch: default
90 branch: default
86 commit: 1 subrepos
91 commit: 1 subrepos
87 update: (current)
92 update: (current)
88 $ hg ci -m2
93 $ hg ci -m2
89 committing subrepository s
94 committing subrepository s
90 committing subrepository s/ss
95 committing subrepository s/ss
91 $ hg sum
96 $ hg sum
92 parent: 2:df30734270ae tip
97 parent: 2:df30734270ae tip
93 2
98 2
94 branch: default
99 branch: default
95 commit: (clean)
100 commit: (clean)
96 update: (current)
101 update: (current)
97
102
98 bump sub rev (and check it is ignored by ui.commitsubrepos)
103 bump sub rev (and check it is ignored by ui.commitsubrepos)
99
104
100 $ echo b > s/a
105 $ echo b > s/a
101 $ hg -R s ci -ms1
106 $ hg -R s ci -ms1
102 $ hg --config ui.commitsubrepos=no ci -m3
107 $ hg --config ui.commitsubrepos=no ci -m3
103 committing subrepository s
108 committing subrepository s
104
109
105 leave sub dirty (and check ui.commitsubrepos=no aborts the commit)
110 leave sub dirty (and check ui.commitsubrepos=no aborts the commit)
106
111
107 $ echo c > s/a
112 $ echo c > s/a
108 $ hg --config ui.commitsubrepos=no ci -m4
113 $ hg --config ui.commitsubrepos=no ci -m4
109 abort: uncommitted changes in subrepo s
114 abort: uncommitted changes in subrepo s
115 (use --subrepos for recursive commit)
110 [255]
116 [255]
111 $ hg ci -m4
117 $ hg ci -m4
112 committing subrepository s
118 committing subrepository s
113 $ hg tip -R s
119 $ hg tip -R s
114 changeset: 3:1c833a7a9e3a
120 changeset: 3:1c833a7a9e3a
115 tag: tip
121 tag: tip
116 user: test
122 user: test
117 date: Thu Jan 01 00:00:00 1970 +0000
123 date: Thu Jan 01 00:00:00 1970 +0000
118 summary: 4
124 summary: 4
119
125
120
126
121 check caching
127 check caching
122
128
123 $ hg co 0
129 $ hg co 0
124 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
125 $ hg debugsub
131 $ hg debugsub
126
132
127 restore
133 restore
128
134
129 $ hg co
135 $ hg co
130 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
131 $ hg debugsub
137 $ hg debugsub
132 path s
138 path s
133 source s
139 source s
134 revision 1c833a7a9e3a4445c711aaf0f012379cd0d4034e
140 revision 1c833a7a9e3a4445c711aaf0f012379cd0d4034e
135
141
136 new branch for merge tests
142 new branch for merge tests
137
143
138 $ hg co 1
144 $ hg co 1
139 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
140 $ echo t = t >> .hgsub
146 $ echo t = t >> .hgsub
141 $ hg init t
147 $ hg init t
142 $ echo t > t/t
148 $ echo t > t/t
143 $ hg -R t add t
149 $ hg -R t add t
144 adding t/t
150 adding t/t
145
151
146 5
152 5
147
153
148 $ hg ci -m5 # add sub
154 $ hg ci -m5 # add sub
149 committing subrepository t
155 committing subrepository t
150 created new head
156 created new head
151 $ echo t2 > t/t
157 $ echo t2 > t/t
152
158
153 6
159 6
154
160
155 $ hg st -R s
161 $ hg st -R s
156 $ hg ci -m6 # change sub
162 $ hg ci -m6 # change sub
157 committing subrepository t
163 committing subrepository t
158 $ hg debugsub
164 $ hg debugsub
159 path s
165 path s
160 source s
166 source s
161 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
167 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
162 path t
168 path t
163 source t
169 source t
164 revision 6747d179aa9a688023c4b0cad32e4c92bb7f34ad
170 revision 6747d179aa9a688023c4b0cad32e4c92bb7f34ad
165 $ echo t3 > t/t
171 $ echo t3 > t/t
166
172
167 7
173 7
168
174
169 $ hg ci -m7 # change sub again for conflict test
175 $ hg ci -m7 # change sub again for conflict test
170 committing subrepository t
176 committing subrepository t
171 $ hg rm .hgsub
177 $ hg rm .hgsub
172
178
173 8
179 8
174
180
175 $ hg ci -m8 # remove sub
181 $ hg ci -m8 # remove sub
176
182
177 merge tests
183 merge tests
178
184
179 $ hg co -C 3
185 $ hg co -C 3
180 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
181 $ hg merge 5 # test adding
187 $ hg merge 5 # test adding
182 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
183 (branch merge, don't forget to commit)
189 (branch merge, don't forget to commit)
184 $ hg debugsub
190 $ hg debugsub
185 path s
191 path s
186 source s
192 source s
187 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
193 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
188 path t
194 path t
189 source t
195 source t
190 revision 60ca1237c19474e7a3978b0dc1ca4e6f36d51382
196 revision 60ca1237c19474e7a3978b0dc1ca4e6f36d51382
191 $ hg ci -m9
197 $ hg ci -m9
192 created new head
198 created new head
193 $ hg merge 6 --debug # test change
199 $ hg merge 6 --debug # test change
194 searching for copies back to rev 2
200 searching for copies back to rev 2
195 resolving manifests
201 resolving manifests
196 overwrite None partial False
202 overwrite None partial False
197 ancestor 1f14a2e2d3ec local f0d2028bf86d+ remote 1831e14459c4
203 ancestor 1f14a2e2d3ec local f0d2028bf86d+ remote 1831e14459c4
198 .hgsubstate: versions differ -> m
204 .hgsubstate: versions differ -> m
199 updating: .hgsubstate 1/1 files (100.00%)
205 updating: .hgsubstate 1/1 files (100.00%)
200 subrepo merge f0d2028bf86d+ 1831e14459c4 1f14a2e2d3ec
206 subrepo merge f0d2028bf86d+ 1831e14459c4 1f14a2e2d3ec
201 subrepo t: other changed, get t:6747d179aa9a688023c4b0cad32e4c92bb7f34ad:hg
207 subrepo t: other changed, get t:6747d179aa9a688023c4b0cad32e4c92bb7f34ad:hg
202 getting subrepo t
208 getting subrepo t
203 resolving manifests
209 resolving manifests
204 overwrite True partial False
210 overwrite True partial False
205 ancestor 60ca1237c194+ local 60ca1237c194+ remote 6747d179aa9a
211 ancestor 60ca1237c194+ local 60ca1237c194+ remote 6747d179aa9a
206 t: remote is newer -> g
212 t: remote is newer -> g
207 updating: t 1/1 files (100.00%)
213 updating: t 1/1 files (100.00%)
208 getting t
214 getting t
209 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
210 (branch merge, don't forget to commit)
216 (branch merge, don't forget to commit)
211 $ hg debugsub
217 $ hg debugsub
212 path s
218 path s
213 source s
219 source s
214 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
220 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
215 path t
221 path t
216 source t
222 source t
217 revision 6747d179aa9a688023c4b0cad32e4c92bb7f34ad
223 revision 6747d179aa9a688023c4b0cad32e4c92bb7f34ad
218 $ echo conflict > t/t
224 $ echo conflict > t/t
219 $ hg ci -m10
225 $ hg ci -m10
220 committing subrepository t
226 committing subrepository t
221 $ HGMERGE=internal:merge hg merge --debug 7 # test conflict
227 $ HGMERGE=internal:merge hg merge --debug 7 # test conflict
222 searching for copies back to rev 2
228 searching for copies back to rev 2
223 resolving manifests
229 resolving manifests
224 overwrite None partial False
230 overwrite None partial False
225 ancestor 1831e14459c4 local e45c8b14af55+ remote f94576341bcf
231 ancestor 1831e14459c4 local e45c8b14af55+ remote f94576341bcf
226 .hgsubstate: versions differ -> m
232 .hgsubstate: versions differ -> m
227 updating: .hgsubstate 1/1 files (100.00%)
233 updating: .hgsubstate 1/1 files (100.00%)
228 subrepo merge e45c8b14af55+ f94576341bcf 1831e14459c4
234 subrepo merge e45c8b14af55+ f94576341bcf 1831e14459c4
229 subrepo t: both sides changed, merge with t:7af322bc1198a32402fe903e0b7ebcfc5c9bf8f4:hg
235 subrepo t: both sides changed, merge with t:7af322bc1198a32402fe903e0b7ebcfc5c9bf8f4:hg
230 merging subrepo t
236 merging subrepo t
231 searching for copies back to rev 2
237 searching for copies back to rev 2
232 resolving manifests
238 resolving manifests
233 overwrite None partial False
239 overwrite None partial False
234 ancestor 6747d179aa9a local 20a0db6fbf6c+ remote 7af322bc1198
240 ancestor 6747d179aa9a local 20a0db6fbf6c+ remote 7af322bc1198
235 t: versions differ -> m
241 t: versions differ -> m
236 preserving t for resolve of t
242 preserving t for resolve of t
237 updating: t 1/1 files (100.00%)
243 updating: t 1/1 files (100.00%)
238 picked tool 'internal:merge' for t (binary False symlink False)
244 picked tool 'internal:merge' for t (binary False symlink False)
239 merging t
245 merging t
240 my t@20a0db6fbf6c+ other t@7af322bc1198 ancestor t@6747d179aa9a
246 my t@20a0db6fbf6c+ other t@7af322bc1198 ancestor t@6747d179aa9a
241 warning: conflicts during merge.
247 warning: conflicts during merge.
242 merging t failed!
248 merging t failed!
243 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
244 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
245 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
246 (branch merge, don't forget to commit)
252 (branch merge, don't forget to commit)
247
253
248 should conflict
254 should conflict
249
255
250 $ cat t/t
256 $ cat t/t
251 <<<<<<< local
257 <<<<<<< local
252 conflict
258 conflict
253 =======
259 =======
254 t3
260 t3
255 >>>>>>> other
261 >>>>>>> other
256
262
257 clone
263 clone
258
264
259 $ cd ..
265 $ cd ..
260 $ hg clone t tc
266 $ hg clone t tc
261 updating to branch default
267 updating to branch default
262 cloning subrepo s from $TESTTMP/sub/t/s
268 cloning subrepo s from $TESTTMP/sub/t/s
263 cloning subrepo s/ss from $TESTTMP/sub/t/s/ss
269 cloning subrepo s/ss from $TESTTMP/sub/t/s/ss
264 cloning subrepo t from $TESTTMP/sub/t/t
270 cloning subrepo t from $TESTTMP/sub/t/t
265 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
266 $ cd tc
272 $ cd tc
267 $ hg debugsub
273 $ hg debugsub
268 path s
274 path s
269 source s
275 source s
270 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
276 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
271 path t
277 path t
272 source t
278 source t
273 revision 20a0db6fbf6c3d2836e6519a642ae929bfc67c0e
279 revision 20a0db6fbf6c3d2836e6519a642ae929bfc67c0e
274
280
275 push
281 push
276
282
277 $ echo bah > t/t
283 $ echo bah > t/t
278 $ hg ci -m11
284 $ hg ci -m11
279 committing subrepository t
285 committing subrepository t
280 $ hg push
286 $ hg push
281 pushing to $TESTTMP/sub/t
287 pushing to $TESTTMP/sub/t
282 pushing subrepo s/ss to $TESTTMP/sub/t/s/ss
288 pushing subrepo s/ss to $TESTTMP/sub/t/s/ss
283 searching for changes
289 searching for changes
284 no changes found
290 no changes found
285 pushing subrepo s to $TESTTMP/sub/t/s
291 pushing subrepo s to $TESTTMP/sub/t/s
286 searching for changes
292 searching for changes
287 no changes found
293 no changes found
288 pushing subrepo t to $TESTTMP/sub/t/t
294 pushing subrepo t to $TESTTMP/sub/t/t
289 searching for changes
295 searching for changes
290 adding changesets
296 adding changesets
291 adding manifests
297 adding manifests
292 adding file changes
298 adding file changes
293 added 1 changesets with 1 changes to 1 files
299 added 1 changesets with 1 changes to 1 files
294 searching for changes
300 searching for changes
295 adding changesets
301 adding changesets
296 adding manifests
302 adding manifests
297 adding file changes
303 adding file changes
298 added 1 changesets with 1 changes to 1 files
304 added 1 changesets with 1 changes to 1 files
299
305
300 push -f
306 push -f
301
307
302 $ echo bah > s/a
308 $ echo bah > s/a
303 $ hg ci -m12
309 $ hg ci -m12
304 committing subrepository s
310 committing subrepository s
305 $ hg push
311 $ hg push
306 pushing to $TESTTMP/sub/t
312 pushing to $TESTTMP/sub/t
307 pushing subrepo s/ss to $TESTTMP/sub/t/s/ss
313 pushing subrepo s/ss to $TESTTMP/sub/t/s/ss
308 searching for changes
314 searching for changes
309 no changes found
315 no changes found
310 pushing subrepo s to $TESTTMP/sub/t/s
316 pushing subrepo s to $TESTTMP/sub/t/s
311 searching for changes
317 searching for changes
312 abort: push creates new remote head 12a213df6fa9!
318 abort: push creates new remote head 12a213df6fa9!
313 (did you forget to merge? use push -f to force)
319 (did you forget to merge? use push -f to force)
314 [255]
320 [255]
315 $ hg push -f
321 $ hg push -f
316 pushing to $TESTTMP/sub/t
322 pushing to $TESTTMP/sub/t
317 pushing subrepo s/ss to $TESTTMP/sub/t/s/ss
323 pushing subrepo s/ss to $TESTTMP/sub/t/s/ss
318 searching for changes
324 searching for changes
319 no changes found
325 no changes found
320 pushing subrepo s to $TESTTMP/sub/t/s
326 pushing subrepo s to $TESTTMP/sub/t/s
321 searching for changes
327 searching for changes
322 adding changesets
328 adding changesets
323 adding manifests
329 adding manifests
324 adding file changes
330 adding file changes
325 added 1 changesets with 1 changes to 1 files (+1 heads)
331 added 1 changesets with 1 changes to 1 files (+1 heads)
326 pushing subrepo t to $TESTTMP/sub/t/t
332 pushing subrepo t to $TESTTMP/sub/t/t
327 searching for changes
333 searching for changes
328 no changes found
334 no changes found
329 searching for changes
335 searching for changes
330 adding changesets
336 adding changesets
331 adding manifests
337 adding manifests
332 adding file changes
338 adding file changes
333 added 1 changesets with 1 changes to 1 files
339 added 1 changesets with 1 changes to 1 files
334
340
335 update
341 update
336
342
337 $ cd ../t
343 $ cd ../t
338 $ hg up -C # discard our earlier merge
344 $ hg up -C # discard our earlier merge
339 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
340 $ echo blah > t/t
346 $ echo blah > t/t
341 $ hg ci -m13
347 $ hg ci -m13
342 committing subrepository t
348 committing subrepository t
343
349
344 pull
350 pull
345
351
346 $ cd ../tc
352 $ cd ../tc
347 $ hg pull
353 $ hg pull
348 pulling from $TESTTMP/sub/t
354 pulling from $TESTTMP/sub/t
349 searching for changes
355 searching for changes
350 adding changesets
356 adding changesets
351 adding manifests
357 adding manifests
352 adding file changes
358 adding file changes
353 added 1 changesets with 1 changes to 1 files
359 added 1 changesets with 1 changes to 1 files
354 (run 'hg update' to get a working copy)
360 (run 'hg update' to get a working copy)
355
361
356 should pull t
362 should pull t
357
363
358 $ hg up
364 $ hg up
359 pulling subrepo t from $TESTTMP/sub/t/t
365 pulling subrepo t from $TESTTMP/sub/t/t
360 searching for changes
366 searching for changes
361 adding changesets
367 adding changesets
362 adding manifests
368 adding manifests
363 adding file changes
369 adding file changes
364 added 1 changesets with 1 changes to 1 files
370 added 1 changesets with 1 changes to 1 files
365 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
366 $ cat t/t
372 $ cat t/t
367 blah
373 blah
368
374
369 bogus subrepo path aborts
375 bogus subrepo path aborts
370
376
371 $ echo 'bogus=[boguspath' >> .hgsub
377 $ echo 'bogus=[boguspath' >> .hgsub
372 $ hg ci -m 'bogus subrepo path'
378 $ hg ci -m 'bogus subrepo path'
373 abort: missing ] in subrepo source
379 abort: missing ] in subrepo source
374 [255]
380 [255]
375
381
376 Issue1986: merge aborts when trying to merge a subrepo that
382 Issue1986: merge aborts when trying to merge a subrepo that
377 shouldn't need merging
383 shouldn't need merging
378
384
379 # subrepo layout
385 # subrepo layout
380 #
386 #
381 # o 5 br
387 # o 5 br
382 # /|
388 # /|
383 # o | 4 default
389 # o | 4 default
384 # | |
390 # | |
385 # | o 3 br
391 # | o 3 br
386 # |/|
392 # |/|
387 # o | 2 default
393 # o | 2 default
388 # | |
394 # | |
389 # | o 1 br
395 # | o 1 br
390 # |/
396 # |/
391 # o 0 default
397 # o 0 default
392
398
393 $ cd ..
399 $ cd ..
394 $ rm -rf sub
400 $ rm -rf sub
395 $ hg init main
401 $ hg init main
396 $ cd main
402 $ cd main
397 $ hg init s
403 $ hg init s
398 $ cd s
404 $ cd s
399 $ echo a > a
405 $ echo a > a
400 $ hg ci -Am1
406 $ hg ci -Am1
401 adding a
407 adding a
402 $ hg branch br
408 $ hg branch br
403 marked working directory as branch br
409 marked working directory as branch br
404 $ echo a >> a
410 $ echo a >> a
405 $ hg ci -m1
411 $ hg ci -m1
406 $ hg up default
412 $ hg up default
407 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
408 $ echo b > b
414 $ echo b > b
409 $ hg ci -Am1
415 $ hg ci -Am1
410 adding b
416 adding b
411 $ hg up br
417 $ hg up br
412 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
413 $ hg merge tip
419 $ hg merge tip
414 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
415 (branch merge, don't forget to commit)
421 (branch merge, don't forget to commit)
416 $ hg ci -m1
422 $ hg ci -m1
417 $ hg up 2
423 $ hg up 2
418 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
419 $ echo c > c
425 $ echo c > c
420 $ hg ci -Am1
426 $ hg ci -Am1
421 adding c
427 adding c
422 $ hg up 3
428 $ hg up 3
423 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
424 $ hg merge 4
430 $ hg merge 4
425 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
426 (branch merge, don't forget to commit)
432 (branch merge, don't forget to commit)
427 $ hg ci -m1
433 $ hg ci -m1
428
434
429 # main repo layout:
435 # main repo layout:
430 #
436 #
431 # * <-- try to merge default into br again
437 # * <-- try to merge default into br again
432 # .`|
438 # .`|
433 # . o 5 br --> substate = 5
439 # . o 5 br --> substate = 5
434 # . |
440 # . |
435 # o | 4 default --> substate = 4
441 # o | 4 default --> substate = 4
436 # | |
442 # | |
437 # | o 3 br --> substate = 2
443 # | o 3 br --> substate = 2
438 # |/|
444 # |/|
439 # o | 2 default --> substate = 2
445 # o | 2 default --> substate = 2
440 # | |
446 # | |
441 # | o 1 br --> substate = 3
447 # | o 1 br --> substate = 3
442 # |/
448 # |/
443 # o 0 default --> substate = 2
449 # o 0 default --> substate = 2
444
450
445 $ cd ..
451 $ cd ..
446 $ echo 's = s' > .hgsub
452 $ echo 's = s' > .hgsub
447 $ hg -R s up 2
453 $ hg -R s up 2
448 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
449 $ hg ci -Am1
455 $ hg ci -Am1
450 adding .hgsub
456 adding .hgsub
451 committing subrepository s
457 committing subrepository s
452 $ hg branch br
458 $ hg branch br
453 marked working directory as branch br
459 marked working directory as branch br
454 $ echo b > b
460 $ echo b > b
455 $ hg -R s up 3
461 $ hg -R s up 3
456 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
457 $ hg ci -Am1
463 $ hg ci -Am1
458 adding b
464 adding b
459 committing subrepository s
465 committing subrepository s
460 $ hg up default
466 $ hg up default
461 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
462 $ echo c > c
468 $ echo c > c
463 $ hg ci -Am1
469 $ hg ci -Am1
464 adding c
470 adding c
465 $ hg up 1
471 $ hg up 1
466 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
467 $ hg merge 2
473 $ hg merge 2
468 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
469 (branch merge, don't forget to commit)
475 (branch merge, don't forget to commit)
470 $ hg ci -m1
476 $ hg ci -m1
471 $ hg up 2
477 $ hg up 2
472 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
473 $ hg -R s up 4
479 $ hg -R s up 4
474 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
475 $ echo d > d
481 $ echo d > d
476 $ hg ci -Am1
482 $ hg ci -Am1
477 adding d
483 adding d
478 committing subrepository s
484 committing subrepository s
479 $ hg up 3
485 $ hg up 3
480 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
481 $ hg -R s up 5
487 $ hg -R s up 5
482 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
483 $ echo e > e
489 $ echo e > e
484 $ hg ci -Am1
490 $ hg ci -Am1
485 adding e
491 adding e
486 committing subrepository s
492 committing subrepository s
487
493
488 $ hg up 5
494 $ hg up 5
489 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
490 $ hg merge 4 # try to merge default into br again
496 $ hg merge 4 # try to merge default into br again
491 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
492 (branch merge, don't forget to commit)
498 (branch merge, don't forget to commit)
493 $ cd ..
499 $ cd ..
494
500
495 test subrepo delete from .hgsubstate
501 test subrepo delete from .hgsubstate
496
502
497 $ hg init testdelete
503 $ hg init testdelete
498 $ mkdir testdelete/nested testdelete/nested2
504 $ mkdir testdelete/nested testdelete/nested2
499 $ hg init testdelete/nested
505 $ hg init testdelete/nested
500 $ hg init testdelete/nested2
506 $ hg init testdelete/nested2
501 $ echo test > testdelete/nested/foo
507 $ echo test > testdelete/nested/foo
502 $ echo test > testdelete/nested2/foo
508 $ echo test > testdelete/nested2/foo
503 $ hg -R testdelete/nested add
509 $ hg -R testdelete/nested add
504 adding testdelete/nested/foo
510 adding testdelete/nested/foo
505 $ hg -R testdelete/nested2 add
511 $ hg -R testdelete/nested2 add
506 adding testdelete/nested2/foo
512 adding testdelete/nested2/foo
507 $ hg -R testdelete/nested ci -m test
513 $ hg -R testdelete/nested ci -m test
508 $ hg -R testdelete/nested2 ci -m test
514 $ hg -R testdelete/nested2 ci -m test
509 $ echo nested = nested > testdelete/.hgsub
515 $ echo nested = nested > testdelete/.hgsub
510 $ echo nested2 = nested2 >> testdelete/.hgsub
516 $ echo nested2 = nested2 >> testdelete/.hgsub
511 $ hg -R testdelete add
517 $ hg -R testdelete add
512 adding testdelete/.hgsub
518 adding testdelete/.hgsub
513 $ hg -R testdelete ci -m "nested 1 & 2 added"
519 $ hg -R testdelete ci -m "nested 1 & 2 added"
514 committing subrepository nested
520 committing subrepository nested
515 committing subrepository nested2
521 committing subrepository nested2
516 $ echo nested = nested > testdelete/.hgsub
522 $ echo nested = nested > testdelete/.hgsub
517 $ hg -R testdelete ci -m "nested 2 deleted"
523 $ hg -R testdelete ci -m "nested 2 deleted"
518 $ cat testdelete/.hgsubstate
524 $ cat testdelete/.hgsubstate
519 bdf5c9a3103743d900b12ae0db3ffdcfd7b0d878 nested
525 bdf5c9a3103743d900b12ae0db3ffdcfd7b0d878 nested
520 $ hg -R testdelete remove testdelete/.hgsub
526 $ hg -R testdelete remove testdelete/.hgsub
521 $ hg -R testdelete ci -m ".hgsub deleted"
527 $ hg -R testdelete ci -m ".hgsub deleted"
522 $ cat testdelete/.hgsubstate
528 $ cat testdelete/.hgsubstate
523 bdf5c9a3103743d900b12ae0db3ffdcfd7b0d878 nested
529 bdf5c9a3103743d900b12ae0db3ffdcfd7b0d878 nested
524
530
525 test repository cloning
531 test repository cloning
526
532
527 $ mkdir mercurial mercurial2
533 $ mkdir mercurial mercurial2
528 $ hg init nested_absolute
534 $ hg init nested_absolute
529 $ echo test > nested_absolute/foo
535 $ echo test > nested_absolute/foo
530 $ hg -R nested_absolute add
536 $ hg -R nested_absolute add
531 adding nested_absolute/foo
537 adding nested_absolute/foo
532 $ hg -R nested_absolute ci -mtest
538 $ hg -R nested_absolute ci -mtest
533 $ cd mercurial
539 $ cd mercurial
534 $ hg init nested_relative
540 $ hg init nested_relative
535 $ echo test2 > nested_relative/foo2
541 $ echo test2 > nested_relative/foo2
536 $ hg -R nested_relative add
542 $ hg -R nested_relative add
537 adding nested_relative/foo2
543 adding nested_relative/foo2
538 $ hg -R nested_relative ci -mtest2
544 $ hg -R nested_relative ci -mtest2
539 $ hg init main
545 $ hg init main
540 $ echo "nested_relative = ../nested_relative" > main/.hgsub
546 $ echo "nested_relative = ../nested_relative" > main/.hgsub
541 $ echo "nested_absolute = `pwd`/nested_absolute" >> main/.hgsub
547 $ echo "nested_absolute = `pwd`/nested_absolute" >> main/.hgsub
542 $ hg -R main add
548 $ hg -R main add
543 adding main/.hgsub
549 adding main/.hgsub
544 $ hg -R main ci -m "add subrepos"
550 $ hg -R main ci -m "add subrepos"
545 committing subrepository nested_absolute
551 committing subrepository nested_absolute
546 committing subrepository nested_relative
552 committing subrepository nested_relative
547 $ cd ..
553 $ cd ..
548 $ hg clone mercurial/main mercurial2/main
554 $ hg clone mercurial/main mercurial2/main
549 updating to branch default
555 updating to branch default
550 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
551 $ cat mercurial2/main/nested_absolute/.hg/hgrc \
557 $ cat mercurial2/main/nested_absolute/.hg/hgrc \
552 > mercurial2/main/nested_relative/.hg/hgrc
558 > mercurial2/main/nested_relative/.hg/hgrc
553 [paths]
559 [paths]
554 default = $TESTTMP/sub/mercurial/nested_absolute
560 default = $TESTTMP/sub/mercurial/nested_absolute
555 [paths]
561 [paths]
556 default = $TESTTMP/sub/mercurial/nested_relative
562 default = $TESTTMP/sub/mercurial/nested_relative
557 $ rm -rf mercurial mercurial2
563 $ rm -rf mercurial mercurial2
558
564
559 Issue1977: multirepo push should fail if subrepo push fails
565 Issue1977: multirepo push should fail if subrepo push fails
560
566
561 $ hg init repo
567 $ hg init repo
562 $ hg init repo/s
568 $ hg init repo/s
563 $ echo a > repo/s/a
569 $ echo a > repo/s/a
564 $ hg -R repo/s ci -Am0
570 $ hg -R repo/s ci -Am0
565 adding a
571 adding a
566 $ echo s = s > repo/.hgsub
572 $ echo s = s > repo/.hgsub
567 $ hg -R repo ci -Am1
573 $ hg -R repo ci -Am1
568 adding .hgsub
574 adding .hgsub
569 committing subrepository s
575 committing subrepository s
570 $ hg clone repo repo2
576 $ hg clone repo repo2
571 updating to branch default
577 updating to branch default
572 cloning subrepo s from $TESTTMP/sub/repo/s
578 cloning subrepo s from $TESTTMP/sub/repo/s
573 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
574 $ hg -q -R repo2 pull -u
580 $ hg -q -R repo2 pull -u
575 $ echo 1 > repo2/s/a
581 $ echo 1 > repo2/s/a
576 $ hg -R repo2/s ci -m2
582 $ hg -R repo2/s ci -m2
577 $ hg -q -R repo2/s push
583 $ hg -q -R repo2/s push
578 $ hg -R repo2/s up -C 0
584 $ hg -R repo2/s up -C 0
579 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
580 $ echo 2 > repo2/s/a
586 $ echo 2 > repo2/s/a
581 $ hg -R repo2/s ci -m3
587 $ hg -R repo2/s ci -m3
582 created new head
588 created new head
583 $ hg -R repo2 ci -m3
589 $ hg -R repo2 ci -m3
584 committing subrepository s
590 committing subrepository s
585 $ hg -q -R repo2 push
591 $ hg -q -R repo2 push
586 abort: push creates new remote head 9d66565e64e1!
592 abort: push creates new remote head 9d66565e64e1!
587 (did you forget to merge? use push -f to force)
593 (did you forget to merge? use push -f to force)
588 [255]
594 [255]
589 $ hg -R repo update
595 $ hg -R repo update
590 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
591 $ rm -rf repo2 repo
597 $ rm -rf repo2 repo
592
598
593
599
594 Issue1852 subrepos with relative paths always push/pull relative to default
600 Issue1852 subrepos with relative paths always push/pull relative to default
595
601
596 Prepare a repo with subrepo
602 Prepare a repo with subrepo
597
603
598 $ hg init issue1852a
604 $ hg init issue1852a
599 $ cd issue1852a
605 $ cd issue1852a
600 $ hg init sub/repo
606 $ hg init sub/repo
601 $ echo test > sub/repo/foo
607 $ echo test > sub/repo/foo
602 $ hg -R sub/repo add sub/repo/foo
608 $ hg -R sub/repo add sub/repo/foo
603 $ echo sub/repo = sub/repo > .hgsub
609 $ echo sub/repo = sub/repo > .hgsub
604 $ hg add .hgsub
610 $ hg add .hgsub
605 $ hg ci -mtest
611 $ hg ci -mtest
606 committing subrepository sub/repo
612 committing subrepository sub/repo
607 $ echo test >> sub/repo/foo
613 $ echo test >> sub/repo/foo
608 $ hg ci -mtest
614 $ hg ci -mtest
609 committing subrepository sub/repo
615 committing subrepository sub/repo
610 $ cd ..
616 $ cd ..
611
617
612 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
613
619
614 $ hg init issue1852b
620 $ hg init issue1852b
615 $ hg -R issue1852b pull issue1852a
621 $ hg -R issue1852b pull issue1852a
616 pulling from issue1852a
622 pulling from issue1852a
617 requesting all changes
623 requesting all changes
618 adding changesets
624 adding changesets
619 adding manifests
625 adding manifests
620 adding file changes
626 adding file changes
621 added 2 changesets with 3 changes to 2 files
627 added 2 changesets with 3 changes to 2 files
622 (run 'hg update' to get a working copy)
628 (run 'hg update' to get a working copy)
623 $ hg -R issue1852b update
629 $ hg -R issue1852b update
624 abort: default path for subrepository sub/repo not found
630 abort: default path for subrepository sub/repo not found
625 [255]
631 [255]
626
632
627 Pull -u now doesn't help
633 Pull -u now doesn't help
628
634
629 $ hg -R issue1852b pull -u issue1852a
635 $ hg -R issue1852b pull -u issue1852a
630 pulling from issue1852a
636 pulling from issue1852a
631 searching for changes
637 searching for changes
632 no changes found
638 no changes found
633
639
634 Try the same, but with pull -u
640 Try the same, but with pull -u
635
641
636 $ hg init issue1852c
642 $ hg init issue1852c
637 $ hg -R issue1852c pull -r0 -u issue1852a
643 $ hg -R issue1852c pull -r0 -u issue1852a
638 pulling from issue1852a
644 pulling from issue1852a
639 adding changesets
645 adding changesets
640 adding manifests
646 adding manifests
641 adding file changes
647 adding file changes
642 added 1 changesets with 2 changes to 2 files
648 added 1 changesets with 2 changes to 2 files
643 cloning subrepo sub/repo from issue1852a/sub/repo
649 cloning subrepo sub/repo from issue1852a/sub/repo
644 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
645
651
646 Try to push from the other side
652 Try to push from the other side
647
653
648 $ hg -R issue1852a push `pwd`/issue1852c
654 $ hg -R issue1852a push `pwd`/issue1852c
649 pushing to $TESTTMP/sub/issue1852c
655 pushing to $TESTTMP/sub/issue1852c
650 pushing subrepo sub/repo to $TESTTMP/sub/issue1852c/sub/repo
656 pushing subrepo sub/repo to $TESTTMP/sub/issue1852c/sub/repo
651 searching for changes
657 searching for changes
652 no changes found
658 no changes found
653 searching for changes
659 searching for changes
654 adding changesets
660 adding changesets
655 adding manifests
661 adding manifests
656 adding file changes
662 adding file changes
657 added 1 changesets with 1 changes to 1 files
663 added 1 changesets with 1 changes to 1 files
658
664
659 Incoming and outgoing should not use the default path:
665 Incoming and outgoing should not use the default path:
660
666
661 $ hg clone -q issue1852a issue1852d
667 $ hg clone -q issue1852a issue1852d
662 $ hg -R issue1852d outgoing --subrepos issue1852c
668 $ hg -R issue1852d outgoing --subrepos issue1852c
663 comparing with issue1852c
669 comparing with issue1852c
664 searching for changes
670 searching for changes
665 no changes found
671 no changes found
666 comparing with issue1852c/sub/repo
672 comparing with issue1852c/sub/repo
667 searching for changes
673 searching for changes
668 no changes found
674 no changes found
669 [1]
675 [1]
670 $ hg -R issue1852d incoming --subrepos issue1852c
676 $ hg -R issue1852d incoming --subrepos issue1852c
671 comparing with issue1852c
677 comparing with issue1852c
672 searching for changes
678 searching for changes
673 no changes found
679 no changes found
674 comparing with issue1852c/sub/repo
680 comparing with issue1852c/sub/repo
675 searching for changes
681 searching for changes
676 no changes found
682 no changes found
677 [1]
683 [1]
678
684
679 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
680 subrepository:
686 subrepository:
681
687
682 $ hg init subrepo-status
688 $ hg init subrepo-status
683 $ cd subrepo-status
689 $ cd subrepo-status
684 $ hg init subrepo-1
690 $ hg init subrepo-1
685 $ hg init subrepo-2
691 $ hg init subrepo-2
686 $ cd subrepo-2
692 $ cd subrepo-2
687 $ touch file
693 $ touch file
688 $ hg add file
694 $ hg add file
689 $ cd ..
695 $ cd ..
690 $ echo subrepo-1 = subrepo-1 > .hgsub
696 $ echo subrepo-1 = subrepo-1 > .hgsub
691 $ echo subrepo-2 = subrepo-2 >> .hgsub
697 $ echo subrepo-2 = subrepo-2 >> .hgsub
692 $ hg add .hgsub
698 $ hg add .hgsub
693 $ hg ci -m 'Added subrepos'
699 $ hg ci -m 'Added subrepos'
694 committing subrepository subrepo-1
700 committing subrepository subrepo-1
695 committing subrepository subrepo-2
701 committing subrepository subrepo-2
696 $ hg st subrepo-2/file
702 $ hg st subrepo-2/file
697
703
698 Check hg update --clean
704 Check hg update --clean
699 $ cd $TESTTMP/sub/t
705 $ cd $TESTTMP/sub/t
700 $ rm -r t/t.orig
706 $ rm -r t/t.orig
701 $ hg status -S --all
707 $ hg status -S --all
702 C .hgsub
708 C .hgsub
703 C .hgsubstate
709 C .hgsubstate
704 C a
710 C a
705 C s/.hgsub
711 C s/.hgsub
706 C s/.hgsubstate
712 C s/.hgsubstate
707 C s/a
713 C s/a
708 C s/ss/a
714 C s/ss/a
709 C t/t
715 C t/t
710 $ echo c1 > s/a
716 $ echo c1 > s/a
711 $ cd s
717 $ cd s
712 $ echo c1 > b
718 $ echo c1 > b
713 $ echo c1 > c
719 $ echo c1 > c
714 $ hg add b
720 $ hg add b
715 $ cd ..
721 $ cd ..
716 $ hg status -S
722 $ hg status -S
717 M s/a
723 M s/a
718 A s/b
724 A s/b
719 ? s/c
725 ? s/c
720 $ hg update -C
726 $ hg update -C
721 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
722 $ hg status -S
728 $ hg status -S
723 ? s/b
729 ? s/b
724 ? s/c
730 ? s/c
725
731
726 Sticky subrepositories, no changes
732 Sticky subrepositories, no changes
727 $ cd $TESTTMP/sub/t
733 $ cd $TESTTMP/sub/t
728 $ hg id
734 $ hg id
729 925c17564ef8 tip
735 925c17564ef8 tip
730 $ hg -R s id
736 $ hg -R s id
731 12a213df6fa9 tip
737 12a213df6fa9 tip
732 $ hg -R t id
738 $ hg -R t id
733 52c0adc0515a tip
739 52c0adc0515a tip
734 $ hg update 11
740 $ hg update 11
735 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
736 $ hg id
742 $ hg id
737 365661e5936a
743 365661e5936a
738 $ hg -R s id
744 $ hg -R s id
739 fc627a69481f
745 fc627a69481f
740 $ hg -R t id
746 $ hg -R t id
741 e95bcfa18a35
747 e95bcfa18a35
742
748
743 Sticky subrepositorys, file changes
749 Sticky subrepositorys, file changes
744 $ touch s/f1
750 $ touch s/f1
745 $ touch t/f1
751 $ touch t/f1
746 $ hg add -S s/f1
752 $ hg add -S s/f1
747 $ hg add -S t/f1
753 $ hg add -S t/f1
748 $ hg id
754 $ hg id
749 365661e5936a
755 365661e5936a
750 $ hg -R s id
756 $ hg -R s id
751 fc627a69481f+
757 fc627a69481f+
752 $ hg -R t id
758 $ hg -R t id
753 e95bcfa18a35+
759 e95bcfa18a35+
754 $ hg update tip
760 $ hg update tip
755 subrepository sources for s differ
761 subrepository sources for s differ
756 use (l)ocal source (fc627a69481f) or (r)emote source (12a213df6fa9)?
762 use (l)ocal source (fc627a69481f) or (r)emote source (12a213df6fa9)?
757 l
763 l
758 subrepository sources for t differ
764 subrepository sources for t differ
759 use (l)ocal source (e95bcfa18a35) or (r)emote source (52c0adc0515a)?
765 use (l)ocal source (e95bcfa18a35) or (r)emote source (52c0adc0515a)?
760 l
766 l
761 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
762 $ hg id
768 $ hg id
763 925c17564ef8+ tip
769 925c17564ef8+ tip
764 $ hg -R s id
770 $ hg -R s id
765 fc627a69481f+
771 fc627a69481f+
766 $ hg -R t id
772 $ hg -R t id
767 e95bcfa18a35+
773 e95bcfa18a35+
768 $ hg update --clean tip
774 $ hg update --clean tip
769 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
770
776
771 Sticky subrepository, revision updates
777 Sticky subrepository, revision updates
772 $ hg id
778 $ hg id
773 925c17564ef8 tip
779 925c17564ef8 tip
774 $ hg -R s id
780 $ hg -R s id
775 12a213df6fa9 tip
781 12a213df6fa9 tip
776 $ hg -R t id
782 $ hg -R t id
777 52c0adc0515a tip
783 52c0adc0515a tip
778 $ cd s
784 $ cd s
779 $ hg update -r -2
785 $ hg update -r -2
780 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
781 $ cd ../t
787 $ cd ../t
782 $ hg update -r 2
788 $ hg update -r 2
783 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
784 $ cd ..
790 $ cd ..
785 $ hg update 10
791 $ hg update 10
786 subrepository sources for t differ (in checked out version)
792 subrepository sources for t differ (in checked out version)
787 use (l)ocal source (7af322bc1198) or (r)emote source (20a0db6fbf6c)?
793 use (l)ocal source (7af322bc1198) or (r)emote source (20a0db6fbf6c)?
788 l
794 l
789 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
790 $ hg id
796 $ hg id
791 e45c8b14af55+
797 e45c8b14af55+
792 $ hg -R s id
798 $ hg -R s id
793 1c833a7a9e3a
799 1c833a7a9e3a
794 $ hg -R t id
800 $ hg -R t id
795 7af322bc1198
801 7af322bc1198
796
802
797 Sticky subrepository, file changes and revision updates
803 Sticky subrepository, file changes and revision updates
798 $ touch s/f1
804 $ touch s/f1
799 $ touch t/f1
805 $ touch t/f1
800 $ hg add -S s/f1
806 $ hg add -S s/f1
801 $ hg add -S t/f1
807 $ hg add -S t/f1
802 $ hg id
808 $ hg id
803 e45c8b14af55+
809 e45c8b14af55+
804 $ hg -R s id
810 $ hg -R s id
805 1c833a7a9e3a+
811 1c833a7a9e3a+
806 $ hg -R t id
812 $ hg -R t id
807 7af322bc1198+
813 7af322bc1198+
808 $ hg update tip
814 $ hg update tip
809 subrepository sources for s differ
815 subrepository sources for s differ
810 use (l)ocal source (1c833a7a9e3a) or (r)emote source (12a213df6fa9)?
816 use (l)ocal source (1c833a7a9e3a) or (r)emote source (12a213df6fa9)?
811 l
817 l
812 subrepository sources for t differ
818 subrepository sources for t differ
813 use (l)ocal source (7af322bc1198) or (r)emote source (52c0adc0515a)?
819 use (l)ocal source (7af322bc1198) or (r)emote source (52c0adc0515a)?
814 l
820 l
815 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
816 $ hg id
822 $ hg id
817 925c17564ef8 tip
823 925c17564ef8 tip
818 $ hg -R s id
824 $ hg -R s id
819 1c833a7a9e3a+
825 1c833a7a9e3a+
820 $ hg -R t id
826 $ hg -R t id
821 7af322bc1198+
827 7af322bc1198+
822
828
823 Sticky repository, update --clean
829 Sticky repository, update --clean
824 $ hg update --clean tip
830 $ hg update --clean tip
825 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
826 $ hg id
832 $ hg id
827 925c17564ef8 tip
833 925c17564ef8 tip
828 $ hg -R s id
834 $ hg -R s id
829 12a213df6fa9 tip
835 12a213df6fa9 tip
830 $ hg -R t id
836 $ hg -R t id
831 52c0adc0515a tip
837 52c0adc0515a tip
832
838
833 Test subrepo already at intended revision:
839 Test subrepo already at intended revision:
834 $ cd s
840 $ cd s
835 $ hg update fc627a69481f
841 $ hg update fc627a69481f
836 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
837 $ cd ..
843 $ cd ..
838 $ hg update 11
844 $ hg update 11
839 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
840 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
841 $ hg id -n
847 $ hg id -n
842 11+
848 11+
843 $ hg -R s id
849 $ hg -R s id
844 fc627a69481f
850 fc627a69481f
845 $ hg -R t id
851 $ hg -R t id
846 e95bcfa18a35
852 e95bcfa18a35
847
853
848 Test that removing .hgsubstate doesn't break anything:
854 Test that removing .hgsubstate doesn't break anything:
849
855
850 $ hg rm -f .hgsubstate
856 $ hg rm -f .hgsubstate
851 $ hg ci -mrm
857 $ hg ci -mrm
852 committing subrepository s
858 committing subrepository s
853 committing subrepository t
859 committing subrepository t
854 created new head
860 created new head
855 $ hg log -vr tip
861 $ hg log -vr tip
856 changeset: 14:3941e0aa5236
862 changeset: 14:3941e0aa5236
857 tag: tip
863 tag: tip
858 parent: 11:365661e5936a
864 parent: 11:365661e5936a
859 user: test
865 user: test
860 date: Thu Jan 01 00:00:00 1970 +0000
866 date: Thu Jan 01 00:00:00 1970 +0000
861 description:
867 description:
862 rm
868 rm
863
869
864
870
865
871
866 Test that removing .hgsub removes .hgsubstate:
872 Test that removing .hgsub removes .hgsubstate:
867
873
868 $ hg rm .hgsub
874 $ hg rm .hgsub
869 $ hg ci -mrm2
875 $ hg ci -mrm2
870 $ hg log -vr tip
876 $ hg log -vr tip
871 changeset: 15:8b31de9d13d1
877 changeset: 15:8b31de9d13d1
872 tag: tip
878 tag: tip
873 user: test
879 user: test
874 date: Thu Jan 01 00:00:00 1970 +0000
880 date: Thu Jan 01 00:00:00 1970 +0000
875 files: .hgsub .hgsubstate
881 files: .hgsub .hgsubstate
876 description:
882 description:
877 rm2
883 rm2
878
884
879
885
General Comments 0
You need to be logged in to leave comments. Login now