##// END OF EJS Templates
commands: advance current active bookmark at pull --update correctly...
FUJIWARA Katsunori -
r27948:7cb7264c stable
parent child Browse files
Show More
@@ -1,7038 +1,7040 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, nullhex, nullid, nullrev, short
8 from node import hex, bin, nullhex, nullid, nullrev, short
9 from lock import release
9 from lock import release
10 from i18n import _
10 from i18n import _
11 import os, re, difflib, time, tempfile, errno, shlex
11 import os, re, difflib, time, tempfile, errno, shlex
12 import sys, socket
12 import sys, socket
13 import hg, scmutil, util, revlog, copies, error, bookmarks
13 import hg, scmutil, util, revlog, copies, error, bookmarks
14 import patch, help, encoding, templatekw, discovery
14 import patch, help, encoding, templatekw, discovery
15 import archival, changegroup, cmdutil, hbisect
15 import archival, changegroup, cmdutil, hbisect
16 import sshserver, hgweb
16 import sshserver, hgweb
17 import extensions
17 import extensions
18 import merge as mergemod
18 import merge as mergemod
19 import minirst, revset, fileset
19 import minirst, revset, fileset
20 import dagparser, context, simplemerge, graphmod, copies
20 import dagparser, context, simplemerge, graphmod, copies
21 import random, operator
21 import random, operator
22 import setdiscovery, treediscovery, dagutil, pvec, localrepo, destutil
22 import setdiscovery, treediscovery, dagutil, pvec, localrepo, destutil
23 import phases, obsolete, exchange, bundle2, repair, lock as lockmod
23 import phases, obsolete, exchange, bundle2, repair, lock as lockmod
24 import ui as uimod
24 import ui as uimod
25 import streamclone
25 import streamclone
26 import commandserver
26 import commandserver
27
27
28 table = {}
28 table = {}
29
29
30 command = cmdutil.command(table)
30 command = cmdutil.command(table)
31
31
32 # Space delimited list of commands that don't require local repositories.
32 # Space delimited list of commands that don't require local repositories.
33 # This should be populated by passing norepo=True into the @command decorator.
33 # This should be populated by passing norepo=True into the @command decorator.
34 norepo = ''
34 norepo = ''
35 # Space delimited list of commands that optionally require local repositories.
35 # Space delimited list of commands that optionally require local repositories.
36 # This should be populated by passing optionalrepo=True into the @command
36 # This should be populated by passing optionalrepo=True into the @command
37 # decorator.
37 # decorator.
38 optionalrepo = ''
38 optionalrepo = ''
39 # Space delimited list of commands that will examine arguments looking for
39 # Space delimited list of commands that will examine arguments looking for
40 # a repository. This should be populated by passing inferrepo=True into the
40 # a repository. This should be populated by passing inferrepo=True into the
41 # @command decorator.
41 # @command decorator.
42 inferrepo = ''
42 inferrepo = ''
43
43
44 # label constants
44 # label constants
45 # until 3.5, bookmarks.current was the advertised name, not
45 # until 3.5, bookmarks.current was the advertised name, not
46 # bookmarks.active, so we must use both to avoid breaking old
46 # bookmarks.active, so we must use both to avoid breaking old
47 # custom styles
47 # custom styles
48 activebookmarklabel = 'bookmarks.active bookmarks.current'
48 activebookmarklabel = 'bookmarks.active bookmarks.current'
49
49
50 # common command options
50 # common command options
51
51
52 globalopts = [
52 globalopts = [
53 ('R', 'repository', '',
53 ('R', 'repository', '',
54 _('repository root directory or name of overlay bundle file'),
54 _('repository root directory or name of overlay bundle file'),
55 _('REPO')),
55 _('REPO')),
56 ('', 'cwd', '',
56 ('', 'cwd', '',
57 _('change working directory'), _('DIR')),
57 _('change working directory'), _('DIR')),
58 ('y', 'noninteractive', None,
58 ('y', 'noninteractive', None,
59 _('do not prompt, automatically pick the first choice for all prompts')),
59 _('do not prompt, automatically pick the first choice for all prompts')),
60 ('q', 'quiet', None, _('suppress output')),
60 ('q', 'quiet', None, _('suppress output')),
61 ('v', 'verbose', None, _('enable additional output')),
61 ('v', 'verbose', None, _('enable additional output')),
62 ('', 'config', [],
62 ('', 'config', [],
63 _('set/override config option (use \'section.name=value\')'),
63 _('set/override config option (use \'section.name=value\')'),
64 _('CONFIG')),
64 _('CONFIG')),
65 ('', 'debug', None, _('enable debugging output')),
65 ('', 'debug', None, _('enable debugging output')),
66 ('', 'debugger', None, _('start debugger')),
66 ('', 'debugger', None, _('start debugger')),
67 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
67 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
68 _('ENCODE')),
68 _('ENCODE')),
69 ('', 'encodingmode', encoding.encodingmode,
69 ('', 'encodingmode', encoding.encodingmode,
70 _('set the charset encoding mode'), _('MODE')),
70 _('set the charset encoding mode'), _('MODE')),
71 ('', 'traceback', None, _('always print a traceback on exception')),
71 ('', 'traceback', None, _('always print a traceback on exception')),
72 ('', 'time', None, _('time how long the command takes')),
72 ('', 'time', None, _('time how long the command takes')),
73 ('', 'profile', None, _('print command execution profile')),
73 ('', 'profile', None, _('print command execution profile')),
74 ('', 'version', None, _('output version information and exit')),
74 ('', 'version', None, _('output version information and exit')),
75 ('h', 'help', None, _('display help and exit')),
75 ('h', 'help', None, _('display help and exit')),
76 ('', 'hidden', False, _('consider hidden changesets')),
76 ('', 'hidden', False, _('consider hidden changesets')),
77 ]
77 ]
78
78
79 dryrunopts = [('n', 'dry-run', None,
79 dryrunopts = [('n', 'dry-run', None,
80 _('do not perform actions, just print output'))]
80 _('do not perform actions, just print output'))]
81
81
82 remoteopts = [
82 remoteopts = [
83 ('e', 'ssh', '',
83 ('e', 'ssh', '',
84 _('specify ssh command to use'), _('CMD')),
84 _('specify ssh command to use'), _('CMD')),
85 ('', 'remotecmd', '',
85 ('', 'remotecmd', '',
86 _('specify hg command to run on the remote side'), _('CMD')),
86 _('specify hg command to run on the remote side'), _('CMD')),
87 ('', 'insecure', None,
87 ('', 'insecure', None,
88 _('do not verify server certificate (ignoring web.cacerts config)')),
88 _('do not verify server certificate (ignoring web.cacerts config)')),
89 ]
89 ]
90
90
91 walkopts = [
91 walkopts = [
92 ('I', 'include', [],
92 ('I', 'include', [],
93 _('include names matching the given patterns'), _('PATTERN')),
93 _('include names matching the given patterns'), _('PATTERN')),
94 ('X', 'exclude', [],
94 ('X', 'exclude', [],
95 _('exclude names matching the given patterns'), _('PATTERN')),
95 _('exclude names matching the given patterns'), _('PATTERN')),
96 ]
96 ]
97
97
98 commitopts = [
98 commitopts = [
99 ('m', 'message', '',
99 ('m', 'message', '',
100 _('use text as commit message'), _('TEXT')),
100 _('use text as commit message'), _('TEXT')),
101 ('l', 'logfile', '',
101 ('l', 'logfile', '',
102 _('read commit message from file'), _('FILE')),
102 _('read commit message from file'), _('FILE')),
103 ]
103 ]
104
104
105 commitopts2 = [
105 commitopts2 = [
106 ('d', 'date', '',
106 ('d', 'date', '',
107 _('record the specified date as commit date'), _('DATE')),
107 _('record the specified date as commit date'), _('DATE')),
108 ('u', 'user', '',
108 ('u', 'user', '',
109 _('record the specified user as committer'), _('USER')),
109 _('record the specified user as committer'), _('USER')),
110 ]
110 ]
111
111
112 # hidden for now
112 # hidden for now
113 formatteropts = [
113 formatteropts = [
114 ('T', 'template', '',
114 ('T', 'template', '',
115 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
115 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
116 ]
116 ]
117
117
118 templateopts = [
118 templateopts = [
119 ('', 'style', '',
119 ('', 'style', '',
120 _('display using template map file (DEPRECATED)'), _('STYLE')),
120 _('display using template map file (DEPRECATED)'), _('STYLE')),
121 ('T', 'template', '',
121 ('T', 'template', '',
122 _('display with template'), _('TEMPLATE')),
122 _('display with template'), _('TEMPLATE')),
123 ]
123 ]
124
124
125 logopts = [
125 logopts = [
126 ('p', 'patch', None, _('show patch')),
126 ('p', 'patch', None, _('show patch')),
127 ('g', 'git', None, _('use git extended diff format')),
127 ('g', 'git', None, _('use git extended diff format')),
128 ('l', 'limit', '',
128 ('l', 'limit', '',
129 _('limit number of changes displayed'), _('NUM')),
129 _('limit number of changes displayed'), _('NUM')),
130 ('M', 'no-merges', None, _('do not show merges')),
130 ('M', 'no-merges', None, _('do not show merges')),
131 ('', 'stat', None, _('output diffstat-style summary of changes')),
131 ('', 'stat', None, _('output diffstat-style summary of changes')),
132 ('G', 'graph', None, _("show the revision DAG")),
132 ('G', 'graph', None, _("show the revision DAG")),
133 ] + templateopts
133 ] + templateopts
134
134
135 diffopts = [
135 diffopts = [
136 ('a', 'text', None, _('treat all files as text')),
136 ('a', 'text', None, _('treat all files as text')),
137 ('g', 'git', None, _('use git extended diff format')),
137 ('g', 'git', None, _('use git extended diff format')),
138 ('', 'nodates', None, _('omit dates from diff headers'))
138 ('', 'nodates', None, _('omit dates from diff headers'))
139 ]
139 ]
140
140
141 diffwsopts = [
141 diffwsopts = [
142 ('w', 'ignore-all-space', None,
142 ('w', 'ignore-all-space', None,
143 _('ignore white space when comparing lines')),
143 _('ignore white space when comparing lines')),
144 ('b', 'ignore-space-change', None,
144 ('b', 'ignore-space-change', None,
145 _('ignore changes in the amount of white space')),
145 _('ignore changes in the amount of white space')),
146 ('B', 'ignore-blank-lines', None,
146 ('B', 'ignore-blank-lines', None,
147 _('ignore changes whose lines are all blank')),
147 _('ignore changes whose lines are all blank')),
148 ]
148 ]
149
149
150 diffopts2 = [
150 diffopts2 = [
151 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
151 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
152 ('p', 'show-function', None, _('show which function each change is in')),
152 ('p', 'show-function', None, _('show which function each change is in')),
153 ('', 'reverse', None, _('produce a diff that undoes the changes')),
153 ('', 'reverse', None, _('produce a diff that undoes the changes')),
154 ] + diffwsopts + [
154 ] + diffwsopts + [
155 ('U', 'unified', '',
155 ('U', 'unified', '',
156 _('number of lines of context to show'), _('NUM')),
156 _('number of lines of context to show'), _('NUM')),
157 ('', 'stat', None, _('output diffstat-style summary of changes')),
157 ('', 'stat', None, _('output diffstat-style summary of changes')),
158 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
158 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
159 ]
159 ]
160
160
161 mergetoolopts = [
161 mergetoolopts = [
162 ('t', 'tool', '', _('specify merge tool')),
162 ('t', 'tool', '', _('specify merge tool')),
163 ]
163 ]
164
164
165 similarityopts = [
165 similarityopts = [
166 ('s', 'similarity', '',
166 ('s', 'similarity', '',
167 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
167 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
168 ]
168 ]
169
169
170 subrepoopts = [
170 subrepoopts = [
171 ('S', 'subrepos', None,
171 ('S', 'subrepos', None,
172 _('recurse into subrepositories'))
172 _('recurse into subrepositories'))
173 ]
173 ]
174
174
175 debugrevlogopts = [
175 debugrevlogopts = [
176 ('c', 'changelog', False, _('open changelog')),
176 ('c', 'changelog', False, _('open changelog')),
177 ('m', 'manifest', False, _('open manifest')),
177 ('m', 'manifest', False, _('open manifest')),
178 ('', 'dir', False, _('open directory manifest')),
178 ('', 'dir', False, _('open directory manifest')),
179 ]
179 ]
180
180
181 # Commands start here, listed alphabetically
181 # Commands start here, listed alphabetically
182
182
183 @command('^add',
183 @command('^add',
184 walkopts + subrepoopts + dryrunopts,
184 walkopts + subrepoopts + dryrunopts,
185 _('[OPTION]... [FILE]...'),
185 _('[OPTION]... [FILE]...'),
186 inferrepo=True)
186 inferrepo=True)
187 def add(ui, repo, *pats, **opts):
187 def add(ui, repo, *pats, **opts):
188 """add the specified files on the next commit
188 """add the specified files on the next commit
189
189
190 Schedule files to be version controlled and added to the
190 Schedule files to be version controlled and added to the
191 repository.
191 repository.
192
192
193 The files will be added to the repository at the next commit. To
193 The files will be added to the repository at the next commit. To
194 undo an add before that, see :hg:`forget`.
194 undo an add before that, see :hg:`forget`.
195
195
196 If no names are given, add all files to the repository (except
196 If no names are given, add all files to the repository (except
197 files matching ``.hgignore``).
197 files matching ``.hgignore``).
198
198
199 .. container:: verbose
199 .. container:: verbose
200
200
201 Examples:
201 Examples:
202
202
203 - New (unknown) files are added
203 - New (unknown) files are added
204 automatically by :hg:`add`::
204 automatically by :hg:`add`::
205
205
206 $ ls
206 $ ls
207 foo.c
207 foo.c
208 $ hg status
208 $ hg status
209 ? foo.c
209 ? foo.c
210 $ hg add
210 $ hg add
211 adding foo.c
211 adding foo.c
212 $ hg status
212 $ hg status
213 A foo.c
213 A foo.c
214
214
215 - Specific files to be added can be specified::
215 - Specific files to be added can be specified::
216
216
217 $ ls
217 $ ls
218 bar.c foo.c
218 bar.c foo.c
219 $ hg status
219 $ hg status
220 ? bar.c
220 ? bar.c
221 ? foo.c
221 ? foo.c
222 $ hg add bar.c
222 $ hg add bar.c
223 $ hg status
223 $ hg status
224 A bar.c
224 A bar.c
225 ? foo.c
225 ? foo.c
226
226
227 Returns 0 if all files are successfully added.
227 Returns 0 if all files are successfully added.
228 """
228 """
229
229
230 m = scmutil.match(repo[None], pats, opts)
230 m = scmutil.match(repo[None], pats, opts)
231 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
231 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
232 return rejected and 1 or 0
232 return rejected and 1 or 0
233
233
234 @command('addremove',
234 @command('addremove',
235 similarityopts + subrepoopts + walkopts + dryrunopts,
235 similarityopts + subrepoopts + walkopts + dryrunopts,
236 _('[OPTION]... [FILE]...'),
236 _('[OPTION]... [FILE]...'),
237 inferrepo=True)
237 inferrepo=True)
238 def addremove(ui, repo, *pats, **opts):
238 def addremove(ui, repo, *pats, **opts):
239 """add all new files, delete all missing files
239 """add all new files, delete all missing files
240
240
241 Add all new files and remove all missing files from the
241 Add all new files and remove all missing files from the
242 repository.
242 repository.
243
243
244 Unless names are given, new files are ignored if they match any of
244 Unless names are given, new files are ignored if they match any of
245 the patterns in ``.hgignore``. As with add, these changes take
245 the patterns in ``.hgignore``. As with add, these changes take
246 effect at the next commit.
246 effect at the next commit.
247
247
248 Use the -s/--similarity option to detect renamed files. This
248 Use the -s/--similarity option to detect renamed files. This
249 option takes a percentage between 0 (disabled) and 100 (files must
249 option takes a percentage between 0 (disabled) and 100 (files must
250 be identical) as its parameter. With a parameter greater than 0,
250 be identical) as its parameter. With a parameter greater than 0,
251 this compares every removed file with every added file and records
251 this compares every removed file with every added file and records
252 those similar enough as renames. Detecting renamed files this way
252 those similar enough as renames. Detecting renamed files this way
253 can be expensive. After using this option, :hg:`status -C` can be
253 can be expensive. After using this option, :hg:`status -C` can be
254 used to check which files were identified as moved or renamed. If
254 used to check which files were identified as moved or renamed. If
255 not specified, -s/--similarity defaults to 100 and only renames of
255 not specified, -s/--similarity defaults to 100 and only renames of
256 identical files are detected.
256 identical files are detected.
257
257
258 .. container:: verbose
258 .. container:: verbose
259
259
260 Examples:
260 Examples:
261
261
262 - A number of files (bar.c and foo.c) are new,
262 - A number of files (bar.c and foo.c) are new,
263 while foobar.c has been removed (without using :hg:`remove`)
263 while foobar.c has been removed (without using :hg:`remove`)
264 from the repository::
264 from the repository::
265
265
266 $ ls
266 $ ls
267 bar.c foo.c
267 bar.c foo.c
268 $ hg status
268 $ hg status
269 ! foobar.c
269 ! foobar.c
270 ? bar.c
270 ? bar.c
271 ? foo.c
271 ? foo.c
272 $ hg addremove
272 $ hg addremove
273 adding bar.c
273 adding bar.c
274 adding foo.c
274 adding foo.c
275 removing foobar.c
275 removing foobar.c
276 $ hg status
276 $ hg status
277 A bar.c
277 A bar.c
278 A foo.c
278 A foo.c
279 R foobar.c
279 R foobar.c
280
280
281 - A file foobar.c was moved to foo.c without using :hg:`rename`.
281 - A file foobar.c was moved to foo.c without using :hg:`rename`.
282 Afterwards, it was edited slightly::
282 Afterwards, it was edited slightly::
283
283
284 $ ls
284 $ ls
285 foo.c
285 foo.c
286 $ hg status
286 $ hg status
287 ! foobar.c
287 ! foobar.c
288 ? foo.c
288 ? foo.c
289 $ hg addremove --similarity 90
289 $ hg addremove --similarity 90
290 removing foobar.c
290 removing foobar.c
291 adding foo.c
291 adding foo.c
292 recording removal of foobar.c as rename to foo.c (94% similar)
292 recording removal of foobar.c as rename to foo.c (94% similar)
293 $ hg status -C
293 $ hg status -C
294 A foo.c
294 A foo.c
295 foobar.c
295 foobar.c
296 R foobar.c
296 R foobar.c
297
297
298 Returns 0 if all files are successfully added.
298 Returns 0 if all files are successfully added.
299 """
299 """
300 try:
300 try:
301 sim = float(opts.get('similarity') or 100)
301 sim = float(opts.get('similarity') or 100)
302 except ValueError:
302 except ValueError:
303 raise error.Abort(_('similarity must be a number'))
303 raise error.Abort(_('similarity must be a number'))
304 if sim < 0 or sim > 100:
304 if sim < 0 or sim > 100:
305 raise error.Abort(_('similarity must be between 0 and 100'))
305 raise error.Abort(_('similarity must be between 0 and 100'))
306 matcher = scmutil.match(repo[None], pats, opts)
306 matcher = scmutil.match(repo[None], pats, opts)
307 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
307 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
308
308
309 @command('^annotate|blame',
309 @command('^annotate|blame',
310 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
310 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
311 ('', 'follow', None,
311 ('', 'follow', None,
312 _('follow copies/renames and list the filename (DEPRECATED)')),
312 _('follow copies/renames and list the filename (DEPRECATED)')),
313 ('', 'no-follow', None, _("don't follow copies and renames")),
313 ('', 'no-follow', None, _("don't follow copies and renames")),
314 ('a', 'text', None, _('treat all files as text')),
314 ('a', 'text', None, _('treat all files as text')),
315 ('u', 'user', None, _('list the author (long with -v)')),
315 ('u', 'user', None, _('list the author (long with -v)')),
316 ('f', 'file', None, _('list the filename')),
316 ('f', 'file', None, _('list the filename')),
317 ('d', 'date', None, _('list the date (short with -q)')),
317 ('d', 'date', None, _('list the date (short with -q)')),
318 ('n', 'number', None, _('list the revision number (default)')),
318 ('n', 'number', None, _('list the revision number (default)')),
319 ('c', 'changeset', None, _('list the changeset')),
319 ('c', 'changeset', None, _('list the changeset')),
320 ('l', 'line-number', None, _('show line number at the first appearance'))
320 ('l', 'line-number', None, _('show line number at the first appearance'))
321 ] + diffwsopts + walkopts + formatteropts,
321 ] + diffwsopts + walkopts + formatteropts,
322 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
322 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
323 inferrepo=True)
323 inferrepo=True)
324 def annotate(ui, repo, *pats, **opts):
324 def annotate(ui, repo, *pats, **opts):
325 """show changeset information by line for each file
325 """show changeset information by line for each file
326
326
327 List changes in files, showing the revision id responsible for
327 List changes in files, showing the revision id responsible for
328 each line.
328 each line.
329
329
330 This command is useful for discovering when a change was made and
330 This command is useful for discovering when a change was made and
331 by whom.
331 by whom.
332
332
333 If you include --file, --user, or --date, the revision number is
333 If you include --file, --user, or --date, the revision number is
334 suppressed unless you also include --number.
334 suppressed unless you also include --number.
335
335
336 Without the -a/--text option, annotate will avoid processing files
336 Without the -a/--text option, annotate will avoid processing files
337 it detects as binary. With -a, annotate will annotate the file
337 it detects as binary. With -a, annotate will annotate the file
338 anyway, although the results will probably be neither useful
338 anyway, although the results will probably be neither useful
339 nor desirable.
339 nor desirable.
340
340
341 Returns 0 on success.
341 Returns 0 on success.
342 """
342 """
343 if not pats:
343 if not pats:
344 raise error.Abort(_('at least one filename or pattern is required'))
344 raise error.Abort(_('at least one filename or pattern is required'))
345
345
346 if opts.get('follow'):
346 if opts.get('follow'):
347 # --follow is deprecated and now just an alias for -f/--file
347 # --follow is deprecated and now just an alias for -f/--file
348 # to mimic the behavior of Mercurial before version 1.5
348 # to mimic the behavior of Mercurial before version 1.5
349 opts['file'] = True
349 opts['file'] = True
350
350
351 ctx = scmutil.revsingle(repo, opts.get('rev'))
351 ctx = scmutil.revsingle(repo, opts.get('rev'))
352
352
353 fm = ui.formatter('annotate', opts)
353 fm = ui.formatter('annotate', opts)
354 if ui.quiet:
354 if ui.quiet:
355 datefunc = util.shortdate
355 datefunc = util.shortdate
356 else:
356 else:
357 datefunc = util.datestr
357 datefunc = util.datestr
358 if ctx.rev() is None:
358 if ctx.rev() is None:
359 def hexfn(node):
359 def hexfn(node):
360 if node is None:
360 if node is None:
361 return None
361 return None
362 else:
362 else:
363 return fm.hexfunc(node)
363 return fm.hexfunc(node)
364 if opts.get('changeset'):
364 if opts.get('changeset'):
365 # omit "+" suffix which is appended to node hex
365 # omit "+" suffix which is appended to node hex
366 def formatrev(rev):
366 def formatrev(rev):
367 if rev is None:
367 if rev is None:
368 return '%d' % ctx.p1().rev()
368 return '%d' % ctx.p1().rev()
369 else:
369 else:
370 return '%d' % rev
370 return '%d' % rev
371 else:
371 else:
372 def formatrev(rev):
372 def formatrev(rev):
373 if rev is None:
373 if rev is None:
374 return '%d+' % ctx.p1().rev()
374 return '%d+' % ctx.p1().rev()
375 else:
375 else:
376 return '%d ' % rev
376 return '%d ' % rev
377 def formathex(hex):
377 def formathex(hex):
378 if hex is None:
378 if hex is None:
379 return '%s+' % fm.hexfunc(ctx.p1().node())
379 return '%s+' % fm.hexfunc(ctx.p1().node())
380 else:
380 else:
381 return '%s ' % hex
381 return '%s ' % hex
382 else:
382 else:
383 hexfn = fm.hexfunc
383 hexfn = fm.hexfunc
384 formatrev = formathex = str
384 formatrev = formathex = str
385
385
386 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
386 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
387 ('number', ' ', lambda x: x[0].rev(), formatrev),
387 ('number', ' ', lambda x: x[0].rev(), formatrev),
388 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
388 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
389 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
389 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
390 ('file', ' ', lambda x: x[0].path(), str),
390 ('file', ' ', lambda x: x[0].path(), str),
391 ('line_number', ':', lambda x: x[1], str),
391 ('line_number', ':', lambda x: x[1], str),
392 ]
392 ]
393 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
393 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
394
394
395 if (not opts.get('user') and not opts.get('changeset')
395 if (not opts.get('user') and not opts.get('changeset')
396 and not opts.get('date') and not opts.get('file')):
396 and not opts.get('date') and not opts.get('file')):
397 opts['number'] = True
397 opts['number'] = True
398
398
399 linenumber = opts.get('line_number') is not None
399 linenumber = opts.get('line_number') is not None
400 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
400 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
401 raise error.Abort(_('at least one of -n/-c is required for -l'))
401 raise error.Abort(_('at least one of -n/-c is required for -l'))
402
402
403 if fm:
403 if fm:
404 def makefunc(get, fmt):
404 def makefunc(get, fmt):
405 return get
405 return get
406 else:
406 else:
407 def makefunc(get, fmt):
407 def makefunc(get, fmt):
408 return lambda x: fmt(get(x))
408 return lambda x: fmt(get(x))
409 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
409 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
410 if opts.get(op)]
410 if opts.get(op)]
411 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
411 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
412 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
412 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
413 if opts.get(op))
413 if opts.get(op))
414
414
415 def bad(x, y):
415 def bad(x, y):
416 raise error.Abort("%s: %s" % (x, y))
416 raise error.Abort("%s: %s" % (x, y))
417
417
418 m = scmutil.match(ctx, pats, opts, badfn=bad)
418 m = scmutil.match(ctx, pats, opts, badfn=bad)
419
419
420 follow = not opts.get('no_follow')
420 follow = not opts.get('no_follow')
421 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
421 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
422 whitespace=True)
422 whitespace=True)
423 for abs in ctx.walk(m):
423 for abs in ctx.walk(m):
424 fctx = ctx[abs]
424 fctx = ctx[abs]
425 if not opts.get('text') and util.binary(fctx.data()):
425 if not opts.get('text') and util.binary(fctx.data()):
426 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
426 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
427 continue
427 continue
428
428
429 lines = fctx.annotate(follow=follow, linenumber=linenumber,
429 lines = fctx.annotate(follow=follow, linenumber=linenumber,
430 diffopts=diffopts)
430 diffopts=diffopts)
431 formats = []
431 formats = []
432 pieces = []
432 pieces = []
433
433
434 for f, sep in funcmap:
434 for f, sep in funcmap:
435 l = [f(n) for n, dummy in lines]
435 l = [f(n) for n, dummy in lines]
436 if l:
436 if l:
437 if fm:
437 if fm:
438 formats.append(['%s' for x in l])
438 formats.append(['%s' for x in l])
439 else:
439 else:
440 sizes = [encoding.colwidth(x) for x in l]
440 sizes = [encoding.colwidth(x) for x in l]
441 ml = max(sizes)
441 ml = max(sizes)
442 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
442 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
443 pieces.append(l)
443 pieces.append(l)
444
444
445 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
445 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
446 fm.startitem()
446 fm.startitem()
447 fm.write(fields, "".join(f), *p)
447 fm.write(fields, "".join(f), *p)
448 fm.write('line', ": %s", l[1])
448 fm.write('line', ": %s", l[1])
449
449
450 if lines and not lines[-1][1].endswith('\n'):
450 if lines and not lines[-1][1].endswith('\n'):
451 fm.plain('\n')
451 fm.plain('\n')
452
452
453 fm.end()
453 fm.end()
454
454
455 @command('archive',
455 @command('archive',
456 [('', 'no-decode', None, _('do not pass files through decoders')),
456 [('', 'no-decode', None, _('do not pass files through decoders')),
457 ('p', 'prefix', '', _('directory prefix for files in archive'),
457 ('p', 'prefix', '', _('directory prefix for files in archive'),
458 _('PREFIX')),
458 _('PREFIX')),
459 ('r', 'rev', '', _('revision to distribute'), _('REV')),
459 ('r', 'rev', '', _('revision to distribute'), _('REV')),
460 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
460 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
461 ] + subrepoopts + walkopts,
461 ] + subrepoopts + walkopts,
462 _('[OPTION]... DEST'))
462 _('[OPTION]... DEST'))
463 def archive(ui, repo, dest, **opts):
463 def archive(ui, repo, dest, **opts):
464 '''create an unversioned archive of a repository revision
464 '''create an unversioned archive of a repository revision
465
465
466 By default, the revision used is the parent of the working
466 By default, the revision used is the parent of the working
467 directory; use -r/--rev to specify a different revision.
467 directory; use -r/--rev to specify a different revision.
468
468
469 The archive type is automatically detected based on file
469 The archive type is automatically detected based on file
470 extension (to override, use -t/--type).
470 extension (to override, use -t/--type).
471
471
472 .. container:: verbose
472 .. container:: verbose
473
473
474 Examples:
474 Examples:
475
475
476 - create a zip file containing the 1.0 release::
476 - create a zip file containing the 1.0 release::
477
477
478 hg archive -r 1.0 project-1.0.zip
478 hg archive -r 1.0 project-1.0.zip
479
479
480 - create a tarball excluding .hg files::
480 - create a tarball excluding .hg files::
481
481
482 hg archive project.tar.gz -X ".hg*"
482 hg archive project.tar.gz -X ".hg*"
483
483
484 Valid types are:
484 Valid types are:
485
485
486 :``files``: a directory full of files (default)
486 :``files``: a directory full of files (default)
487 :``tar``: tar archive, uncompressed
487 :``tar``: tar archive, uncompressed
488 :``tbz2``: tar archive, compressed using bzip2
488 :``tbz2``: tar archive, compressed using bzip2
489 :``tgz``: tar archive, compressed using gzip
489 :``tgz``: tar archive, compressed using gzip
490 :``uzip``: zip archive, uncompressed
490 :``uzip``: zip archive, uncompressed
491 :``zip``: zip archive, compressed using deflate
491 :``zip``: zip archive, compressed using deflate
492
492
493 The exact name of the destination archive or directory is given
493 The exact name of the destination archive or directory is given
494 using a format string; see :hg:`help export` for details.
494 using a format string; see :hg:`help export` for details.
495
495
496 Each member added to an archive file has a directory prefix
496 Each member added to an archive file has a directory prefix
497 prepended. Use -p/--prefix to specify a format string for the
497 prepended. Use -p/--prefix to specify a format string for the
498 prefix. The default is the basename of the archive, with suffixes
498 prefix. The default is the basename of the archive, with suffixes
499 removed.
499 removed.
500
500
501 Returns 0 on success.
501 Returns 0 on success.
502 '''
502 '''
503
503
504 ctx = scmutil.revsingle(repo, opts.get('rev'))
504 ctx = scmutil.revsingle(repo, opts.get('rev'))
505 if not ctx:
505 if not ctx:
506 raise error.Abort(_('no working directory: please specify a revision'))
506 raise error.Abort(_('no working directory: please specify a revision'))
507 node = ctx.node()
507 node = ctx.node()
508 dest = cmdutil.makefilename(repo, dest, node)
508 dest = cmdutil.makefilename(repo, dest, node)
509 if os.path.realpath(dest) == repo.root:
509 if os.path.realpath(dest) == repo.root:
510 raise error.Abort(_('repository root cannot be destination'))
510 raise error.Abort(_('repository root cannot be destination'))
511
511
512 kind = opts.get('type') or archival.guesskind(dest) or 'files'
512 kind = opts.get('type') or archival.guesskind(dest) or 'files'
513 prefix = opts.get('prefix')
513 prefix = opts.get('prefix')
514
514
515 if dest == '-':
515 if dest == '-':
516 if kind == 'files':
516 if kind == 'files':
517 raise error.Abort(_('cannot archive plain files to stdout'))
517 raise error.Abort(_('cannot archive plain files to stdout'))
518 dest = cmdutil.makefileobj(repo, dest)
518 dest = cmdutil.makefileobj(repo, dest)
519 if not prefix:
519 if not prefix:
520 prefix = os.path.basename(repo.root) + '-%h'
520 prefix = os.path.basename(repo.root) + '-%h'
521
521
522 prefix = cmdutil.makefilename(repo, prefix, node)
522 prefix = cmdutil.makefilename(repo, prefix, node)
523 matchfn = scmutil.match(ctx, [], opts)
523 matchfn = scmutil.match(ctx, [], opts)
524 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
524 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
525 matchfn, prefix, subrepos=opts.get('subrepos'))
525 matchfn, prefix, subrepos=opts.get('subrepos'))
526
526
527 @command('backout',
527 @command('backout',
528 [('', 'merge', None, _('merge with old dirstate parent after backout')),
528 [('', 'merge', None, _('merge with old dirstate parent after backout')),
529 ('', 'commit', None,
529 ('', 'commit', None,
530 _('commit if no conflicts were encountered (DEPRECATED)')),
530 _('commit if no conflicts were encountered (DEPRECATED)')),
531 ('', 'no-commit', None, _('do not commit')),
531 ('', 'no-commit', None, _('do not commit')),
532 ('', 'parent', '',
532 ('', 'parent', '',
533 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
533 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
534 ('r', 'rev', '', _('revision to backout'), _('REV')),
534 ('r', 'rev', '', _('revision to backout'), _('REV')),
535 ('e', 'edit', False, _('invoke editor on commit messages')),
535 ('e', 'edit', False, _('invoke editor on commit messages')),
536 ] + mergetoolopts + walkopts + commitopts + commitopts2,
536 ] + mergetoolopts + walkopts + commitopts + commitopts2,
537 _('[OPTION]... [-r] REV'))
537 _('[OPTION]... [-r] REV'))
538 def backout(ui, repo, node=None, rev=None, **opts):
538 def backout(ui, repo, node=None, rev=None, **opts):
539 '''reverse effect of earlier changeset
539 '''reverse effect of earlier changeset
540
540
541 Prepare a new changeset with the effect of REV undone in the
541 Prepare a new changeset with the effect of REV undone in the
542 current working directory. If no conflicts were encountered,
542 current working directory. If no conflicts were encountered,
543 it will be committed immediately.
543 it will be committed immediately.
544
544
545 If REV is the parent of the working directory, then this new changeset
545 If REV is the parent of the working directory, then this new changeset
546 is committed automatically (unless --no-commit is specified).
546 is committed automatically (unless --no-commit is specified).
547
547
548 .. note::
548 .. note::
549
549
550 :hg:`backout` cannot be used to fix either an unwanted or
550 :hg:`backout` cannot be used to fix either an unwanted or
551 incorrect merge.
551 incorrect merge.
552
552
553 .. container:: verbose
553 .. container:: verbose
554
554
555 Examples:
555 Examples:
556
556
557 - Reverse the effect of the parent of the working directory.
557 - Reverse the effect of the parent of the working directory.
558 This backout will be committed immediately::
558 This backout will be committed immediately::
559
559
560 hg backout -r .
560 hg backout -r .
561
561
562 - Reverse the effect of previous bad revision 23::
562 - Reverse the effect of previous bad revision 23::
563
563
564 hg backout -r 23
564 hg backout -r 23
565
565
566 - Reverse the effect of previous bad revision 23 and
566 - Reverse the effect of previous bad revision 23 and
567 leave changes uncommitted::
567 leave changes uncommitted::
568
568
569 hg backout -r 23 --no-commit
569 hg backout -r 23 --no-commit
570 hg commit -m "Backout revision 23"
570 hg commit -m "Backout revision 23"
571
571
572 By default, the pending changeset will have one parent,
572 By default, the pending changeset will have one parent,
573 maintaining a linear history. With --merge, the pending
573 maintaining a linear history. With --merge, the pending
574 changeset will instead have two parents: the old parent of the
574 changeset will instead have two parents: the old parent of the
575 working directory and a new child of REV that simply undoes REV.
575 working directory and a new child of REV that simply undoes REV.
576
576
577 Before version 1.7, the behavior without --merge was equivalent
577 Before version 1.7, the behavior without --merge was equivalent
578 to specifying --merge followed by :hg:`update --clean .` to
578 to specifying --merge followed by :hg:`update --clean .` to
579 cancel the merge and leave the child of REV as a head to be
579 cancel the merge and leave the child of REV as a head to be
580 merged separately.
580 merged separately.
581
581
582 See :hg:`help dates` for a list of formats valid for -d/--date.
582 See :hg:`help dates` for a list of formats valid for -d/--date.
583
583
584 See :hg:`help revert` for a way to restore files to the state
584 See :hg:`help revert` for a way to restore files to the state
585 of another revision.
585 of another revision.
586
586
587 Returns 0 on success, 1 if nothing to backout or there are unresolved
587 Returns 0 on success, 1 if nothing to backout or there are unresolved
588 files.
588 files.
589 '''
589 '''
590 wlock = lock = None
590 wlock = lock = None
591 try:
591 try:
592 wlock = repo.wlock()
592 wlock = repo.wlock()
593 lock = repo.lock()
593 lock = repo.lock()
594 return _dobackout(ui, repo, node, rev, **opts)
594 return _dobackout(ui, repo, node, rev, **opts)
595 finally:
595 finally:
596 release(lock, wlock)
596 release(lock, wlock)
597
597
598 def _dobackout(ui, repo, node=None, rev=None, **opts):
598 def _dobackout(ui, repo, node=None, rev=None, **opts):
599 if opts.get('commit') and opts.get('no_commit'):
599 if opts.get('commit') and opts.get('no_commit'):
600 raise error.Abort(_("cannot use --commit with --no-commit"))
600 raise error.Abort(_("cannot use --commit with --no-commit"))
601
601
602 if rev and node:
602 if rev and node:
603 raise error.Abort(_("please specify just one revision"))
603 raise error.Abort(_("please specify just one revision"))
604
604
605 if not rev:
605 if not rev:
606 rev = node
606 rev = node
607
607
608 if not rev:
608 if not rev:
609 raise error.Abort(_("please specify a revision to backout"))
609 raise error.Abort(_("please specify a revision to backout"))
610
610
611 date = opts.get('date')
611 date = opts.get('date')
612 if date:
612 if date:
613 opts['date'] = util.parsedate(date)
613 opts['date'] = util.parsedate(date)
614
614
615 cmdutil.checkunfinished(repo)
615 cmdutil.checkunfinished(repo)
616 cmdutil.bailifchanged(repo)
616 cmdutil.bailifchanged(repo)
617 node = scmutil.revsingle(repo, rev).node()
617 node = scmutil.revsingle(repo, rev).node()
618
618
619 op1, op2 = repo.dirstate.parents()
619 op1, op2 = repo.dirstate.parents()
620 if not repo.changelog.isancestor(node, op1):
620 if not repo.changelog.isancestor(node, op1):
621 raise error.Abort(_('cannot backout change that is not an ancestor'))
621 raise error.Abort(_('cannot backout change that is not an ancestor'))
622
622
623 p1, p2 = repo.changelog.parents(node)
623 p1, p2 = repo.changelog.parents(node)
624 if p1 == nullid:
624 if p1 == nullid:
625 raise error.Abort(_('cannot backout a change with no parents'))
625 raise error.Abort(_('cannot backout a change with no parents'))
626 if p2 != nullid:
626 if p2 != nullid:
627 if not opts.get('parent'):
627 if not opts.get('parent'):
628 raise error.Abort(_('cannot backout a merge changeset'))
628 raise error.Abort(_('cannot backout a merge changeset'))
629 p = repo.lookup(opts['parent'])
629 p = repo.lookup(opts['parent'])
630 if p not in (p1, p2):
630 if p not in (p1, p2):
631 raise error.Abort(_('%s is not a parent of %s') %
631 raise error.Abort(_('%s is not a parent of %s') %
632 (short(p), short(node)))
632 (short(p), short(node)))
633 parent = p
633 parent = p
634 else:
634 else:
635 if opts.get('parent'):
635 if opts.get('parent'):
636 raise error.Abort(_('cannot use --parent on non-merge changeset'))
636 raise error.Abort(_('cannot use --parent on non-merge changeset'))
637 parent = p1
637 parent = p1
638
638
639 # the backout should appear on the same branch
639 # the backout should appear on the same branch
640 branch = repo.dirstate.branch()
640 branch = repo.dirstate.branch()
641 bheads = repo.branchheads(branch)
641 bheads = repo.branchheads(branch)
642 rctx = scmutil.revsingle(repo, hex(parent))
642 rctx = scmutil.revsingle(repo, hex(parent))
643 if not opts.get('merge') and op1 != node:
643 if not opts.get('merge') and op1 != node:
644 dsguard = cmdutil.dirstateguard(repo, 'backout')
644 dsguard = cmdutil.dirstateguard(repo, 'backout')
645 try:
645 try:
646 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
646 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
647 'backout')
647 'backout')
648 stats = mergemod.update(repo, parent, True, True, node, False)
648 stats = mergemod.update(repo, parent, True, True, node, False)
649 repo.setparents(op1, op2)
649 repo.setparents(op1, op2)
650 dsguard.close()
650 dsguard.close()
651 hg._showstats(repo, stats)
651 hg._showstats(repo, stats)
652 if stats[3]:
652 if stats[3]:
653 repo.ui.status(_("use 'hg resolve' to retry unresolved "
653 repo.ui.status(_("use 'hg resolve' to retry unresolved "
654 "file merges\n"))
654 "file merges\n"))
655 return 1
655 return 1
656 finally:
656 finally:
657 ui.setconfig('ui', 'forcemerge', '', '')
657 ui.setconfig('ui', 'forcemerge', '', '')
658 lockmod.release(dsguard)
658 lockmod.release(dsguard)
659 else:
659 else:
660 hg.clean(repo, node, show_stats=False)
660 hg.clean(repo, node, show_stats=False)
661 repo.dirstate.setbranch(branch)
661 repo.dirstate.setbranch(branch)
662 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
662 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
663
663
664 if opts.get('no_commit'):
664 if opts.get('no_commit'):
665 msg = _("changeset %s backed out, "
665 msg = _("changeset %s backed out, "
666 "don't forget to commit.\n")
666 "don't forget to commit.\n")
667 ui.status(msg % short(node))
667 ui.status(msg % short(node))
668 return 0
668 return 0
669
669
670 def commitfunc(ui, repo, message, match, opts):
670 def commitfunc(ui, repo, message, match, opts):
671 editform = 'backout'
671 editform = 'backout'
672 e = cmdutil.getcommiteditor(editform=editform, **opts)
672 e = cmdutil.getcommiteditor(editform=editform, **opts)
673 if not message:
673 if not message:
674 # we don't translate commit messages
674 # we don't translate commit messages
675 message = "Backed out changeset %s" % short(node)
675 message = "Backed out changeset %s" % short(node)
676 e = cmdutil.getcommiteditor(edit=True, editform=editform)
676 e = cmdutil.getcommiteditor(edit=True, editform=editform)
677 return repo.commit(message, opts.get('user'), opts.get('date'),
677 return repo.commit(message, opts.get('user'), opts.get('date'),
678 match, editor=e)
678 match, editor=e)
679 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
679 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
680 if not newnode:
680 if not newnode:
681 ui.status(_("nothing changed\n"))
681 ui.status(_("nothing changed\n"))
682 return 1
682 return 1
683 cmdutil.commitstatus(repo, newnode, branch, bheads)
683 cmdutil.commitstatus(repo, newnode, branch, bheads)
684
684
685 def nice(node):
685 def nice(node):
686 return '%d:%s' % (repo.changelog.rev(node), short(node))
686 return '%d:%s' % (repo.changelog.rev(node), short(node))
687 ui.status(_('changeset %s backs out changeset %s\n') %
687 ui.status(_('changeset %s backs out changeset %s\n') %
688 (nice(repo.changelog.tip()), nice(node)))
688 (nice(repo.changelog.tip()), nice(node)))
689 if opts.get('merge') and op1 != node:
689 if opts.get('merge') and op1 != node:
690 hg.clean(repo, op1, show_stats=False)
690 hg.clean(repo, op1, show_stats=False)
691 ui.status(_('merging with changeset %s\n')
691 ui.status(_('merging with changeset %s\n')
692 % nice(repo.changelog.tip()))
692 % nice(repo.changelog.tip()))
693 try:
693 try:
694 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
694 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
695 'backout')
695 'backout')
696 return hg.merge(repo, hex(repo.changelog.tip()))
696 return hg.merge(repo, hex(repo.changelog.tip()))
697 finally:
697 finally:
698 ui.setconfig('ui', 'forcemerge', '', '')
698 ui.setconfig('ui', 'forcemerge', '', '')
699 return 0
699 return 0
700
700
701 @command('bisect',
701 @command('bisect',
702 [('r', 'reset', False, _('reset bisect state')),
702 [('r', 'reset', False, _('reset bisect state')),
703 ('g', 'good', False, _('mark changeset good')),
703 ('g', 'good', False, _('mark changeset good')),
704 ('b', 'bad', False, _('mark changeset bad')),
704 ('b', 'bad', False, _('mark changeset bad')),
705 ('s', 'skip', False, _('skip testing changeset')),
705 ('s', 'skip', False, _('skip testing changeset')),
706 ('e', 'extend', False, _('extend the bisect range')),
706 ('e', 'extend', False, _('extend the bisect range')),
707 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
707 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
708 ('U', 'noupdate', False, _('do not update to target'))],
708 ('U', 'noupdate', False, _('do not update to target'))],
709 _("[-gbsr] [-U] [-c CMD] [REV]"))
709 _("[-gbsr] [-U] [-c CMD] [REV]"))
710 def bisect(ui, repo, rev=None, extra=None, command=None,
710 def bisect(ui, repo, rev=None, extra=None, command=None,
711 reset=None, good=None, bad=None, skip=None, extend=None,
711 reset=None, good=None, bad=None, skip=None, extend=None,
712 noupdate=None):
712 noupdate=None):
713 """subdivision search of changesets
713 """subdivision search of changesets
714
714
715 This command helps to find changesets which introduce problems. To
715 This command helps to find changesets which introduce problems. To
716 use, mark the earliest changeset you know exhibits the problem as
716 use, mark the earliest changeset you know exhibits the problem as
717 bad, then mark the latest changeset which is free from the problem
717 bad, then mark the latest changeset which is free from the problem
718 as good. Bisect will update your working directory to a revision
718 as good. Bisect will update your working directory to a revision
719 for testing (unless the -U/--noupdate option is specified). Once
719 for testing (unless the -U/--noupdate option is specified). Once
720 you have performed tests, mark the working directory as good or
720 you have performed tests, mark the working directory as good or
721 bad, and bisect will either update to another candidate changeset
721 bad, and bisect will either update to another candidate changeset
722 or announce that it has found the bad revision.
722 or announce that it has found the bad revision.
723
723
724 As a shortcut, you can also use the revision argument to mark a
724 As a shortcut, you can also use the revision argument to mark a
725 revision as good or bad without checking it out first.
725 revision as good or bad without checking it out first.
726
726
727 If you supply a command, it will be used for automatic bisection.
727 If you supply a command, it will be used for automatic bisection.
728 The environment variable HG_NODE will contain the ID of the
728 The environment variable HG_NODE will contain the ID of the
729 changeset being tested. The exit status of the command will be
729 changeset being tested. The exit status of the command will be
730 used to mark revisions as good or bad: status 0 means good, 125
730 used to mark revisions as good or bad: status 0 means good, 125
731 means to skip the revision, 127 (command not found) will abort the
731 means to skip the revision, 127 (command not found) will abort the
732 bisection, and any other non-zero exit status means the revision
732 bisection, and any other non-zero exit status means the revision
733 is bad.
733 is bad.
734
734
735 .. container:: verbose
735 .. container:: verbose
736
736
737 Some examples:
737 Some examples:
738
738
739 - start a bisection with known bad revision 34, and good revision 12::
739 - start a bisection with known bad revision 34, and good revision 12::
740
740
741 hg bisect --bad 34
741 hg bisect --bad 34
742 hg bisect --good 12
742 hg bisect --good 12
743
743
744 - advance the current bisection by marking current revision as good or
744 - advance the current bisection by marking current revision as good or
745 bad::
745 bad::
746
746
747 hg bisect --good
747 hg bisect --good
748 hg bisect --bad
748 hg bisect --bad
749
749
750 - mark the current revision, or a known revision, to be skipped (e.g. if
750 - mark the current revision, or a known revision, to be skipped (e.g. if
751 that revision is not usable because of another issue)::
751 that revision is not usable because of another issue)::
752
752
753 hg bisect --skip
753 hg bisect --skip
754 hg bisect --skip 23
754 hg bisect --skip 23
755
755
756 - skip all revisions that do not touch directories ``foo`` or ``bar``::
756 - skip all revisions that do not touch directories ``foo`` or ``bar``::
757
757
758 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
758 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
759
759
760 - forget the current bisection::
760 - forget the current bisection::
761
761
762 hg bisect --reset
762 hg bisect --reset
763
763
764 - use 'make && make tests' to automatically find the first broken
764 - use 'make && make tests' to automatically find the first broken
765 revision::
765 revision::
766
766
767 hg bisect --reset
767 hg bisect --reset
768 hg bisect --bad 34
768 hg bisect --bad 34
769 hg bisect --good 12
769 hg bisect --good 12
770 hg bisect --command "make && make tests"
770 hg bisect --command "make && make tests"
771
771
772 - see all changesets whose states are already known in the current
772 - see all changesets whose states are already known in the current
773 bisection::
773 bisection::
774
774
775 hg log -r "bisect(pruned)"
775 hg log -r "bisect(pruned)"
776
776
777 - see the changeset currently being bisected (especially useful
777 - see the changeset currently being bisected (especially useful
778 if running with -U/--noupdate)::
778 if running with -U/--noupdate)::
779
779
780 hg log -r "bisect(current)"
780 hg log -r "bisect(current)"
781
781
782 - see all changesets that took part in the current bisection::
782 - see all changesets that took part in the current bisection::
783
783
784 hg log -r "bisect(range)"
784 hg log -r "bisect(range)"
785
785
786 - you can even get a nice graph::
786 - you can even get a nice graph::
787
787
788 hg log --graph -r "bisect(range)"
788 hg log --graph -r "bisect(range)"
789
789
790 See :hg:`help revsets` for more about the `bisect()` keyword.
790 See :hg:`help revsets` for more about the `bisect()` keyword.
791
791
792 Returns 0 on success.
792 Returns 0 on success.
793 """
793 """
794 def extendbisectrange(nodes, good):
794 def extendbisectrange(nodes, good):
795 # bisect is incomplete when it ends on a merge node and
795 # bisect is incomplete when it ends on a merge node and
796 # one of the parent was not checked.
796 # one of the parent was not checked.
797 parents = repo[nodes[0]].parents()
797 parents = repo[nodes[0]].parents()
798 if len(parents) > 1:
798 if len(parents) > 1:
799 if good:
799 if good:
800 side = state['bad']
800 side = state['bad']
801 else:
801 else:
802 side = state['good']
802 side = state['good']
803 num = len(set(i.node() for i in parents) & set(side))
803 num = len(set(i.node() for i in parents) & set(side))
804 if num == 1:
804 if num == 1:
805 return parents[0].ancestor(parents[1])
805 return parents[0].ancestor(parents[1])
806 return None
806 return None
807
807
808 def print_result(nodes, good):
808 def print_result(nodes, good):
809 displayer = cmdutil.show_changeset(ui, repo, {})
809 displayer = cmdutil.show_changeset(ui, repo, {})
810 if len(nodes) == 1:
810 if len(nodes) == 1:
811 # narrowed it down to a single revision
811 # narrowed it down to a single revision
812 if good:
812 if good:
813 ui.write(_("The first good revision is:\n"))
813 ui.write(_("The first good revision is:\n"))
814 else:
814 else:
815 ui.write(_("The first bad revision is:\n"))
815 ui.write(_("The first bad revision is:\n"))
816 displayer.show(repo[nodes[0]])
816 displayer.show(repo[nodes[0]])
817 extendnode = extendbisectrange(nodes, good)
817 extendnode = extendbisectrange(nodes, good)
818 if extendnode is not None:
818 if extendnode is not None:
819 ui.write(_('Not all ancestors of this changeset have been'
819 ui.write(_('Not all ancestors of this changeset have been'
820 ' checked.\nUse bisect --extend to continue the '
820 ' checked.\nUse bisect --extend to continue the '
821 'bisection from\nthe common ancestor, %s.\n')
821 'bisection from\nthe common ancestor, %s.\n')
822 % extendnode)
822 % extendnode)
823 else:
823 else:
824 # multiple possible revisions
824 # multiple possible revisions
825 if good:
825 if good:
826 ui.write(_("Due to skipped revisions, the first "
826 ui.write(_("Due to skipped revisions, the first "
827 "good revision could be any of:\n"))
827 "good revision could be any of:\n"))
828 else:
828 else:
829 ui.write(_("Due to skipped revisions, the first "
829 ui.write(_("Due to skipped revisions, the first "
830 "bad revision could be any of:\n"))
830 "bad revision could be any of:\n"))
831 for n in nodes:
831 for n in nodes:
832 displayer.show(repo[n])
832 displayer.show(repo[n])
833 displayer.close()
833 displayer.close()
834
834
835 def check_state(state, interactive=True):
835 def check_state(state, interactive=True):
836 if not state['good'] or not state['bad']:
836 if not state['good'] or not state['bad']:
837 if (good or bad or skip or reset) and interactive:
837 if (good or bad or skip or reset) and interactive:
838 return
838 return
839 if not state['good']:
839 if not state['good']:
840 raise error.Abort(_('cannot bisect (no known good revisions)'))
840 raise error.Abort(_('cannot bisect (no known good revisions)'))
841 else:
841 else:
842 raise error.Abort(_('cannot bisect (no known bad revisions)'))
842 raise error.Abort(_('cannot bisect (no known bad revisions)'))
843 return True
843 return True
844
844
845 # backward compatibility
845 # backward compatibility
846 if rev in "good bad reset init".split():
846 if rev in "good bad reset init".split():
847 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
847 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
848 cmd, rev, extra = rev, extra, None
848 cmd, rev, extra = rev, extra, None
849 if cmd == "good":
849 if cmd == "good":
850 good = True
850 good = True
851 elif cmd == "bad":
851 elif cmd == "bad":
852 bad = True
852 bad = True
853 else:
853 else:
854 reset = True
854 reset = True
855 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
855 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
856 raise error.Abort(_('incompatible arguments'))
856 raise error.Abort(_('incompatible arguments'))
857
857
858 cmdutil.checkunfinished(repo)
858 cmdutil.checkunfinished(repo)
859
859
860 if reset:
860 if reset:
861 p = repo.join("bisect.state")
861 p = repo.join("bisect.state")
862 if os.path.exists(p):
862 if os.path.exists(p):
863 os.unlink(p)
863 os.unlink(p)
864 return
864 return
865
865
866 state = hbisect.load_state(repo)
866 state = hbisect.load_state(repo)
867
867
868 if command:
868 if command:
869 changesets = 1
869 changesets = 1
870 if noupdate:
870 if noupdate:
871 try:
871 try:
872 node = state['current'][0]
872 node = state['current'][0]
873 except LookupError:
873 except LookupError:
874 raise error.Abort(_('current bisect revision is unknown - '
874 raise error.Abort(_('current bisect revision is unknown - '
875 'start a new bisect to fix'))
875 'start a new bisect to fix'))
876 else:
876 else:
877 node, p2 = repo.dirstate.parents()
877 node, p2 = repo.dirstate.parents()
878 if p2 != nullid:
878 if p2 != nullid:
879 raise error.Abort(_('current bisect revision is a merge'))
879 raise error.Abort(_('current bisect revision is a merge'))
880 try:
880 try:
881 while changesets:
881 while changesets:
882 # update state
882 # update state
883 state['current'] = [node]
883 state['current'] = [node]
884 hbisect.save_state(repo, state)
884 hbisect.save_state(repo, state)
885 status = ui.system(command, environ={'HG_NODE': hex(node)})
885 status = ui.system(command, environ={'HG_NODE': hex(node)})
886 if status == 125:
886 if status == 125:
887 transition = "skip"
887 transition = "skip"
888 elif status == 0:
888 elif status == 0:
889 transition = "good"
889 transition = "good"
890 # status < 0 means process was killed
890 # status < 0 means process was killed
891 elif status == 127:
891 elif status == 127:
892 raise error.Abort(_("failed to execute %s") % command)
892 raise error.Abort(_("failed to execute %s") % command)
893 elif status < 0:
893 elif status < 0:
894 raise error.Abort(_("%s killed") % command)
894 raise error.Abort(_("%s killed") % command)
895 else:
895 else:
896 transition = "bad"
896 transition = "bad"
897 ctx = scmutil.revsingle(repo, rev, node)
897 ctx = scmutil.revsingle(repo, rev, node)
898 rev = None # clear for future iterations
898 rev = None # clear for future iterations
899 state[transition].append(ctx.node())
899 state[transition].append(ctx.node())
900 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
900 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
901 check_state(state, interactive=False)
901 check_state(state, interactive=False)
902 # bisect
902 # bisect
903 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
903 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
904 # update to next check
904 # update to next check
905 node = nodes[0]
905 node = nodes[0]
906 if not noupdate:
906 if not noupdate:
907 cmdutil.bailifchanged(repo)
907 cmdutil.bailifchanged(repo)
908 hg.clean(repo, node, show_stats=False)
908 hg.clean(repo, node, show_stats=False)
909 finally:
909 finally:
910 state['current'] = [node]
910 state['current'] = [node]
911 hbisect.save_state(repo, state)
911 hbisect.save_state(repo, state)
912 print_result(nodes, bgood)
912 print_result(nodes, bgood)
913 return
913 return
914
914
915 # update state
915 # update state
916
916
917 if rev:
917 if rev:
918 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
918 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
919 else:
919 else:
920 nodes = [repo.lookup('.')]
920 nodes = [repo.lookup('.')]
921
921
922 if good or bad or skip:
922 if good or bad or skip:
923 if good:
923 if good:
924 state['good'] += nodes
924 state['good'] += nodes
925 elif bad:
925 elif bad:
926 state['bad'] += nodes
926 state['bad'] += nodes
927 elif skip:
927 elif skip:
928 state['skip'] += nodes
928 state['skip'] += nodes
929 hbisect.save_state(repo, state)
929 hbisect.save_state(repo, state)
930
930
931 if not check_state(state):
931 if not check_state(state):
932 return
932 return
933
933
934 # actually bisect
934 # actually bisect
935 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
935 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
936 if extend:
936 if extend:
937 if not changesets:
937 if not changesets:
938 extendnode = extendbisectrange(nodes, good)
938 extendnode = extendbisectrange(nodes, good)
939 if extendnode is not None:
939 if extendnode is not None:
940 ui.write(_("Extending search to changeset %d:%s\n")
940 ui.write(_("Extending search to changeset %d:%s\n")
941 % (extendnode.rev(), extendnode))
941 % (extendnode.rev(), extendnode))
942 state['current'] = [extendnode.node()]
942 state['current'] = [extendnode.node()]
943 hbisect.save_state(repo, state)
943 hbisect.save_state(repo, state)
944 if noupdate:
944 if noupdate:
945 return
945 return
946 cmdutil.bailifchanged(repo)
946 cmdutil.bailifchanged(repo)
947 return hg.clean(repo, extendnode.node())
947 return hg.clean(repo, extendnode.node())
948 raise error.Abort(_("nothing to extend"))
948 raise error.Abort(_("nothing to extend"))
949
949
950 if changesets == 0:
950 if changesets == 0:
951 print_result(nodes, good)
951 print_result(nodes, good)
952 else:
952 else:
953 assert len(nodes) == 1 # only a single node can be tested next
953 assert len(nodes) == 1 # only a single node can be tested next
954 node = nodes[0]
954 node = nodes[0]
955 # compute the approximate number of remaining tests
955 # compute the approximate number of remaining tests
956 tests, size = 0, 2
956 tests, size = 0, 2
957 while size <= changesets:
957 while size <= changesets:
958 tests, size = tests + 1, size * 2
958 tests, size = tests + 1, size * 2
959 rev = repo.changelog.rev(node)
959 rev = repo.changelog.rev(node)
960 ui.write(_("Testing changeset %d:%s "
960 ui.write(_("Testing changeset %d:%s "
961 "(%d changesets remaining, ~%d tests)\n")
961 "(%d changesets remaining, ~%d tests)\n")
962 % (rev, short(node), changesets, tests))
962 % (rev, short(node), changesets, tests))
963 state['current'] = [node]
963 state['current'] = [node]
964 hbisect.save_state(repo, state)
964 hbisect.save_state(repo, state)
965 if not noupdate:
965 if not noupdate:
966 cmdutil.bailifchanged(repo)
966 cmdutil.bailifchanged(repo)
967 return hg.clean(repo, node)
967 return hg.clean(repo, node)
968
968
969 @command('bookmarks|bookmark',
969 @command('bookmarks|bookmark',
970 [('f', 'force', False, _('force')),
970 [('f', 'force', False, _('force')),
971 ('r', 'rev', '', _('revision'), _('REV')),
971 ('r', 'rev', '', _('revision'), _('REV')),
972 ('d', 'delete', False, _('delete a given bookmark')),
972 ('d', 'delete', False, _('delete a given bookmark')),
973 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
973 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
974 ('i', 'inactive', False, _('mark a bookmark inactive')),
974 ('i', 'inactive', False, _('mark a bookmark inactive')),
975 ] + formatteropts,
975 ] + formatteropts,
976 _('hg bookmarks [OPTIONS]... [NAME]...'))
976 _('hg bookmarks [OPTIONS]... [NAME]...'))
977 def bookmark(ui, repo, *names, **opts):
977 def bookmark(ui, repo, *names, **opts):
978 '''create a new bookmark or list existing bookmarks
978 '''create a new bookmark or list existing bookmarks
979
979
980 Bookmarks are labels on changesets to help track lines of development.
980 Bookmarks are labels on changesets to help track lines of development.
981 Bookmarks are unversioned and can be moved, renamed and deleted.
981 Bookmarks are unversioned and can be moved, renamed and deleted.
982 Deleting or moving a bookmark has no effect on the associated changesets.
982 Deleting or moving a bookmark has no effect on the associated changesets.
983
983
984 Creating or updating to a bookmark causes it to be marked as 'active'.
984 Creating or updating to a bookmark causes it to be marked as 'active'.
985 The active bookmark is indicated with a '*'.
985 The active bookmark is indicated with a '*'.
986 When a commit is made, the active bookmark will advance to the new commit.
986 When a commit is made, the active bookmark will advance to the new commit.
987 A plain :hg:`update` will also advance an active bookmark, if possible.
987 A plain :hg:`update` will also advance an active bookmark, if possible.
988 Updating away from a bookmark will cause it to be deactivated.
988 Updating away from a bookmark will cause it to be deactivated.
989
989
990 Bookmarks can be pushed and pulled between repositories (see
990 Bookmarks can be pushed and pulled between repositories (see
991 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
991 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
992 diverged, a new 'divergent bookmark' of the form 'name@path' will
992 diverged, a new 'divergent bookmark' of the form 'name@path' will
993 be created. Using :hg:`merge` will resolve the divergence.
993 be created. Using :hg:`merge` will resolve the divergence.
994
994
995 A bookmark named '@' has the special property that :hg:`clone` will
995 A bookmark named '@' has the special property that :hg:`clone` will
996 check it out by default if it exists.
996 check it out by default if it exists.
997
997
998 .. container:: verbose
998 .. container:: verbose
999
999
1000 Examples:
1000 Examples:
1001
1001
1002 - create an active bookmark for a new line of development::
1002 - create an active bookmark for a new line of development::
1003
1003
1004 hg book new-feature
1004 hg book new-feature
1005
1005
1006 - create an inactive bookmark as a place marker::
1006 - create an inactive bookmark as a place marker::
1007
1007
1008 hg book -i reviewed
1008 hg book -i reviewed
1009
1009
1010 - create an inactive bookmark on another changeset::
1010 - create an inactive bookmark on another changeset::
1011
1011
1012 hg book -r .^ tested
1012 hg book -r .^ tested
1013
1013
1014 - rename bookmark turkey to dinner::
1014 - rename bookmark turkey to dinner::
1015
1015
1016 hg book -m turkey dinner
1016 hg book -m turkey dinner
1017
1017
1018 - move the '@' bookmark from another branch::
1018 - move the '@' bookmark from another branch::
1019
1019
1020 hg book -f @
1020 hg book -f @
1021 '''
1021 '''
1022 force = opts.get('force')
1022 force = opts.get('force')
1023 rev = opts.get('rev')
1023 rev = opts.get('rev')
1024 delete = opts.get('delete')
1024 delete = opts.get('delete')
1025 rename = opts.get('rename')
1025 rename = opts.get('rename')
1026 inactive = opts.get('inactive')
1026 inactive = opts.get('inactive')
1027
1027
1028 def checkformat(mark):
1028 def checkformat(mark):
1029 mark = mark.strip()
1029 mark = mark.strip()
1030 if not mark:
1030 if not mark:
1031 raise error.Abort(_("bookmark names cannot consist entirely of "
1031 raise error.Abort(_("bookmark names cannot consist entirely of "
1032 "whitespace"))
1032 "whitespace"))
1033 scmutil.checknewlabel(repo, mark, 'bookmark')
1033 scmutil.checknewlabel(repo, mark, 'bookmark')
1034 return mark
1034 return mark
1035
1035
1036 def checkconflict(repo, mark, cur, force=False, target=None):
1036 def checkconflict(repo, mark, cur, force=False, target=None):
1037 if mark in marks and not force:
1037 if mark in marks and not force:
1038 if target:
1038 if target:
1039 if marks[mark] == target and target == cur:
1039 if marks[mark] == target and target == cur:
1040 # re-activating a bookmark
1040 # re-activating a bookmark
1041 return
1041 return
1042 anc = repo.changelog.ancestors([repo[target].rev()])
1042 anc = repo.changelog.ancestors([repo[target].rev()])
1043 bmctx = repo[marks[mark]]
1043 bmctx = repo[marks[mark]]
1044 divs = [repo[b].node() for b in marks
1044 divs = [repo[b].node() for b in marks
1045 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1045 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1046
1046
1047 # allow resolving a single divergent bookmark even if moving
1047 # allow resolving a single divergent bookmark even if moving
1048 # the bookmark across branches when a revision is specified
1048 # the bookmark across branches when a revision is specified
1049 # that contains a divergent bookmark
1049 # that contains a divergent bookmark
1050 if bmctx.rev() not in anc and target in divs:
1050 if bmctx.rev() not in anc and target in divs:
1051 bookmarks.deletedivergent(repo, [target], mark)
1051 bookmarks.deletedivergent(repo, [target], mark)
1052 return
1052 return
1053
1053
1054 deletefrom = [b for b in divs
1054 deletefrom = [b for b in divs
1055 if repo[b].rev() in anc or b == target]
1055 if repo[b].rev() in anc or b == target]
1056 bookmarks.deletedivergent(repo, deletefrom, mark)
1056 bookmarks.deletedivergent(repo, deletefrom, mark)
1057 if bookmarks.validdest(repo, bmctx, repo[target]):
1057 if bookmarks.validdest(repo, bmctx, repo[target]):
1058 ui.status(_("moving bookmark '%s' forward from %s\n") %
1058 ui.status(_("moving bookmark '%s' forward from %s\n") %
1059 (mark, short(bmctx.node())))
1059 (mark, short(bmctx.node())))
1060 return
1060 return
1061 raise error.Abort(_("bookmark '%s' already exists "
1061 raise error.Abort(_("bookmark '%s' already exists "
1062 "(use -f to force)") % mark)
1062 "(use -f to force)") % mark)
1063 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1063 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1064 and not force):
1064 and not force):
1065 raise error.Abort(
1065 raise error.Abort(
1066 _("a bookmark cannot have the name of an existing branch"))
1066 _("a bookmark cannot have the name of an existing branch"))
1067
1067
1068 if delete and rename:
1068 if delete and rename:
1069 raise error.Abort(_("--delete and --rename are incompatible"))
1069 raise error.Abort(_("--delete and --rename are incompatible"))
1070 if delete and rev:
1070 if delete and rev:
1071 raise error.Abort(_("--rev is incompatible with --delete"))
1071 raise error.Abort(_("--rev is incompatible with --delete"))
1072 if rename and rev:
1072 if rename and rev:
1073 raise error.Abort(_("--rev is incompatible with --rename"))
1073 raise error.Abort(_("--rev is incompatible with --rename"))
1074 if not names and (delete or rev):
1074 if not names and (delete or rev):
1075 raise error.Abort(_("bookmark name required"))
1075 raise error.Abort(_("bookmark name required"))
1076
1076
1077 if delete or rename or names or inactive:
1077 if delete or rename or names or inactive:
1078 wlock = lock = tr = None
1078 wlock = lock = tr = None
1079 try:
1079 try:
1080 wlock = repo.wlock()
1080 wlock = repo.wlock()
1081 lock = repo.lock()
1081 lock = repo.lock()
1082 cur = repo.changectx('.').node()
1082 cur = repo.changectx('.').node()
1083 marks = repo._bookmarks
1083 marks = repo._bookmarks
1084 if delete:
1084 if delete:
1085 tr = repo.transaction('bookmark')
1085 tr = repo.transaction('bookmark')
1086 for mark in names:
1086 for mark in names:
1087 if mark not in marks:
1087 if mark not in marks:
1088 raise error.Abort(_("bookmark '%s' does not exist") %
1088 raise error.Abort(_("bookmark '%s' does not exist") %
1089 mark)
1089 mark)
1090 if mark == repo._activebookmark:
1090 if mark == repo._activebookmark:
1091 bookmarks.deactivate(repo)
1091 bookmarks.deactivate(repo)
1092 del marks[mark]
1092 del marks[mark]
1093
1093
1094 elif rename:
1094 elif rename:
1095 tr = repo.transaction('bookmark')
1095 tr = repo.transaction('bookmark')
1096 if not names:
1096 if not names:
1097 raise error.Abort(_("new bookmark name required"))
1097 raise error.Abort(_("new bookmark name required"))
1098 elif len(names) > 1:
1098 elif len(names) > 1:
1099 raise error.Abort(_("only one new bookmark name allowed"))
1099 raise error.Abort(_("only one new bookmark name allowed"))
1100 mark = checkformat(names[0])
1100 mark = checkformat(names[0])
1101 if rename not in marks:
1101 if rename not in marks:
1102 raise error.Abort(_("bookmark '%s' does not exist")
1102 raise error.Abort(_("bookmark '%s' does not exist")
1103 % rename)
1103 % rename)
1104 checkconflict(repo, mark, cur, force)
1104 checkconflict(repo, mark, cur, force)
1105 marks[mark] = marks[rename]
1105 marks[mark] = marks[rename]
1106 if repo._activebookmark == rename and not inactive:
1106 if repo._activebookmark == rename and not inactive:
1107 bookmarks.activate(repo, mark)
1107 bookmarks.activate(repo, mark)
1108 del marks[rename]
1108 del marks[rename]
1109 elif names:
1109 elif names:
1110 tr = repo.transaction('bookmark')
1110 tr = repo.transaction('bookmark')
1111 newact = None
1111 newact = None
1112 for mark in names:
1112 for mark in names:
1113 mark = checkformat(mark)
1113 mark = checkformat(mark)
1114 if newact is None:
1114 if newact is None:
1115 newact = mark
1115 newact = mark
1116 if inactive and mark == repo._activebookmark:
1116 if inactive and mark == repo._activebookmark:
1117 bookmarks.deactivate(repo)
1117 bookmarks.deactivate(repo)
1118 return
1118 return
1119 tgt = cur
1119 tgt = cur
1120 if rev:
1120 if rev:
1121 tgt = scmutil.revsingle(repo, rev).node()
1121 tgt = scmutil.revsingle(repo, rev).node()
1122 checkconflict(repo, mark, cur, force, tgt)
1122 checkconflict(repo, mark, cur, force, tgt)
1123 marks[mark] = tgt
1123 marks[mark] = tgt
1124 if not inactive and cur == marks[newact] and not rev:
1124 if not inactive and cur == marks[newact] and not rev:
1125 bookmarks.activate(repo, newact)
1125 bookmarks.activate(repo, newact)
1126 elif cur != tgt and newact == repo._activebookmark:
1126 elif cur != tgt and newact == repo._activebookmark:
1127 bookmarks.deactivate(repo)
1127 bookmarks.deactivate(repo)
1128 elif inactive:
1128 elif inactive:
1129 if len(marks) == 0:
1129 if len(marks) == 0:
1130 ui.status(_("no bookmarks set\n"))
1130 ui.status(_("no bookmarks set\n"))
1131 elif not repo._activebookmark:
1131 elif not repo._activebookmark:
1132 ui.status(_("no active bookmark\n"))
1132 ui.status(_("no active bookmark\n"))
1133 else:
1133 else:
1134 bookmarks.deactivate(repo)
1134 bookmarks.deactivate(repo)
1135 if tr is not None:
1135 if tr is not None:
1136 marks.recordchange(tr)
1136 marks.recordchange(tr)
1137 tr.close()
1137 tr.close()
1138 finally:
1138 finally:
1139 lockmod.release(tr, lock, wlock)
1139 lockmod.release(tr, lock, wlock)
1140 else: # show bookmarks
1140 else: # show bookmarks
1141 fm = ui.formatter('bookmarks', opts)
1141 fm = ui.formatter('bookmarks', opts)
1142 hexfn = fm.hexfunc
1142 hexfn = fm.hexfunc
1143 marks = repo._bookmarks
1143 marks = repo._bookmarks
1144 if len(marks) == 0 and not fm:
1144 if len(marks) == 0 and not fm:
1145 ui.status(_("no bookmarks set\n"))
1145 ui.status(_("no bookmarks set\n"))
1146 for bmark, n in sorted(marks.iteritems()):
1146 for bmark, n in sorted(marks.iteritems()):
1147 active = repo._activebookmark
1147 active = repo._activebookmark
1148 if bmark == active:
1148 if bmark == active:
1149 prefix, label = '*', activebookmarklabel
1149 prefix, label = '*', activebookmarklabel
1150 else:
1150 else:
1151 prefix, label = ' ', ''
1151 prefix, label = ' ', ''
1152
1152
1153 fm.startitem()
1153 fm.startitem()
1154 if not ui.quiet:
1154 if not ui.quiet:
1155 fm.plain(' %s ' % prefix, label=label)
1155 fm.plain(' %s ' % prefix, label=label)
1156 fm.write('bookmark', '%s', bmark, label=label)
1156 fm.write('bookmark', '%s', bmark, label=label)
1157 pad = " " * (25 - encoding.colwidth(bmark))
1157 pad = " " * (25 - encoding.colwidth(bmark))
1158 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1158 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1159 repo.changelog.rev(n), hexfn(n), label=label)
1159 repo.changelog.rev(n), hexfn(n), label=label)
1160 fm.data(active=(bmark == active))
1160 fm.data(active=(bmark == active))
1161 fm.plain('\n')
1161 fm.plain('\n')
1162 fm.end()
1162 fm.end()
1163
1163
1164 @command('branch',
1164 @command('branch',
1165 [('f', 'force', None,
1165 [('f', 'force', None,
1166 _('set branch name even if it shadows an existing branch')),
1166 _('set branch name even if it shadows an existing branch')),
1167 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1167 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1168 _('[-fC] [NAME]'))
1168 _('[-fC] [NAME]'))
1169 def branch(ui, repo, label=None, **opts):
1169 def branch(ui, repo, label=None, **opts):
1170 """set or show the current branch name
1170 """set or show the current branch name
1171
1171
1172 .. note::
1172 .. note::
1173
1173
1174 Branch names are permanent and global. Use :hg:`bookmark` to create a
1174 Branch names are permanent and global. Use :hg:`bookmark` to create a
1175 light-weight bookmark instead. See :hg:`help glossary` for more
1175 light-weight bookmark instead. See :hg:`help glossary` for more
1176 information about named branches and bookmarks.
1176 information about named branches and bookmarks.
1177
1177
1178 With no argument, show the current branch name. With one argument,
1178 With no argument, show the current branch name. With one argument,
1179 set the working directory branch name (the branch will not exist
1179 set the working directory branch name (the branch will not exist
1180 in the repository until the next commit). Standard practice
1180 in the repository until the next commit). Standard practice
1181 recommends that primary development take place on the 'default'
1181 recommends that primary development take place on the 'default'
1182 branch.
1182 branch.
1183
1183
1184 Unless -f/--force is specified, branch will not let you set a
1184 Unless -f/--force is specified, branch will not let you set a
1185 branch name that already exists.
1185 branch name that already exists.
1186
1186
1187 Use -C/--clean to reset the working directory branch to that of
1187 Use -C/--clean to reset the working directory branch to that of
1188 the parent of the working directory, negating a previous branch
1188 the parent of the working directory, negating a previous branch
1189 change.
1189 change.
1190
1190
1191 Use the command :hg:`update` to switch to an existing branch. Use
1191 Use the command :hg:`update` to switch to an existing branch. Use
1192 :hg:`commit --close-branch` to mark this branch head as closed.
1192 :hg:`commit --close-branch` to mark this branch head as closed.
1193 When all heads of a branch are closed, the branch will be
1193 When all heads of a branch are closed, the branch will be
1194 considered closed.
1194 considered closed.
1195
1195
1196 Returns 0 on success.
1196 Returns 0 on success.
1197 """
1197 """
1198 if label:
1198 if label:
1199 label = label.strip()
1199 label = label.strip()
1200
1200
1201 if not opts.get('clean') and not label:
1201 if not opts.get('clean') and not label:
1202 ui.write("%s\n" % repo.dirstate.branch())
1202 ui.write("%s\n" % repo.dirstate.branch())
1203 return
1203 return
1204
1204
1205 with repo.wlock():
1205 with repo.wlock():
1206 if opts.get('clean'):
1206 if opts.get('clean'):
1207 label = repo[None].p1().branch()
1207 label = repo[None].p1().branch()
1208 repo.dirstate.setbranch(label)
1208 repo.dirstate.setbranch(label)
1209 ui.status(_('reset working directory to branch %s\n') % label)
1209 ui.status(_('reset working directory to branch %s\n') % label)
1210 elif label:
1210 elif label:
1211 if not opts.get('force') and label in repo.branchmap():
1211 if not opts.get('force') and label in repo.branchmap():
1212 if label not in [p.branch() for p in repo[None].parents()]:
1212 if label not in [p.branch() for p in repo[None].parents()]:
1213 raise error.Abort(_('a branch of the same name already'
1213 raise error.Abort(_('a branch of the same name already'
1214 ' exists'),
1214 ' exists'),
1215 # i18n: "it" refers to an existing branch
1215 # i18n: "it" refers to an existing branch
1216 hint=_("use 'hg update' to switch to it"))
1216 hint=_("use 'hg update' to switch to it"))
1217 scmutil.checknewlabel(repo, label, 'branch')
1217 scmutil.checknewlabel(repo, label, 'branch')
1218 repo.dirstate.setbranch(label)
1218 repo.dirstate.setbranch(label)
1219 ui.status(_('marked working directory as branch %s\n') % label)
1219 ui.status(_('marked working directory as branch %s\n') % label)
1220
1220
1221 # find any open named branches aside from default
1221 # find any open named branches aside from default
1222 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1222 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1223 if n != "default" and not c]
1223 if n != "default" and not c]
1224 if not others:
1224 if not others:
1225 ui.status(_('(branches are permanent and global, '
1225 ui.status(_('(branches are permanent and global, '
1226 'did you want a bookmark?)\n'))
1226 'did you want a bookmark?)\n'))
1227
1227
1228 @command('branches',
1228 @command('branches',
1229 [('a', 'active', False,
1229 [('a', 'active', False,
1230 _('show only branches that have unmerged heads (DEPRECATED)')),
1230 _('show only branches that have unmerged heads (DEPRECATED)')),
1231 ('c', 'closed', False, _('show normal and closed branches')),
1231 ('c', 'closed', False, _('show normal and closed branches')),
1232 ] + formatteropts,
1232 ] + formatteropts,
1233 _('[-ac]'))
1233 _('[-ac]'))
1234 def branches(ui, repo, active=False, closed=False, **opts):
1234 def branches(ui, repo, active=False, closed=False, **opts):
1235 """list repository named branches
1235 """list repository named branches
1236
1236
1237 List the repository's named branches, indicating which ones are
1237 List the repository's named branches, indicating which ones are
1238 inactive. If -c/--closed is specified, also list branches which have
1238 inactive. If -c/--closed is specified, also list branches which have
1239 been marked closed (see :hg:`commit --close-branch`).
1239 been marked closed (see :hg:`commit --close-branch`).
1240
1240
1241 Use the command :hg:`update` to switch to an existing branch.
1241 Use the command :hg:`update` to switch to an existing branch.
1242
1242
1243 Returns 0.
1243 Returns 0.
1244 """
1244 """
1245
1245
1246 fm = ui.formatter('branches', opts)
1246 fm = ui.formatter('branches', opts)
1247 hexfunc = fm.hexfunc
1247 hexfunc = fm.hexfunc
1248
1248
1249 allheads = set(repo.heads())
1249 allheads = set(repo.heads())
1250 branches = []
1250 branches = []
1251 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1251 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1252 isactive = not isclosed and bool(set(heads) & allheads)
1252 isactive = not isclosed and bool(set(heads) & allheads)
1253 branches.append((tag, repo[tip], isactive, not isclosed))
1253 branches.append((tag, repo[tip], isactive, not isclosed))
1254 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1254 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1255 reverse=True)
1255 reverse=True)
1256
1256
1257 for tag, ctx, isactive, isopen in branches:
1257 for tag, ctx, isactive, isopen in branches:
1258 if active and not isactive:
1258 if active and not isactive:
1259 continue
1259 continue
1260 if isactive:
1260 if isactive:
1261 label = 'branches.active'
1261 label = 'branches.active'
1262 notice = ''
1262 notice = ''
1263 elif not isopen:
1263 elif not isopen:
1264 if not closed:
1264 if not closed:
1265 continue
1265 continue
1266 label = 'branches.closed'
1266 label = 'branches.closed'
1267 notice = _(' (closed)')
1267 notice = _(' (closed)')
1268 else:
1268 else:
1269 label = 'branches.inactive'
1269 label = 'branches.inactive'
1270 notice = _(' (inactive)')
1270 notice = _(' (inactive)')
1271 current = (tag == repo.dirstate.branch())
1271 current = (tag == repo.dirstate.branch())
1272 if current:
1272 if current:
1273 label = 'branches.current'
1273 label = 'branches.current'
1274
1274
1275 fm.startitem()
1275 fm.startitem()
1276 fm.write('branch', '%s', tag, label=label)
1276 fm.write('branch', '%s', tag, label=label)
1277 rev = ctx.rev()
1277 rev = ctx.rev()
1278 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1278 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1279 fmt = ' ' * padsize + ' %d:%s'
1279 fmt = ' ' * padsize + ' %d:%s'
1280 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1280 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1281 label='log.changeset changeset.%s' % ctx.phasestr())
1281 label='log.changeset changeset.%s' % ctx.phasestr())
1282 fm.data(active=isactive, closed=not isopen, current=current)
1282 fm.data(active=isactive, closed=not isopen, current=current)
1283 if not ui.quiet:
1283 if not ui.quiet:
1284 fm.plain(notice)
1284 fm.plain(notice)
1285 fm.plain('\n')
1285 fm.plain('\n')
1286 fm.end()
1286 fm.end()
1287
1287
1288 @command('bundle',
1288 @command('bundle',
1289 [('f', 'force', None, _('run even when the destination is unrelated')),
1289 [('f', 'force', None, _('run even when the destination is unrelated')),
1290 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1290 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1291 _('REV')),
1291 _('REV')),
1292 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1292 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1293 _('BRANCH')),
1293 _('BRANCH')),
1294 ('', 'base', [],
1294 ('', 'base', [],
1295 _('a base changeset assumed to be available at the destination'),
1295 _('a base changeset assumed to be available at the destination'),
1296 _('REV')),
1296 _('REV')),
1297 ('a', 'all', None, _('bundle all changesets in the repository')),
1297 ('a', 'all', None, _('bundle all changesets in the repository')),
1298 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1298 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1299 ] + remoteopts,
1299 ] + remoteopts,
1300 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1300 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1301 def bundle(ui, repo, fname, dest=None, **opts):
1301 def bundle(ui, repo, fname, dest=None, **opts):
1302 """create a changegroup file
1302 """create a changegroup file
1303
1303
1304 Generate a changegroup file collecting changesets to be added
1304 Generate a changegroup file collecting changesets to be added
1305 to a repository.
1305 to a repository.
1306
1306
1307 To create a bundle containing all changesets, use -a/--all
1307 To create a bundle containing all changesets, use -a/--all
1308 (or --base null). Otherwise, hg assumes the destination will have
1308 (or --base null). Otherwise, hg assumes the destination will have
1309 all the nodes you specify with --base parameters. Otherwise, hg
1309 all the nodes you specify with --base parameters. Otherwise, hg
1310 will assume the repository has all the nodes in destination, or
1310 will assume the repository has all the nodes in destination, or
1311 default-push/default if no destination is specified.
1311 default-push/default if no destination is specified.
1312
1312
1313 You can change bundle format with the -t/--type option. You can
1313 You can change bundle format with the -t/--type option. You can
1314 specify a compression, a bundle version or both using a dash
1314 specify a compression, a bundle version or both using a dash
1315 (comp-version). The available compression methods are: none, bzip2,
1315 (comp-version). The available compression methods are: none, bzip2,
1316 and gzip (by default, bundles are compressed using bzip2). The
1316 and gzip (by default, bundles are compressed using bzip2). The
1317 available formats are: v1, v2 (default to most suitable).
1317 available formats are: v1, v2 (default to most suitable).
1318
1318
1319 The bundle file can then be transferred using conventional means
1319 The bundle file can then be transferred using conventional means
1320 and applied to another repository with the unbundle or pull
1320 and applied to another repository with the unbundle or pull
1321 command. This is useful when direct push and pull are not
1321 command. This is useful when direct push and pull are not
1322 available or when exporting an entire repository is undesirable.
1322 available or when exporting an entire repository is undesirable.
1323
1323
1324 Applying bundles preserves all changeset contents including
1324 Applying bundles preserves all changeset contents including
1325 permissions, copy/rename information, and revision history.
1325 permissions, copy/rename information, and revision history.
1326
1326
1327 Returns 0 on success, 1 if no changes found.
1327 Returns 0 on success, 1 if no changes found.
1328 """
1328 """
1329 revs = None
1329 revs = None
1330 if 'rev' in opts:
1330 if 'rev' in opts:
1331 revstrings = opts['rev']
1331 revstrings = opts['rev']
1332 revs = scmutil.revrange(repo, revstrings)
1332 revs = scmutil.revrange(repo, revstrings)
1333 if revstrings and not revs:
1333 if revstrings and not revs:
1334 raise error.Abort(_('no commits to bundle'))
1334 raise error.Abort(_('no commits to bundle'))
1335
1335
1336 bundletype = opts.get('type', 'bzip2').lower()
1336 bundletype = opts.get('type', 'bzip2').lower()
1337 try:
1337 try:
1338 bcompression, cgversion, params = exchange.parsebundlespec(
1338 bcompression, cgversion, params = exchange.parsebundlespec(
1339 repo, bundletype, strict=False)
1339 repo, bundletype, strict=False)
1340 except error.UnsupportedBundleSpecification as e:
1340 except error.UnsupportedBundleSpecification as e:
1341 raise error.Abort(str(e),
1341 raise error.Abort(str(e),
1342 hint=_('see "hg help bundle" for supported '
1342 hint=_('see "hg help bundle" for supported '
1343 'values for --type'))
1343 'values for --type'))
1344
1344
1345 # Packed bundles are a pseudo bundle format for now.
1345 # Packed bundles are a pseudo bundle format for now.
1346 if cgversion == 's1':
1346 if cgversion == 's1':
1347 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1347 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1348 hint=_('use "hg debugcreatestreamclonebundle"'))
1348 hint=_('use "hg debugcreatestreamclonebundle"'))
1349
1349
1350 if opts.get('all'):
1350 if opts.get('all'):
1351 if dest:
1351 if dest:
1352 raise error.Abort(_("--all is incompatible with specifying "
1352 raise error.Abort(_("--all is incompatible with specifying "
1353 "a destination"))
1353 "a destination"))
1354 if opts.get('base'):
1354 if opts.get('base'):
1355 ui.warn(_("ignoring --base because --all was specified\n"))
1355 ui.warn(_("ignoring --base because --all was specified\n"))
1356 base = ['null']
1356 base = ['null']
1357 else:
1357 else:
1358 base = scmutil.revrange(repo, opts.get('base'))
1358 base = scmutil.revrange(repo, opts.get('base'))
1359 # TODO: get desired bundlecaps from command line.
1359 # TODO: get desired bundlecaps from command line.
1360 bundlecaps = None
1360 bundlecaps = None
1361 if base:
1361 if base:
1362 if dest:
1362 if dest:
1363 raise error.Abort(_("--base is incompatible with specifying "
1363 raise error.Abort(_("--base is incompatible with specifying "
1364 "a destination"))
1364 "a destination"))
1365 common = [repo.lookup(rev) for rev in base]
1365 common = [repo.lookup(rev) for rev in base]
1366 heads = revs and map(repo.lookup, revs) or revs
1366 heads = revs and map(repo.lookup, revs) or revs
1367 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1367 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1368 common=common, bundlecaps=bundlecaps,
1368 common=common, bundlecaps=bundlecaps,
1369 version=cgversion)
1369 version=cgversion)
1370 outgoing = None
1370 outgoing = None
1371 else:
1371 else:
1372 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1372 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1373 dest, branches = hg.parseurl(dest, opts.get('branch'))
1373 dest, branches = hg.parseurl(dest, opts.get('branch'))
1374 other = hg.peer(repo, opts, dest)
1374 other = hg.peer(repo, opts, dest)
1375 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1375 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1376 heads = revs and map(repo.lookup, revs) or revs
1376 heads = revs and map(repo.lookup, revs) or revs
1377 outgoing = discovery.findcommonoutgoing(repo, other,
1377 outgoing = discovery.findcommonoutgoing(repo, other,
1378 onlyheads=heads,
1378 onlyheads=heads,
1379 force=opts.get('force'),
1379 force=opts.get('force'),
1380 portable=True)
1380 portable=True)
1381 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1381 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1382 bundlecaps, version=cgversion)
1382 bundlecaps, version=cgversion)
1383 if not cg:
1383 if not cg:
1384 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1384 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1385 return 1
1385 return 1
1386
1386
1387 if cgversion == '01': #bundle1
1387 if cgversion == '01': #bundle1
1388 if bcompression is None:
1388 if bcompression is None:
1389 bcompression = 'UN'
1389 bcompression = 'UN'
1390 bversion = 'HG10' + bcompression
1390 bversion = 'HG10' + bcompression
1391 bcompression = None
1391 bcompression = None
1392 else:
1392 else:
1393 assert cgversion == '02'
1393 assert cgversion == '02'
1394 bversion = 'HG20'
1394 bversion = 'HG20'
1395
1395
1396
1396
1397 changegroup.writebundle(ui, cg, fname, bversion, compression=bcompression)
1397 changegroup.writebundle(ui, cg, fname, bversion, compression=bcompression)
1398
1398
1399 @command('cat',
1399 @command('cat',
1400 [('o', 'output', '',
1400 [('o', 'output', '',
1401 _('print output to file with formatted name'), _('FORMAT')),
1401 _('print output to file with formatted name'), _('FORMAT')),
1402 ('r', 'rev', '', _('print the given revision'), _('REV')),
1402 ('r', 'rev', '', _('print the given revision'), _('REV')),
1403 ('', 'decode', None, _('apply any matching decode filter')),
1403 ('', 'decode', None, _('apply any matching decode filter')),
1404 ] + walkopts,
1404 ] + walkopts,
1405 _('[OPTION]... FILE...'),
1405 _('[OPTION]... FILE...'),
1406 inferrepo=True)
1406 inferrepo=True)
1407 def cat(ui, repo, file1, *pats, **opts):
1407 def cat(ui, repo, file1, *pats, **opts):
1408 """output the current or given revision of files
1408 """output the current or given revision of files
1409
1409
1410 Print the specified files as they were at the given revision. If
1410 Print the specified files as they were at the given revision. If
1411 no revision is given, the parent of the working directory is used.
1411 no revision is given, the parent of the working directory is used.
1412
1412
1413 Output may be to a file, in which case the name of the file is
1413 Output may be to a file, in which case the name of the file is
1414 given using a format string. The formatting rules as follows:
1414 given using a format string. The formatting rules as follows:
1415
1415
1416 :``%%``: literal "%" character
1416 :``%%``: literal "%" character
1417 :``%s``: basename of file being printed
1417 :``%s``: basename of file being printed
1418 :``%d``: dirname of file being printed, or '.' if in repository root
1418 :``%d``: dirname of file being printed, or '.' if in repository root
1419 :``%p``: root-relative path name of file being printed
1419 :``%p``: root-relative path name of file being printed
1420 :``%H``: changeset hash (40 hexadecimal digits)
1420 :``%H``: changeset hash (40 hexadecimal digits)
1421 :``%R``: changeset revision number
1421 :``%R``: changeset revision number
1422 :``%h``: short-form changeset hash (12 hexadecimal digits)
1422 :``%h``: short-form changeset hash (12 hexadecimal digits)
1423 :``%r``: zero-padded changeset revision number
1423 :``%r``: zero-padded changeset revision number
1424 :``%b``: basename of the exporting repository
1424 :``%b``: basename of the exporting repository
1425
1425
1426 Returns 0 on success.
1426 Returns 0 on success.
1427 """
1427 """
1428 ctx = scmutil.revsingle(repo, opts.get('rev'))
1428 ctx = scmutil.revsingle(repo, opts.get('rev'))
1429 m = scmutil.match(ctx, (file1,) + pats, opts)
1429 m = scmutil.match(ctx, (file1,) + pats, opts)
1430
1430
1431 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1431 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1432
1432
1433 @command('^clone',
1433 @command('^clone',
1434 [('U', 'noupdate', None, _('the clone will include an empty working '
1434 [('U', 'noupdate', None, _('the clone will include an empty working '
1435 'directory (only a repository)')),
1435 'directory (only a repository)')),
1436 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1436 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1437 _('REV')),
1437 _('REV')),
1438 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1438 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1439 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1439 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1440 ('', 'pull', None, _('use pull protocol to copy metadata')),
1440 ('', 'pull', None, _('use pull protocol to copy metadata')),
1441 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1441 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1442 ] + remoteopts,
1442 ] + remoteopts,
1443 _('[OPTION]... SOURCE [DEST]'),
1443 _('[OPTION]... SOURCE [DEST]'),
1444 norepo=True)
1444 norepo=True)
1445 def clone(ui, source, dest=None, **opts):
1445 def clone(ui, source, dest=None, **opts):
1446 """make a copy of an existing repository
1446 """make a copy of an existing repository
1447
1447
1448 Create a copy of an existing repository in a new directory.
1448 Create a copy of an existing repository in a new directory.
1449
1449
1450 If no destination directory name is specified, it defaults to the
1450 If no destination directory name is specified, it defaults to the
1451 basename of the source.
1451 basename of the source.
1452
1452
1453 The location of the source is added to the new repository's
1453 The location of the source is added to the new repository's
1454 ``.hg/hgrc`` file, as the default to be used for future pulls.
1454 ``.hg/hgrc`` file, as the default to be used for future pulls.
1455
1455
1456 Only local paths and ``ssh://`` URLs are supported as
1456 Only local paths and ``ssh://`` URLs are supported as
1457 destinations. For ``ssh://`` destinations, no working directory or
1457 destinations. For ``ssh://`` destinations, no working directory or
1458 ``.hg/hgrc`` will be created on the remote side.
1458 ``.hg/hgrc`` will be created on the remote side.
1459
1459
1460 If the source repository has a bookmark called '@' set, that
1460 If the source repository has a bookmark called '@' set, that
1461 revision will be checked out in the new repository by default.
1461 revision will be checked out in the new repository by default.
1462
1462
1463 To check out a particular version, use -u/--update, or
1463 To check out a particular version, use -u/--update, or
1464 -U/--noupdate to create a clone with no working directory.
1464 -U/--noupdate to create a clone with no working directory.
1465
1465
1466 To pull only a subset of changesets, specify one or more revisions
1466 To pull only a subset of changesets, specify one or more revisions
1467 identifiers with -r/--rev or branches with -b/--branch. The
1467 identifiers with -r/--rev or branches with -b/--branch. The
1468 resulting clone will contain only the specified changesets and
1468 resulting clone will contain only the specified changesets and
1469 their ancestors. These options (or 'clone src#rev dest') imply
1469 their ancestors. These options (or 'clone src#rev dest') imply
1470 --pull, even for local source repositories.
1470 --pull, even for local source repositories.
1471
1471
1472 .. note::
1472 .. note::
1473
1473
1474 Specifying a tag will include the tagged changeset but not the
1474 Specifying a tag will include the tagged changeset but not the
1475 changeset containing the tag.
1475 changeset containing the tag.
1476
1476
1477 .. container:: verbose
1477 .. container:: verbose
1478
1478
1479 For efficiency, hardlinks are used for cloning whenever the
1479 For efficiency, hardlinks are used for cloning whenever the
1480 source and destination are on the same filesystem (note this
1480 source and destination are on the same filesystem (note this
1481 applies only to the repository data, not to the working
1481 applies only to the repository data, not to the working
1482 directory). Some filesystems, such as AFS, implement hardlinking
1482 directory). Some filesystems, such as AFS, implement hardlinking
1483 incorrectly, but do not report errors. In these cases, use the
1483 incorrectly, but do not report errors. In these cases, use the
1484 --pull option to avoid hardlinking.
1484 --pull option to avoid hardlinking.
1485
1485
1486 In some cases, you can clone repositories and the working
1486 In some cases, you can clone repositories and the working
1487 directory using full hardlinks with ::
1487 directory using full hardlinks with ::
1488
1488
1489 $ cp -al REPO REPOCLONE
1489 $ cp -al REPO REPOCLONE
1490
1490
1491 This is the fastest way to clone, but it is not always safe. The
1491 This is the fastest way to clone, but it is not always safe. The
1492 operation is not atomic (making sure REPO is not modified during
1492 operation is not atomic (making sure REPO is not modified during
1493 the operation is up to you) and you have to make sure your
1493 the operation is up to you) and you have to make sure your
1494 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1494 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1495 so). Also, this is not compatible with certain extensions that
1495 so). Also, this is not compatible with certain extensions that
1496 place their metadata under the .hg directory, such as mq.
1496 place their metadata under the .hg directory, such as mq.
1497
1497
1498 Mercurial will update the working directory to the first applicable
1498 Mercurial will update the working directory to the first applicable
1499 revision from this list:
1499 revision from this list:
1500
1500
1501 a) null if -U or the source repository has no changesets
1501 a) null if -U or the source repository has no changesets
1502 b) if -u . and the source repository is local, the first parent of
1502 b) if -u . and the source repository is local, the first parent of
1503 the source repository's working directory
1503 the source repository's working directory
1504 c) the changeset specified with -u (if a branch name, this means the
1504 c) the changeset specified with -u (if a branch name, this means the
1505 latest head of that branch)
1505 latest head of that branch)
1506 d) the changeset specified with -r
1506 d) the changeset specified with -r
1507 e) the tipmost head specified with -b
1507 e) the tipmost head specified with -b
1508 f) the tipmost head specified with the url#branch source syntax
1508 f) the tipmost head specified with the url#branch source syntax
1509 g) the revision marked with the '@' bookmark, if present
1509 g) the revision marked with the '@' bookmark, if present
1510 h) the tipmost head of the default branch
1510 h) the tipmost head of the default branch
1511 i) tip
1511 i) tip
1512
1512
1513 When cloning from servers that support it, Mercurial may fetch
1513 When cloning from servers that support it, Mercurial may fetch
1514 pre-generated data from a server-advertised URL. When this is done,
1514 pre-generated data from a server-advertised URL. When this is done,
1515 hooks operating on incoming changesets and changegroups may fire twice,
1515 hooks operating on incoming changesets and changegroups may fire twice,
1516 once for the bundle fetched from the URL and another for any additional
1516 once for the bundle fetched from the URL and another for any additional
1517 data not fetched from this URL. In addition, if an error occurs, the
1517 data not fetched from this URL. In addition, if an error occurs, the
1518 repository may be rolled back to a partial clone. This behavior may
1518 repository may be rolled back to a partial clone. This behavior may
1519 change in future releases. See :hg:`help -e clonebundles` for more.
1519 change in future releases. See :hg:`help -e clonebundles` for more.
1520
1520
1521 Examples:
1521 Examples:
1522
1522
1523 - clone a remote repository to a new directory named hg/::
1523 - clone a remote repository to a new directory named hg/::
1524
1524
1525 hg clone http://selenic.com/hg
1525 hg clone http://selenic.com/hg
1526
1526
1527 - create a lightweight local clone::
1527 - create a lightweight local clone::
1528
1528
1529 hg clone project/ project-feature/
1529 hg clone project/ project-feature/
1530
1530
1531 - clone from an absolute path on an ssh server (note double-slash)::
1531 - clone from an absolute path on an ssh server (note double-slash)::
1532
1532
1533 hg clone ssh://user@server//home/projects/alpha/
1533 hg clone ssh://user@server//home/projects/alpha/
1534
1534
1535 - do a high-speed clone over a LAN while checking out a
1535 - do a high-speed clone over a LAN while checking out a
1536 specified version::
1536 specified version::
1537
1537
1538 hg clone --uncompressed http://server/repo -u 1.5
1538 hg clone --uncompressed http://server/repo -u 1.5
1539
1539
1540 - create a repository without changesets after a particular revision::
1540 - create a repository without changesets after a particular revision::
1541
1541
1542 hg clone -r 04e544 experimental/ good/
1542 hg clone -r 04e544 experimental/ good/
1543
1543
1544 - clone (and track) a particular named branch::
1544 - clone (and track) a particular named branch::
1545
1545
1546 hg clone http://selenic.com/hg#stable
1546 hg clone http://selenic.com/hg#stable
1547
1547
1548 See :hg:`help urls` for details on specifying URLs.
1548 See :hg:`help urls` for details on specifying URLs.
1549
1549
1550 Returns 0 on success.
1550 Returns 0 on success.
1551 """
1551 """
1552 if opts.get('noupdate') and opts.get('updaterev'):
1552 if opts.get('noupdate') and opts.get('updaterev'):
1553 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1553 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1554
1554
1555 r = hg.clone(ui, opts, source, dest,
1555 r = hg.clone(ui, opts, source, dest,
1556 pull=opts.get('pull'),
1556 pull=opts.get('pull'),
1557 stream=opts.get('uncompressed'),
1557 stream=opts.get('uncompressed'),
1558 rev=opts.get('rev'),
1558 rev=opts.get('rev'),
1559 update=opts.get('updaterev') or not opts.get('noupdate'),
1559 update=opts.get('updaterev') or not opts.get('noupdate'),
1560 branch=opts.get('branch'),
1560 branch=opts.get('branch'),
1561 shareopts=opts.get('shareopts'))
1561 shareopts=opts.get('shareopts'))
1562
1562
1563 return r is None
1563 return r is None
1564
1564
1565 @command('^commit|ci',
1565 @command('^commit|ci',
1566 [('A', 'addremove', None,
1566 [('A', 'addremove', None,
1567 _('mark new/missing files as added/removed before committing')),
1567 _('mark new/missing files as added/removed before committing')),
1568 ('', 'close-branch', None,
1568 ('', 'close-branch', None,
1569 _('mark a branch head as closed')),
1569 _('mark a branch head as closed')),
1570 ('', 'amend', None, _('amend the parent of the working directory')),
1570 ('', 'amend', None, _('amend the parent of the working directory')),
1571 ('s', 'secret', None, _('use the secret phase for committing')),
1571 ('s', 'secret', None, _('use the secret phase for committing')),
1572 ('e', 'edit', None, _('invoke editor on commit messages')),
1572 ('e', 'edit', None, _('invoke editor on commit messages')),
1573 ('i', 'interactive', None, _('use interactive mode')),
1573 ('i', 'interactive', None, _('use interactive mode')),
1574 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1574 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1575 _('[OPTION]... [FILE]...'),
1575 _('[OPTION]... [FILE]...'),
1576 inferrepo=True)
1576 inferrepo=True)
1577 def commit(ui, repo, *pats, **opts):
1577 def commit(ui, repo, *pats, **opts):
1578 """commit the specified files or all outstanding changes
1578 """commit the specified files or all outstanding changes
1579
1579
1580 Commit changes to the given files into the repository. Unlike a
1580 Commit changes to the given files into the repository. Unlike a
1581 centralized SCM, this operation is a local operation. See
1581 centralized SCM, this operation is a local operation. See
1582 :hg:`push` for a way to actively distribute your changes.
1582 :hg:`push` for a way to actively distribute your changes.
1583
1583
1584 If a list of files is omitted, all changes reported by :hg:`status`
1584 If a list of files is omitted, all changes reported by :hg:`status`
1585 will be committed.
1585 will be committed.
1586
1586
1587 If you are committing the result of a merge, do not provide any
1587 If you are committing the result of a merge, do not provide any
1588 filenames or -I/-X filters.
1588 filenames or -I/-X filters.
1589
1589
1590 If no commit message is specified, Mercurial starts your
1590 If no commit message is specified, Mercurial starts your
1591 configured editor where you can enter a message. In case your
1591 configured editor where you can enter a message. In case your
1592 commit fails, you will find a backup of your message in
1592 commit fails, you will find a backup of your message in
1593 ``.hg/last-message.txt``.
1593 ``.hg/last-message.txt``.
1594
1594
1595 The --close-branch flag can be used to mark the current branch
1595 The --close-branch flag can be used to mark the current branch
1596 head closed. When all heads of a branch are closed, the branch
1596 head closed. When all heads of a branch are closed, the branch
1597 will be considered closed and no longer listed.
1597 will be considered closed and no longer listed.
1598
1598
1599 The --amend flag can be used to amend the parent of the
1599 The --amend flag can be used to amend the parent of the
1600 working directory with a new commit that contains the changes
1600 working directory with a new commit that contains the changes
1601 in the parent in addition to those currently reported by :hg:`status`,
1601 in the parent in addition to those currently reported by :hg:`status`,
1602 if there are any. The old commit is stored in a backup bundle in
1602 if there are any. The old commit is stored in a backup bundle in
1603 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1603 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1604 on how to restore it).
1604 on how to restore it).
1605
1605
1606 Message, user and date are taken from the amended commit unless
1606 Message, user and date are taken from the amended commit unless
1607 specified. When a message isn't specified on the command line,
1607 specified. When a message isn't specified on the command line,
1608 the editor will open with the message of the amended commit.
1608 the editor will open with the message of the amended commit.
1609
1609
1610 It is not possible to amend public changesets (see :hg:`help phases`)
1610 It is not possible to amend public changesets (see :hg:`help phases`)
1611 or changesets that have children.
1611 or changesets that have children.
1612
1612
1613 See :hg:`help dates` for a list of formats valid for -d/--date.
1613 See :hg:`help dates` for a list of formats valid for -d/--date.
1614
1614
1615 Returns 0 on success, 1 if nothing changed.
1615 Returns 0 on success, 1 if nothing changed.
1616
1616
1617 .. container:: verbose
1617 .. container:: verbose
1618
1618
1619 Examples:
1619 Examples:
1620
1620
1621 - commit all files ending in .py::
1621 - commit all files ending in .py::
1622
1622
1623 hg commit --include "set:**.py"
1623 hg commit --include "set:**.py"
1624
1624
1625 - commit all non-binary files::
1625 - commit all non-binary files::
1626
1626
1627 hg commit --exclude "set:binary()"
1627 hg commit --exclude "set:binary()"
1628
1628
1629 - amend the current commit and set the date to now::
1629 - amend the current commit and set the date to now::
1630
1630
1631 hg commit --amend --date now
1631 hg commit --amend --date now
1632 """
1632 """
1633 wlock = lock = None
1633 wlock = lock = None
1634 try:
1634 try:
1635 wlock = repo.wlock()
1635 wlock = repo.wlock()
1636 lock = repo.lock()
1636 lock = repo.lock()
1637 return _docommit(ui, repo, *pats, **opts)
1637 return _docommit(ui, repo, *pats, **opts)
1638 finally:
1638 finally:
1639 release(lock, wlock)
1639 release(lock, wlock)
1640
1640
1641 def _docommit(ui, repo, *pats, **opts):
1641 def _docommit(ui, repo, *pats, **opts):
1642 if opts.get('interactive'):
1642 if opts.get('interactive'):
1643 opts.pop('interactive')
1643 opts.pop('interactive')
1644 cmdutil.dorecord(ui, repo, commit, None, False,
1644 cmdutil.dorecord(ui, repo, commit, None, False,
1645 cmdutil.recordfilter, *pats, **opts)
1645 cmdutil.recordfilter, *pats, **opts)
1646 return
1646 return
1647
1647
1648 if opts.get('subrepos'):
1648 if opts.get('subrepos'):
1649 if opts.get('amend'):
1649 if opts.get('amend'):
1650 raise error.Abort(_('cannot amend with --subrepos'))
1650 raise error.Abort(_('cannot amend with --subrepos'))
1651 # Let --subrepos on the command line override config setting.
1651 # Let --subrepos on the command line override config setting.
1652 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1652 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1653
1653
1654 cmdutil.checkunfinished(repo, commit=True)
1654 cmdutil.checkunfinished(repo, commit=True)
1655
1655
1656 branch = repo[None].branch()
1656 branch = repo[None].branch()
1657 bheads = repo.branchheads(branch)
1657 bheads = repo.branchheads(branch)
1658
1658
1659 extra = {}
1659 extra = {}
1660 if opts.get('close_branch'):
1660 if opts.get('close_branch'):
1661 extra['close'] = 1
1661 extra['close'] = 1
1662
1662
1663 if not bheads:
1663 if not bheads:
1664 raise error.Abort(_('can only close branch heads'))
1664 raise error.Abort(_('can only close branch heads'))
1665 elif opts.get('amend'):
1665 elif opts.get('amend'):
1666 if repo[None].parents()[0].p1().branch() != branch and \
1666 if repo[None].parents()[0].p1().branch() != branch and \
1667 repo[None].parents()[0].p2().branch() != branch:
1667 repo[None].parents()[0].p2().branch() != branch:
1668 raise error.Abort(_('can only close branch heads'))
1668 raise error.Abort(_('can only close branch heads'))
1669
1669
1670 if opts.get('amend'):
1670 if opts.get('amend'):
1671 if ui.configbool('ui', 'commitsubrepos'):
1671 if ui.configbool('ui', 'commitsubrepos'):
1672 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1672 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1673
1673
1674 old = repo['.']
1674 old = repo['.']
1675 if not old.mutable():
1675 if not old.mutable():
1676 raise error.Abort(_('cannot amend public changesets'))
1676 raise error.Abort(_('cannot amend public changesets'))
1677 if len(repo[None].parents()) > 1:
1677 if len(repo[None].parents()) > 1:
1678 raise error.Abort(_('cannot amend while merging'))
1678 raise error.Abort(_('cannot amend while merging'))
1679 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1679 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1680 if not allowunstable and old.children():
1680 if not allowunstable and old.children():
1681 raise error.Abort(_('cannot amend changeset with children'))
1681 raise error.Abort(_('cannot amend changeset with children'))
1682
1682
1683 newextra = extra.copy()
1683 newextra = extra.copy()
1684 newextra['branch'] = branch
1684 newextra['branch'] = branch
1685 extra = newextra
1685 extra = newextra
1686 # commitfunc is used only for temporary amend commit by cmdutil.amend
1686 # commitfunc is used only for temporary amend commit by cmdutil.amend
1687 def commitfunc(ui, repo, message, match, opts):
1687 def commitfunc(ui, repo, message, match, opts):
1688 return repo.commit(message,
1688 return repo.commit(message,
1689 opts.get('user') or old.user(),
1689 opts.get('user') or old.user(),
1690 opts.get('date') or old.date(),
1690 opts.get('date') or old.date(),
1691 match,
1691 match,
1692 extra=extra)
1692 extra=extra)
1693
1693
1694 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1694 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1695 if node == old.node():
1695 if node == old.node():
1696 ui.status(_("nothing changed\n"))
1696 ui.status(_("nothing changed\n"))
1697 return 1
1697 return 1
1698 else:
1698 else:
1699 def commitfunc(ui, repo, message, match, opts):
1699 def commitfunc(ui, repo, message, match, opts):
1700 backup = ui.backupconfig('phases', 'new-commit')
1700 backup = ui.backupconfig('phases', 'new-commit')
1701 baseui = repo.baseui
1701 baseui = repo.baseui
1702 basebackup = baseui.backupconfig('phases', 'new-commit')
1702 basebackup = baseui.backupconfig('phases', 'new-commit')
1703 try:
1703 try:
1704 if opts.get('secret'):
1704 if opts.get('secret'):
1705 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1705 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1706 # Propagate to subrepos
1706 # Propagate to subrepos
1707 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1707 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1708
1708
1709 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1709 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1710 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1710 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1711 return repo.commit(message, opts.get('user'), opts.get('date'),
1711 return repo.commit(message, opts.get('user'), opts.get('date'),
1712 match,
1712 match,
1713 editor=editor,
1713 editor=editor,
1714 extra=extra)
1714 extra=extra)
1715 finally:
1715 finally:
1716 ui.restoreconfig(backup)
1716 ui.restoreconfig(backup)
1717 repo.baseui.restoreconfig(basebackup)
1717 repo.baseui.restoreconfig(basebackup)
1718
1718
1719
1719
1720 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1720 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1721
1721
1722 if not node:
1722 if not node:
1723 stat = cmdutil.postcommitstatus(repo, pats, opts)
1723 stat = cmdutil.postcommitstatus(repo, pats, opts)
1724 if stat[3]:
1724 if stat[3]:
1725 ui.status(_("nothing changed (%d missing files, see "
1725 ui.status(_("nothing changed (%d missing files, see "
1726 "'hg status')\n") % len(stat[3]))
1726 "'hg status')\n") % len(stat[3]))
1727 else:
1727 else:
1728 ui.status(_("nothing changed\n"))
1728 ui.status(_("nothing changed\n"))
1729 return 1
1729 return 1
1730
1730
1731 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1731 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1732
1732
1733 @command('config|showconfig|debugconfig',
1733 @command('config|showconfig|debugconfig',
1734 [('u', 'untrusted', None, _('show untrusted configuration options')),
1734 [('u', 'untrusted', None, _('show untrusted configuration options')),
1735 ('e', 'edit', None, _('edit user config')),
1735 ('e', 'edit', None, _('edit user config')),
1736 ('l', 'local', None, _('edit repository config')),
1736 ('l', 'local', None, _('edit repository config')),
1737 ('g', 'global', None, _('edit global config'))],
1737 ('g', 'global', None, _('edit global config'))],
1738 _('[-u] [NAME]...'),
1738 _('[-u] [NAME]...'),
1739 optionalrepo=True)
1739 optionalrepo=True)
1740 def config(ui, repo, *values, **opts):
1740 def config(ui, repo, *values, **opts):
1741 """show combined config settings from all hgrc files
1741 """show combined config settings from all hgrc files
1742
1742
1743 With no arguments, print names and values of all config items.
1743 With no arguments, print names and values of all config items.
1744
1744
1745 With one argument of the form section.name, print just the value
1745 With one argument of the form section.name, print just the value
1746 of that config item.
1746 of that config item.
1747
1747
1748 With multiple arguments, print names and values of all config
1748 With multiple arguments, print names and values of all config
1749 items with matching section names.
1749 items with matching section names.
1750
1750
1751 With --edit, start an editor on the user-level config file. With
1751 With --edit, start an editor on the user-level config file. With
1752 --global, edit the system-wide config file. With --local, edit the
1752 --global, edit the system-wide config file. With --local, edit the
1753 repository-level config file.
1753 repository-level config file.
1754
1754
1755 With --debug, the source (filename and line number) is printed
1755 With --debug, the source (filename and line number) is printed
1756 for each config item.
1756 for each config item.
1757
1757
1758 See :hg:`help config` for more information about config files.
1758 See :hg:`help config` for more information about config files.
1759
1759
1760 Returns 0 on success, 1 if NAME does not exist.
1760 Returns 0 on success, 1 if NAME does not exist.
1761
1761
1762 """
1762 """
1763
1763
1764 if opts.get('edit') or opts.get('local') or opts.get('global'):
1764 if opts.get('edit') or opts.get('local') or opts.get('global'):
1765 if opts.get('local') and opts.get('global'):
1765 if opts.get('local') and opts.get('global'):
1766 raise error.Abort(_("can't use --local and --global together"))
1766 raise error.Abort(_("can't use --local and --global together"))
1767
1767
1768 if opts.get('local'):
1768 if opts.get('local'):
1769 if not repo:
1769 if not repo:
1770 raise error.Abort(_("can't use --local outside a repository"))
1770 raise error.Abort(_("can't use --local outside a repository"))
1771 paths = [repo.join('hgrc')]
1771 paths = [repo.join('hgrc')]
1772 elif opts.get('global'):
1772 elif opts.get('global'):
1773 paths = scmutil.systemrcpath()
1773 paths = scmutil.systemrcpath()
1774 else:
1774 else:
1775 paths = scmutil.userrcpath()
1775 paths = scmutil.userrcpath()
1776
1776
1777 for f in paths:
1777 for f in paths:
1778 if os.path.exists(f):
1778 if os.path.exists(f):
1779 break
1779 break
1780 else:
1780 else:
1781 if opts.get('global'):
1781 if opts.get('global'):
1782 samplehgrc = uimod.samplehgrcs['global']
1782 samplehgrc = uimod.samplehgrcs['global']
1783 elif opts.get('local'):
1783 elif opts.get('local'):
1784 samplehgrc = uimod.samplehgrcs['local']
1784 samplehgrc = uimod.samplehgrcs['local']
1785 else:
1785 else:
1786 samplehgrc = uimod.samplehgrcs['user']
1786 samplehgrc = uimod.samplehgrcs['user']
1787
1787
1788 f = paths[0]
1788 f = paths[0]
1789 fp = open(f, "w")
1789 fp = open(f, "w")
1790 fp.write(samplehgrc)
1790 fp.write(samplehgrc)
1791 fp.close()
1791 fp.close()
1792
1792
1793 editor = ui.geteditor()
1793 editor = ui.geteditor()
1794 ui.system("%s \"%s\"" % (editor, f),
1794 ui.system("%s \"%s\"" % (editor, f),
1795 onerr=error.Abort, errprefix=_("edit failed"))
1795 onerr=error.Abort, errprefix=_("edit failed"))
1796 return
1796 return
1797
1797
1798 for f in scmutil.rcpath():
1798 for f in scmutil.rcpath():
1799 ui.debug('read config from: %s\n' % f)
1799 ui.debug('read config from: %s\n' % f)
1800 untrusted = bool(opts.get('untrusted'))
1800 untrusted = bool(opts.get('untrusted'))
1801 if values:
1801 if values:
1802 sections = [v for v in values if '.' not in v]
1802 sections = [v for v in values if '.' not in v]
1803 items = [v for v in values if '.' in v]
1803 items = [v for v in values if '.' in v]
1804 if len(items) > 1 or items and sections:
1804 if len(items) > 1 or items and sections:
1805 raise error.Abort(_('only one config item permitted'))
1805 raise error.Abort(_('only one config item permitted'))
1806 matched = False
1806 matched = False
1807 for section, name, value in ui.walkconfig(untrusted=untrusted):
1807 for section, name, value in ui.walkconfig(untrusted=untrusted):
1808 value = str(value).replace('\n', '\\n')
1808 value = str(value).replace('\n', '\\n')
1809 sectname = section + '.' + name
1809 sectname = section + '.' + name
1810 if values:
1810 if values:
1811 for v in values:
1811 for v in values:
1812 if v == section:
1812 if v == section:
1813 ui.debug('%s: ' %
1813 ui.debug('%s: ' %
1814 ui.configsource(section, name, untrusted))
1814 ui.configsource(section, name, untrusted))
1815 ui.write('%s=%s\n' % (sectname, value))
1815 ui.write('%s=%s\n' % (sectname, value))
1816 matched = True
1816 matched = True
1817 elif v == sectname:
1817 elif v == sectname:
1818 ui.debug('%s: ' %
1818 ui.debug('%s: ' %
1819 ui.configsource(section, name, untrusted))
1819 ui.configsource(section, name, untrusted))
1820 ui.write(value, '\n')
1820 ui.write(value, '\n')
1821 matched = True
1821 matched = True
1822 else:
1822 else:
1823 ui.debug('%s: ' %
1823 ui.debug('%s: ' %
1824 ui.configsource(section, name, untrusted))
1824 ui.configsource(section, name, untrusted))
1825 ui.write('%s=%s\n' % (sectname, value))
1825 ui.write('%s=%s\n' % (sectname, value))
1826 matched = True
1826 matched = True
1827 if matched:
1827 if matched:
1828 return 0
1828 return 0
1829 return 1
1829 return 1
1830
1830
1831 @command('copy|cp',
1831 @command('copy|cp',
1832 [('A', 'after', None, _('record a copy that has already occurred')),
1832 [('A', 'after', None, _('record a copy that has already occurred')),
1833 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1833 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1834 ] + walkopts + dryrunopts,
1834 ] + walkopts + dryrunopts,
1835 _('[OPTION]... [SOURCE]... DEST'))
1835 _('[OPTION]... [SOURCE]... DEST'))
1836 def copy(ui, repo, *pats, **opts):
1836 def copy(ui, repo, *pats, **opts):
1837 """mark files as copied for the next commit
1837 """mark files as copied for the next commit
1838
1838
1839 Mark dest as having copies of source files. If dest is a
1839 Mark dest as having copies of source files. If dest is a
1840 directory, copies are put in that directory. If dest is a file,
1840 directory, copies are put in that directory. If dest is a file,
1841 the source must be a single file.
1841 the source must be a single file.
1842
1842
1843 By default, this command copies the contents of files as they
1843 By default, this command copies the contents of files as they
1844 exist in the working directory. If invoked with -A/--after, the
1844 exist in the working directory. If invoked with -A/--after, the
1845 operation is recorded, but no copying is performed.
1845 operation is recorded, but no copying is performed.
1846
1846
1847 This command takes effect with the next commit. To undo a copy
1847 This command takes effect with the next commit. To undo a copy
1848 before that, see :hg:`revert`.
1848 before that, see :hg:`revert`.
1849
1849
1850 Returns 0 on success, 1 if errors are encountered.
1850 Returns 0 on success, 1 if errors are encountered.
1851 """
1851 """
1852 with repo.wlock(False):
1852 with repo.wlock(False):
1853 return cmdutil.copy(ui, repo, pats, opts)
1853 return cmdutil.copy(ui, repo, pats, opts)
1854
1854
1855 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1855 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1856 def debugancestor(ui, repo, *args):
1856 def debugancestor(ui, repo, *args):
1857 """find the ancestor revision of two revisions in a given index"""
1857 """find the ancestor revision of two revisions in a given index"""
1858 if len(args) == 3:
1858 if len(args) == 3:
1859 index, rev1, rev2 = args
1859 index, rev1, rev2 = args
1860 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1860 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1861 lookup = r.lookup
1861 lookup = r.lookup
1862 elif len(args) == 2:
1862 elif len(args) == 2:
1863 if not repo:
1863 if not repo:
1864 raise error.Abort(_("there is no Mercurial repository here "
1864 raise error.Abort(_("there is no Mercurial repository here "
1865 "(.hg not found)"))
1865 "(.hg not found)"))
1866 rev1, rev2 = args
1866 rev1, rev2 = args
1867 r = repo.changelog
1867 r = repo.changelog
1868 lookup = repo.lookup
1868 lookup = repo.lookup
1869 else:
1869 else:
1870 raise error.Abort(_('either two or three arguments required'))
1870 raise error.Abort(_('either two or three arguments required'))
1871 a = r.ancestor(lookup(rev1), lookup(rev2))
1871 a = r.ancestor(lookup(rev1), lookup(rev2))
1872 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1872 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1873
1873
1874 @command('debugbuilddag',
1874 @command('debugbuilddag',
1875 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1875 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1876 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1876 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1877 ('n', 'new-file', None, _('add new file at each rev'))],
1877 ('n', 'new-file', None, _('add new file at each rev'))],
1878 _('[OPTION]... [TEXT]'))
1878 _('[OPTION]... [TEXT]'))
1879 def debugbuilddag(ui, repo, text=None,
1879 def debugbuilddag(ui, repo, text=None,
1880 mergeable_file=False,
1880 mergeable_file=False,
1881 overwritten_file=False,
1881 overwritten_file=False,
1882 new_file=False):
1882 new_file=False):
1883 """builds a repo with a given DAG from scratch in the current empty repo
1883 """builds a repo with a given DAG from scratch in the current empty repo
1884
1884
1885 The description of the DAG is read from stdin if not given on the
1885 The description of the DAG is read from stdin if not given on the
1886 command line.
1886 command line.
1887
1887
1888 Elements:
1888 Elements:
1889
1889
1890 - "+n" is a linear run of n nodes based on the current default parent
1890 - "+n" is a linear run of n nodes based on the current default parent
1891 - "." is a single node based on the current default parent
1891 - "." is a single node based on the current default parent
1892 - "$" resets the default parent to null (implied at the start);
1892 - "$" resets the default parent to null (implied at the start);
1893 otherwise the default parent is always the last node created
1893 otherwise the default parent is always the last node created
1894 - "<p" sets the default parent to the backref p
1894 - "<p" sets the default parent to the backref p
1895 - "*p" is a fork at parent p, which is a backref
1895 - "*p" is a fork at parent p, which is a backref
1896 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1896 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1897 - "/p2" is a merge of the preceding node and p2
1897 - "/p2" is a merge of the preceding node and p2
1898 - ":tag" defines a local tag for the preceding node
1898 - ":tag" defines a local tag for the preceding node
1899 - "@branch" sets the named branch for subsequent nodes
1899 - "@branch" sets the named branch for subsequent nodes
1900 - "#...\\n" is a comment up to the end of the line
1900 - "#...\\n" is a comment up to the end of the line
1901
1901
1902 Whitespace between the above elements is ignored.
1902 Whitespace between the above elements is ignored.
1903
1903
1904 A backref is either
1904 A backref is either
1905
1905
1906 - a number n, which references the node curr-n, where curr is the current
1906 - a number n, which references the node curr-n, where curr is the current
1907 node, or
1907 node, or
1908 - the name of a local tag you placed earlier using ":tag", or
1908 - the name of a local tag you placed earlier using ":tag", or
1909 - empty to denote the default parent.
1909 - empty to denote the default parent.
1910
1910
1911 All string valued-elements are either strictly alphanumeric, or must
1911 All string valued-elements are either strictly alphanumeric, or must
1912 be enclosed in double quotes ("..."), with "\\" as escape character.
1912 be enclosed in double quotes ("..."), with "\\" as escape character.
1913 """
1913 """
1914
1914
1915 if text is None:
1915 if text is None:
1916 ui.status(_("reading DAG from stdin\n"))
1916 ui.status(_("reading DAG from stdin\n"))
1917 text = ui.fin.read()
1917 text = ui.fin.read()
1918
1918
1919 cl = repo.changelog
1919 cl = repo.changelog
1920 if len(cl) > 0:
1920 if len(cl) > 0:
1921 raise error.Abort(_('repository is not empty'))
1921 raise error.Abort(_('repository is not empty'))
1922
1922
1923 # determine number of revs in DAG
1923 # determine number of revs in DAG
1924 total = 0
1924 total = 0
1925 for type, data in dagparser.parsedag(text):
1925 for type, data in dagparser.parsedag(text):
1926 if type == 'n':
1926 if type == 'n':
1927 total += 1
1927 total += 1
1928
1928
1929 if mergeable_file:
1929 if mergeable_file:
1930 linesperrev = 2
1930 linesperrev = 2
1931 # make a file with k lines per rev
1931 # make a file with k lines per rev
1932 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1932 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1933 initialmergedlines.append("")
1933 initialmergedlines.append("")
1934
1934
1935 tags = []
1935 tags = []
1936
1936
1937 lock = tr = None
1937 lock = tr = None
1938 try:
1938 try:
1939 lock = repo.lock()
1939 lock = repo.lock()
1940 tr = repo.transaction("builddag")
1940 tr = repo.transaction("builddag")
1941
1941
1942 at = -1
1942 at = -1
1943 atbranch = 'default'
1943 atbranch = 'default'
1944 nodeids = []
1944 nodeids = []
1945 id = 0
1945 id = 0
1946 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1946 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1947 for type, data in dagparser.parsedag(text):
1947 for type, data in dagparser.parsedag(text):
1948 if type == 'n':
1948 if type == 'n':
1949 ui.note(('node %s\n' % str(data)))
1949 ui.note(('node %s\n' % str(data)))
1950 id, ps = data
1950 id, ps = data
1951
1951
1952 files = []
1952 files = []
1953 fctxs = {}
1953 fctxs = {}
1954
1954
1955 p2 = None
1955 p2 = None
1956 if mergeable_file:
1956 if mergeable_file:
1957 fn = "mf"
1957 fn = "mf"
1958 p1 = repo[ps[0]]
1958 p1 = repo[ps[0]]
1959 if len(ps) > 1:
1959 if len(ps) > 1:
1960 p2 = repo[ps[1]]
1960 p2 = repo[ps[1]]
1961 pa = p1.ancestor(p2)
1961 pa = p1.ancestor(p2)
1962 base, local, other = [x[fn].data() for x in (pa, p1,
1962 base, local, other = [x[fn].data() for x in (pa, p1,
1963 p2)]
1963 p2)]
1964 m3 = simplemerge.Merge3Text(base, local, other)
1964 m3 = simplemerge.Merge3Text(base, local, other)
1965 ml = [l.strip() for l in m3.merge_lines()]
1965 ml = [l.strip() for l in m3.merge_lines()]
1966 ml.append("")
1966 ml.append("")
1967 elif at > 0:
1967 elif at > 0:
1968 ml = p1[fn].data().split("\n")
1968 ml = p1[fn].data().split("\n")
1969 else:
1969 else:
1970 ml = initialmergedlines
1970 ml = initialmergedlines
1971 ml[id * linesperrev] += " r%i" % id
1971 ml[id * linesperrev] += " r%i" % id
1972 mergedtext = "\n".join(ml)
1972 mergedtext = "\n".join(ml)
1973 files.append(fn)
1973 files.append(fn)
1974 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1974 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1975
1975
1976 if overwritten_file:
1976 if overwritten_file:
1977 fn = "of"
1977 fn = "of"
1978 files.append(fn)
1978 files.append(fn)
1979 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1979 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1980
1980
1981 if new_file:
1981 if new_file:
1982 fn = "nf%i" % id
1982 fn = "nf%i" % id
1983 files.append(fn)
1983 files.append(fn)
1984 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1984 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1985 if len(ps) > 1:
1985 if len(ps) > 1:
1986 if not p2:
1986 if not p2:
1987 p2 = repo[ps[1]]
1987 p2 = repo[ps[1]]
1988 for fn in p2:
1988 for fn in p2:
1989 if fn.startswith("nf"):
1989 if fn.startswith("nf"):
1990 files.append(fn)
1990 files.append(fn)
1991 fctxs[fn] = p2[fn]
1991 fctxs[fn] = p2[fn]
1992
1992
1993 def fctxfn(repo, cx, path):
1993 def fctxfn(repo, cx, path):
1994 return fctxs.get(path)
1994 return fctxs.get(path)
1995
1995
1996 if len(ps) == 0 or ps[0] < 0:
1996 if len(ps) == 0 or ps[0] < 0:
1997 pars = [None, None]
1997 pars = [None, None]
1998 elif len(ps) == 1:
1998 elif len(ps) == 1:
1999 pars = [nodeids[ps[0]], None]
1999 pars = [nodeids[ps[0]], None]
2000 else:
2000 else:
2001 pars = [nodeids[p] for p in ps]
2001 pars = [nodeids[p] for p in ps]
2002 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
2002 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
2003 date=(id, 0),
2003 date=(id, 0),
2004 user="debugbuilddag",
2004 user="debugbuilddag",
2005 extra={'branch': atbranch})
2005 extra={'branch': atbranch})
2006 nodeid = repo.commitctx(cx)
2006 nodeid = repo.commitctx(cx)
2007 nodeids.append(nodeid)
2007 nodeids.append(nodeid)
2008 at = id
2008 at = id
2009 elif type == 'l':
2009 elif type == 'l':
2010 id, name = data
2010 id, name = data
2011 ui.note(('tag %s\n' % name))
2011 ui.note(('tag %s\n' % name))
2012 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
2012 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
2013 elif type == 'a':
2013 elif type == 'a':
2014 ui.note(('branch %s\n' % data))
2014 ui.note(('branch %s\n' % data))
2015 atbranch = data
2015 atbranch = data
2016 ui.progress(_('building'), id, unit=_('revisions'), total=total)
2016 ui.progress(_('building'), id, unit=_('revisions'), total=total)
2017 tr.close()
2017 tr.close()
2018
2018
2019 if tags:
2019 if tags:
2020 repo.vfs.write("localtags", "".join(tags))
2020 repo.vfs.write("localtags", "".join(tags))
2021 finally:
2021 finally:
2022 ui.progress(_('building'), None)
2022 ui.progress(_('building'), None)
2023 release(tr, lock)
2023 release(tr, lock)
2024
2024
2025 @command('debugbundle',
2025 @command('debugbundle',
2026 [('a', 'all', None, _('show all details')),
2026 [('a', 'all', None, _('show all details')),
2027 ('', 'spec', None, _('print the bundlespec of the bundle'))],
2027 ('', 'spec', None, _('print the bundlespec of the bundle'))],
2028 _('FILE'),
2028 _('FILE'),
2029 norepo=True)
2029 norepo=True)
2030 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
2030 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
2031 """lists the contents of a bundle"""
2031 """lists the contents of a bundle"""
2032 with hg.openpath(ui, bundlepath) as f:
2032 with hg.openpath(ui, bundlepath) as f:
2033 if spec:
2033 if spec:
2034 spec = exchange.getbundlespec(ui, f)
2034 spec = exchange.getbundlespec(ui, f)
2035 ui.write('%s\n' % spec)
2035 ui.write('%s\n' % spec)
2036 return
2036 return
2037
2037
2038 gen = exchange.readbundle(ui, f, bundlepath)
2038 gen = exchange.readbundle(ui, f, bundlepath)
2039 if isinstance(gen, bundle2.unbundle20):
2039 if isinstance(gen, bundle2.unbundle20):
2040 return _debugbundle2(ui, gen, all=all, **opts)
2040 return _debugbundle2(ui, gen, all=all, **opts)
2041 if all:
2041 if all:
2042 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
2042 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
2043
2043
2044 def showchunks(named):
2044 def showchunks(named):
2045 ui.write("\n%s\n" % named)
2045 ui.write("\n%s\n" % named)
2046 chain = None
2046 chain = None
2047 while True:
2047 while True:
2048 chunkdata = gen.deltachunk(chain)
2048 chunkdata = gen.deltachunk(chain)
2049 if not chunkdata:
2049 if not chunkdata:
2050 break
2050 break
2051 node = chunkdata['node']
2051 node = chunkdata['node']
2052 p1 = chunkdata['p1']
2052 p1 = chunkdata['p1']
2053 p2 = chunkdata['p2']
2053 p2 = chunkdata['p2']
2054 cs = chunkdata['cs']
2054 cs = chunkdata['cs']
2055 deltabase = chunkdata['deltabase']
2055 deltabase = chunkdata['deltabase']
2056 delta = chunkdata['delta']
2056 delta = chunkdata['delta']
2057 ui.write("%s %s %s %s %s %s\n" %
2057 ui.write("%s %s %s %s %s %s\n" %
2058 (hex(node), hex(p1), hex(p2),
2058 (hex(node), hex(p1), hex(p2),
2059 hex(cs), hex(deltabase), len(delta)))
2059 hex(cs), hex(deltabase), len(delta)))
2060 chain = node
2060 chain = node
2061
2061
2062 chunkdata = gen.changelogheader()
2062 chunkdata = gen.changelogheader()
2063 showchunks("changelog")
2063 showchunks("changelog")
2064 chunkdata = gen.manifestheader()
2064 chunkdata = gen.manifestheader()
2065 showchunks("manifest")
2065 showchunks("manifest")
2066 while True:
2066 while True:
2067 chunkdata = gen.filelogheader()
2067 chunkdata = gen.filelogheader()
2068 if not chunkdata:
2068 if not chunkdata:
2069 break
2069 break
2070 fname = chunkdata['filename']
2070 fname = chunkdata['filename']
2071 showchunks(fname)
2071 showchunks(fname)
2072 else:
2072 else:
2073 if isinstance(gen, bundle2.unbundle20):
2073 if isinstance(gen, bundle2.unbundle20):
2074 raise error.Abort(_('use debugbundle2 for this file'))
2074 raise error.Abort(_('use debugbundle2 for this file'))
2075 chunkdata = gen.changelogheader()
2075 chunkdata = gen.changelogheader()
2076 chain = None
2076 chain = None
2077 while True:
2077 while True:
2078 chunkdata = gen.deltachunk(chain)
2078 chunkdata = gen.deltachunk(chain)
2079 if not chunkdata:
2079 if not chunkdata:
2080 break
2080 break
2081 node = chunkdata['node']
2081 node = chunkdata['node']
2082 ui.write("%s\n" % hex(node))
2082 ui.write("%s\n" % hex(node))
2083 chain = node
2083 chain = node
2084
2084
2085 def _debugbundle2(ui, gen, **opts):
2085 def _debugbundle2(ui, gen, **opts):
2086 """lists the contents of a bundle2"""
2086 """lists the contents of a bundle2"""
2087 if not isinstance(gen, bundle2.unbundle20):
2087 if not isinstance(gen, bundle2.unbundle20):
2088 raise error.Abort(_('not a bundle2 file'))
2088 raise error.Abort(_('not a bundle2 file'))
2089 ui.write(('Stream params: %s\n' % repr(gen.params)))
2089 ui.write(('Stream params: %s\n' % repr(gen.params)))
2090 for part in gen.iterparts():
2090 for part in gen.iterparts():
2091 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
2091 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
2092 if part.type == 'changegroup':
2092 if part.type == 'changegroup':
2093 version = part.params.get('version', '01')
2093 version = part.params.get('version', '01')
2094 cg = changegroup.getunbundler(version, part, 'UN')
2094 cg = changegroup.getunbundler(version, part, 'UN')
2095 chunkdata = cg.changelogheader()
2095 chunkdata = cg.changelogheader()
2096 chain = None
2096 chain = None
2097 while True:
2097 while True:
2098 chunkdata = cg.deltachunk(chain)
2098 chunkdata = cg.deltachunk(chain)
2099 if not chunkdata:
2099 if not chunkdata:
2100 break
2100 break
2101 node = chunkdata['node']
2101 node = chunkdata['node']
2102 ui.write(" %s\n" % hex(node))
2102 ui.write(" %s\n" % hex(node))
2103 chain = node
2103 chain = node
2104
2104
2105 @command('debugcreatestreamclonebundle', [], 'FILE')
2105 @command('debugcreatestreamclonebundle', [], 'FILE')
2106 def debugcreatestreamclonebundle(ui, repo, fname):
2106 def debugcreatestreamclonebundle(ui, repo, fname):
2107 """create a stream clone bundle file
2107 """create a stream clone bundle file
2108
2108
2109 Stream bundles are special bundles that are essentially archives of
2109 Stream bundles are special bundles that are essentially archives of
2110 revlog files. They are commonly used for cloning very quickly.
2110 revlog files. They are commonly used for cloning very quickly.
2111 """
2111 """
2112 requirements, gen = streamclone.generatebundlev1(repo)
2112 requirements, gen = streamclone.generatebundlev1(repo)
2113 changegroup.writechunks(ui, gen, fname)
2113 changegroup.writechunks(ui, gen, fname)
2114
2114
2115 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
2115 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
2116
2116
2117 @command('debugapplystreamclonebundle', [], 'FILE')
2117 @command('debugapplystreamclonebundle', [], 'FILE')
2118 def debugapplystreamclonebundle(ui, repo, fname):
2118 def debugapplystreamclonebundle(ui, repo, fname):
2119 """apply a stream clone bundle file"""
2119 """apply a stream clone bundle file"""
2120 f = hg.openpath(ui, fname)
2120 f = hg.openpath(ui, fname)
2121 gen = exchange.readbundle(ui, f, fname)
2121 gen = exchange.readbundle(ui, f, fname)
2122 gen.apply(repo)
2122 gen.apply(repo)
2123
2123
2124 @command('debugcheckstate', [], '')
2124 @command('debugcheckstate', [], '')
2125 def debugcheckstate(ui, repo):
2125 def debugcheckstate(ui, repo):
2126 """validate the correctness of the current dirstate"""
2126 """validate the correctness of the current dirstate"""
2127 parent1, parent2 = repo.dirstate.parents()
2127 parent1, parent2 = repo.dirstate.parents()
2128 m1 = repo[parent1].manifest()
2128 m1 = repo[parent1].manifest()
2129 m2 = repo[parent2].manifest()
2129 m2 = repo[parent2].manifest()
2130 errors = 0
2130 errors = 0
2131 for f in repo.dirstate:
2131 for f in repo.dirstate:
2132 state = repo.dirstate[f]
2132 state = repo.dirstate[f]
2133 if state in "nr" and f not in m1:
2133 if state in "nr" and f not in m1:
2134 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
2134 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
2135 errors += 1
2135 errors += 1
2136 if state in "a" and f in m1:
2136 if state in "a" and f in m1:
2137 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
2137 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
2138 errors += 1
2138 errors += 1
2139 if state in "m" and f not in m1 and f not in m2:
2139 if state in "m" and f not in m1 and f not in m2:
2140 ui.warn(_("%s in state %s, but not in either manifest\n") %
2140 ui.warn(_("%s in state %s, but not in either manifest\n") %
2141 (f, state))
2141 (f, state))
2142 errors += 1
2142 errors += 1
2143 for f in m1:
2143 for f in m1:
2144 state = repo.dirstate[f]
2144 state = repo.dirstate[f]
2145 if state not in "nrm":
2145 if state not in "nrm":
2146 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
2146 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
2147 errors += 1
2147 errors += 1
2148 if errors:
2148 if errors:
2149 error = _(".hg/dirstate inconsistent with current parent's manifest")
2149 error = _(".hg/dirstate inconsistent with current parent's manifest")
2150 raise error.Abort(error)
2150 raise error.Abort(error)
2151
2151
2152 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
2152 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
2153 def debugcommands(ui, cmd='', *args):
2153 def debugcommands(ui, cmd='', *args):
2154 """list all available commands and options"""
2154 """list all available commands and options"""
2155 for cmd, vals in sorted(table.iteritems()):
2155 for cmd, vals in sorted(table.iteritems()):
2156 cmd = cmd.split('|')[0].strip('^')
2156 cmd = cmd.split('|')[0].strip('^')
2157 opts = ', '.join([i[1] for i in vals[1]])
2157 opts = ', '.join([i[1] for i in vals[1]])
2158 ui.write('%s: %s\n' % (cmd, opts))
2158 ui.write('%s: %s\n' % (cmd, opts))
2159
2159
2160 @command('debugcomplete',
2160 @command('debugcomplete',
2161 [('o', 'options', None, _('show the command options'))],
2161 [('o', 'options', None, _('show the command options'))],
2162 _('[-o] CMD'),
2162 _('[-o] CMD'),
2163 norepo=True)
2163 norepo=True)
2164 def debugcomplete(ui, cmd='', **opts):
2164 def debugcomplete(ui, cmd='', **opts):
2165 """returns the completion list associated with the given command"""
2165 """returns the completion list associated with the given command"""
2166
2166
2167 if opts.get('options'):
2167 if opts.get('options'):
2168 options = []
2168 options = []
2169 otables = [globalopts]
2169 otables = [globalopts]
2170 if cmd:
2170 if cmd:
2171 aliases, entry = cmdutil.findcmd(cmd, table, False)
2171 aliases, entry = cmdutil.findcmd(cmd, table, False)
2172 otables.append(entry[1])
2172 otables.append(entry[1])
2173 for t in otables:
2173 for t in otables:
2174 for o in t:
2174 for o in t:
2175 if "(DEPRECATED)" in o[3]:
2175 if "(DEPRECATED)" in o[3]:
2176 continue
2176 continue
2177 if o[0]:
2177 if o[0]:
2178 options.append('-%s' % o[0])
2178 options.append('-%s' % o[0])
2179 options.append('--%s' % o[1])
2179 options.append('--%s' % o[1])
2180 ui.write("%s\n" % "\n".join(options))
2180 ui.write("%s\n" % "\n".join(options))
2181 return
2181 return
2182
2182
2183 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2183 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2184 if ui.verbose:
2184 if ui.verbose:
2185 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
2185 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
2186 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
2186 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
2187
2187
2188 @command('debugdag',
2188 @command('debugdag',
2189 [('t', 'tags', None, _('use tags as labels')),
2189 [('t', 'tags', None, _('use tags as labels')),
2190 ('b', 'branches', None, _('annotate with branch names')),
2190 ('b', 'branches', None, _('annotate with branch names')),
2191 ('', 'dots', None, _('use dots for runs')),
2191 ('', 'dots', None, _('use dots for runs')),
2192 ('s', 'spaces', None, _('separate elements by spaces'))],
2192 ('s', 'spaces', None, _('separate elements by spaces'))],
2193 _('[OPTION]... [FILE [REV]...]'),
2193 _('[OPTION]... [FILE [REV]...]'),
2194 optionalrepo=True)
2194 optionalrepo=True)
2195 def debugdag(ui, repo, file_=None, *revs, **opts):
2195 def debugdag(ui, repo, file_=None, *revs, **opts):
2196 """format the changelog or an index DAG as a concise textual description
2196 """format the changelog or an index DAG as a concise textual description
2197
2197
2198 If you pass a revlog index, the revlog's DAG is emitted. If you list
2198 If you pass a revlog index, the revlog's DAG is emitted. If you list
2199 revision numbers, they get labeled in the output as rN.
2199 revision numbers, they get labeled in the output as rN.
2200
2200
2201 Otherwise, the changelog DAG of the current repo is emitted.
2201 Otherwise, the changelog DAG of the current repo is emitted.
2202 """
2202 """
2203 spaces = opts.get('spaces')
2203 spaces = opts.get('spaces')
2204 dots = opts.get('dots')
2204 dots = opts.get('dots')
2205 if file_:
2205 if file_:
2206 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2206 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2207 revs = set((int(r) for r in revs))
2207 revs = set((int(r) for r in revs))
2208 def events():
2208 def events():
2209 for r in rlog:
2209 for r in rlog:
2210 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2210 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2211 if p != -1))
2211 if p != -1))
2212 if r in revs:
2212 if r in revs:
2213 yield 'l', (r, "r%i" % r)
2213 yield 'l', (r, "r%i" % r)
2214 elif repo:
2214 elif repo:
2215 cl = repo.changelog
2215 cl = repo.changelog
2216 tags = opts.get('tags')
2216 tags = opts.get('tags')
2217 branches = opts.get('branches')
2217 branches = opts.get('branches')
2218 if tags:
2218 if tags:
2219 labels = {}
2219 labels = {}
2220 for l, n in repo.tags().items():
2220 for l, n in repo.tags().items():
2221 labels.setdefault(cl.rev(n), []).append(l)
2221 labels.setdefault(cl.rev(n), []).append(l)
2222 def events():
2222 def events():
2223 b = "default"
2223 b = "default"
2224 for r in cl:
2224 for r in cl:
2225 if branches:
2225 if branches:
2226 newb = cl.read(cl.node(r))[5]['branch']
2226 newb = cl.read(cl.node(r))[5]['branch']
2227 if newb != b:
2227 if newb != b:
2228 yield 'a', newb
2228 yield 'a', newb
2229 b = newb
2229 b = newb
2230 yield 'n', (r, list(p for p in cl.parentrevs(r)
2230 yield 'n', (r, list(p for p in cl.parentrevs(r)
2231 if p != -1))
2231 if p != -1))
2232 if tags:
2232 if tags:
2233 ls = labels.get(r)
2233 ls = labels.get(r)
2234 if ls:
2234 if ls:
2235 for l in ls:
2235 for l in ls:
2236 yield 'l', (r, l)
2236 yield 'l', (r, l)
2237 else:
2237 else:
2238 raise error.Abort(_('need repo for changelog dag'))
2238 raise error.Abort(_('need repo for changelog dag'))
2239
2239
2240 for line in dagparser.dagtextlines(events(),
2240 for line in dagparser.dagtextlines(events(),
2241 addspaces=spaces,
2241 addspaces=spaces,
2242 wraplabels=True,
2242 wraplabels=True,
2243 wrapannotations=True,
2243 wrapannotations=True,
2244 wrapnonlinear=dots,
2244 wrapnonlinear=dots,
2245 usedots=dots,
2245 usedots=dots,
2246 maxlinewidth=70):
2246 maxlinewidth=70):
2247 ui.write(line)
2247 ui.write(line)
2248 ui.write("\n")
2248 ui.write("\n")
2249
2249
2250 @command('debugdata', debugrevlogopts, _('-c|-m|FILE REV'))
2250 @command('debugdata', debugrevlogopts, _('-c|-m|FILE REV'))
2251 def debugdata(ui, repo, file_, rev=None, **opts):
2251 def debugdata(ui, repo, file_, rev=None, **opts):
2252 """dump the contents of a data file revision"""
2252 """dump the contents of a data file revision"""
2253 if opts.get('changelog') or opts.get('manifest'):
2253 if opts.get('changelog') or opts.get('manifest'):
2254 file_, rev = None, file_
2254 file_, rev = None, file_
2255 elif rev is None:
2255 elif rev is None:
2256 raise error.CommandError('debugdata', _('invalid arguments'))
2256 raise error.CommandError('debugdata', _('invalid arguments'))
2257 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2257 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2258 try:
2258 try:
2259 ui.write(r.revision(r.lookup(rev)))
2259 ui.write(r.revision(r.lookup(rev)))
2260 except KeyError:
2260 except KeyError:
2261 raise error.Abort(_('invalid revision identifier %s') % rev)
2261 raise error.Abort(_('invalid revision identifier %s') % rev)
2262
2262
2263 @command('debugdate',
2263 @command('debugdate',
2264 [('e', 'extended', None, _('try extended date formats'))],
2264 [('e', 'extended', None, _('try extended date formats'))],
2265 _('[-e] DATE [RANGE]'),
2265 _('[-e] DATE [RANGE]'),
2266 norepo=True, optionalrepo=True)
2266 norepo=True, optionalrepo=True)
2267 def debugdate(ui, date, range=None, **opts):
2267 def debugdate(ui, date, range=None, **opts):
2268 """parse and display a date"""
2268 """parse and display a date"""
2269 if opts["extended"]:
2269 if opts["extended"]:
2270 d = util.parsedate(date, util.extendeddateformats)
2270 d = util.parsedate(date, util.extendeddateformats)
2271 else:
2271 else:
2272 d = util.parsedate(date)
2272 d = util.parsedate(date)
2273 ui.write(("internal: %s %s\n") % d)
2273 ui.write(("internal: %s %s\n") % d)
2274 ui.write(("standard: %s\n") % util.datestr(d))
2274 ui.write(("standard: %s\n") % util.datestr(d))
2275 if range:
2275 if range:
2276 m = util.matchdate(range)
2276 m = util.matchdate(range)
2277 ui.write(("match: %s\n") % m(d[0]))
2277 ui.write(("match: %s\n") % m(d[0]))
2278
2278
2279 @command('debugdiscovery',
2279 @command('debugdiscovery',
2280 [('', 'old', None, _('use old-style discovery')),
2280 [('', 'old', None, _('use old-style discovery')),
2281 ('', 'nonheads', None,
2281 ('', 'nonheads', None,
2282 _('use old-style discovery with non-heads included')),
2282 _('use old-style discovery with non-heads included')),
2283 ] + remoteopts,
2283 ] + remoteopts,
2284 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2284 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2285 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2285 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2286 """runs the changeset discovery protocol in isolation"""
2286 """runs the changeset discovery protocol in isolation"""
2287 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2287 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2288 opts.get('branch'))
2288 opts.get('branch'))
2289 remote = hg.peer(repo, opts, remoteurl)
2289 remote = hg.peer(repo, opts, remoteurl)
2290 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2290 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2291
2291
2292 # make sure tests are repeatable
2292 # make sure tests are repeatable
2293 random.seed(12323)
2293 random.seed(12323)
2294
2294
2295 def doit(localheads, remoteheads, remote=remote):
2295 def doit(localheads, remoteheads, remote=remote):
2296 if opts.get('old'):
2296 if opts.get('old'):
2297 if localheads:
2297 if localheads:
2298 raise error.Abort('cannot use localheads with old style '
2298 raise error.Abort('cannot use localheads with old style '
2299 'discovery')
2299 'discovery')
2300 if not util.safehasattr(remote, 'branches'):
2300 if not util.safehasattr(remote, 'branches'):
2301 # enable in-client legacy support
2301 # enable in-client legacy support
2302 remote = localrepo.locallegacypeer(remote.local())
2302 remote = localrepo.locallegacypeer(remote.local())
2303 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2303 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2304 force=True)
2304 force=True)
2305 common = set(common)
2305 common = set(common)
2306 if not opts.get('nonheads'):
2306 if not opts.get('nonheads'):
2307 ui.write(("unpruned common: %s\n") %
2307 ui.write(("unpruned common: %s\n") %
2308 " ".join(sorted(short(n) for n in common)))
2308 " ".join(sorted(short(n) for n in common)))
2309 dag = dagutil.revlogdag(repo.changelog)
2309 dag = dagutil.revlogdag(repo.changelog)
2310 all = dag.ancestorset(dag.internalizeall(common))
2310 all = dag.ancestorset(dag.internalizeall(common))
2311 common = dag.externalizeall(dag.headsetofconnecteds(all))
2311 common = dag.externalizeall(dag.headsetofconnecteds(all))
2312 else:
2312 else:
2313 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2313 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2314 common = set(common)
2314 common = set(common)
2315 rheads = set(hds)
2315 rheads = set(hds)
2316 lheads = set(repo.heads())
2316 lheads = set(repo.heads())
2317 ui.write(("common heads: %s\n") %
2317 ui.write(("common heads: %s\n") %
2318 " ".join(sorted(short(n) for n in common)))
2318 " ".join(sorted(short(n) for n in common)))
2319 if lheads <= common:
2319 if lheads <= common:
2320 ui.write(("local is subset\n"))
2320 ui.write(("local is subset\n"))
2321 elif rheads <= common:
2321 elif rheads <= common:
2322 ui.write(("remote is subset\n"))
2322 ui.write(("remote is subset\n"))
2323
2323
2324 serverlogs = opts.get('serverlog')
2324 serverlogs = opts.get('serverlog')
2325 if serverlogs:
2325 if serverlogs:
2326 for filename in serverlogs:
2326 for filename in serverlogs:
2327 with open(filename, 'r') as logfile:
2327 with open(filename, 'r') as logfile:
2328 line = logfile.readline()
2328 line = logfile.readline()
2329 while line:
2329 while line:
2330 parts = line.strip().split(';')
2330 parts = line.strip().split(';')
2331 op = parts[1]
2331 op = parts[1]
2332 if op == 'cg':
2332 if op == 'cg':
2333 pass
2333 pass
2334 elif op == 'cgss':
2334 elif op == 'cgss':
2335 doit(parts[2].split(' '), parts[3].split(' '))
2335 doit(parts[2].split(' '), parts[3].split(' '))
2336 elif op == 'unb':
2336 elif op == 'unb':
2337 doit(parts[3].split(' '), parts[2].split(' '))
2337 doit(parts[3].split(' '), parts[2].split(' '))
2338 line = logfile.readline()
2338 line = logfile.readline()
2339 else:
2339 else:
2340 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2340 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2341 opts.get('remote_head'))
2341 opts.get('remote_head'))
2342 localrevs = opts.get('local_head')
2342 localrevs = opts.get('local_head')
2343 doit(localrevs, remoterevs)
2343 doit(localrevs, remoterevs)
2344
2344
2345 @command('debugextensions', formatteropts, [], norepo=True)
2345 @command('debugextensions', formatteropts, [], norepo=True)
2346 def debugextensions(ui, **opts):
2346 def debugextensions(ui, **opts):
2347 '''show information about active extensions'''
2347 '''show information about active extensions'''
2348 exts = extensions.extensions(ui)
2348 exts = extensions.extensions(ui)
2349 fm = ui.formatter('debugextensions', opts)
2349 fm = ui.formatter('debugextensions', opts)
2350 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2350 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2351 extsource = extmod.__file__
2351 extsource = extmod.__file__
2352 exttestedwith = getattr(extmod, 'testedwith', None)
2352 exttestedwith = getattr(extmod, 'testedwith', None)
2353 if exttestedwith is not None:
2353 if exttestedwith is not None:
2354 exttestedwith = exttestedwith.split()
2354 exttestedwith = exttestedwith.split()
2355 extbuglink = getattr(extmod, 'buglink', None)
2355 extbuglink = getattr(extmod, 'buglink', None)
2356
2356
2357 fm.startitem()
2357 fm.startitem()
2358
2358
2359 if ui.quiet or ui.verbose:
2359 if ui.quiet or ui.verbose:
2360 fm.write('name', '%s\n', extname)
2360 fm.write('name', '%s\n', extname)
2361 else:
2361 else:
2362 fm.write('name', '%s', extname)
2362 fm.write('name', '%s', extname)
2363 if not exttestedwith:
2363 if not exttestedwith:
2364 fm.plain(_(' (untested!)\n'))
2364 fm.plain(_(' (untested!)\n'))
2365 else:
2365 else:
2366 if exttestedwith == ['internal'] or \
2366 if exttestedwith == ['internal'] or \
2367 util.version() in exttestedwith:
2367 util.version() in exttestedwith:
2368 fm.plain('\n')
2368 fm.plain('\n')
2369 else:
2369 else:
2370 lasttestedversion = exttestedwith[-1]
2370 lasttestedversion = exttestedwith[-1]
2371 fm.plain(' (%s!)\n' % lasttestedversion)
2371 fm.plain(' (%s!)\n' % lasttestedversion)
2372
2372
2373 fm.condwrite(ui.verbose and extsource, 'source',
2373 fm.condwrite(ui.verbose and extsource, 'source',
2374 _(' location: %s\n'), extsource or "")
2374 _(' location: %s\n'), extsource or "")
2375
2375
2376 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2376 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2377 _(' tested with: %s\n'), ' '.join(exttestedwith or []))
2377 _(' tested with: %s\n'), ' '.join(exttestedwith or []))
2378
2378
2379 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2379 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2380 _(' bug reporting: %s\n'), extbuglink or "")
2380 _(' bug reporting: %s\n'), extbuglink or "")
2381
2381
2382 fm.end()
2382 fm.end()
2383
2383
2384 @command('debugfileset',
2384 @command('debugfileset',
2385 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2385 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2386 _('[-r REV] FILESPEC'))
2386 _('[-r REV] FILESPEC'))
2387 def debugfileset(ui, repo, expr, **opts):
2387 def debugfileset(ui, repo, expr, **opts):
2388 '''parse and apply a fileset specification'''
2388 '''parse and apply a fileset specification'''
2389 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2389 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2390 if ui.verbose:
2390 if ui.verbose:
2391 tree = fileset.parse(expr)
2391 tree = fileset.parse(expr)
2392 ui.note(fileset.prettyformat(tree), "\n")
2392 ui.note(fileset.prettyformat(tree), "\n")
2393
2393
2394 for f in ctx.getfileset(expr):
2394 for f in ctx.getfileset(expr):
2395 ui.write("%s\n" % f)
2395 ui.write("%s\n" % f)
2396
2396
2397 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2397 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2398 def debugfsinfo(ui, path="."):
2398 def debugfsinfo(ui, path="."):
2399 """show information detected about current filesystem"""
2399 """show information detected about current filesystem"""
2400 util.writefile('.debugfsinfo', '')
2400 util.writefile('.debugfsinfo', '')
2401 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2401 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2402 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2402 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2403 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2403 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2404 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2404 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2405 and 'yes' or 'no'))
2405 and 'yes' or 'no'))
2406 os.unlink('.debugfsinfo')
2406 os.unlink('.debugfsinfo')
2407
2407
2408 @command('debuggetbundle',
2408 @command('debuggetbundle',
2409 [('H', 'head', [], _('id of head node'), _('ID')),
2409 [('H', 'head', [], _('id of head node'), _('ID')),
2410 ('C', 'common', [], _('id of common node'), _('ID')),
2410 ('C', 'common', [], _('id of common node'), _('ID')),
2411 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2411 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2412 _('REPO FILE [-H|-C ID]...'),
2412 _('REPO FILE [-H|-C ID]...'),
2413 norepo=True)
2413 norepo=True)
2414 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2414 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2415 """retrieves a bundle from a repo
2415 """retrieves a bundle from a repo
2416
2416
2417 Every ID must be a full-length hex node id string. Saves the bundle to the
2417 Every ID must be a full-length hex node id string. Saves the bundle to the
2418 given file.
2418 given file.
2419 """
2419 """
2420 repo = hg.peer(ui, opts, repopath)
2420 repo = hg.peer(ui, opts, repopath)
2421 if not repo.capable('getbundle'):
2421 if not repo.capable('getbundle'):
2422 raise error.Abort("getbundle() not supported by target repository")
2422 raise error.Abort("getbundle() not supported by target repository")
2423 args = {}
2423 args = {}
2424 if common:
2424 if common:
2425 args['common'] = [bin(s) for s in common]
2425 args['common'] = [bin(s) for s in common]
2426 if head:
2426 if head:
2427 args['heads'] = [bin(s) for s in head]
2427 args['heads'] = [bin(s) for s in head]
2428 # TODO: get desired bundlecaps from command line.
2428 # TODO: get desired bundlecaps from command line.
2429 args['bundlecaps'] = None
2429 args['bundlecaps'] = None
2430 bundle = repo.getbundle('debug', **args)
2430 bundle = repo.getbundle('debug', **args)
2431
2431
2432 bundletype = opts.get('type', 'bzip2').lower()
2432 bundletype = opts.get('type', 'bzip2').lower()
2433 btypes = {'none': 'HG10UN',
2433 btypes = {'none': 'HG10UN',
2434 'bzip2': 'HG10BZ',
2434 'bzip2': 'HG10BZ',
2435 'gzip': 'HG10GZ',
2435 'gzip': 'HG10GZ',
2436 'bundle2': 'HG20'}
2436 'bundle2': 'HG20'}
2437 bundletype = btypes.get(bundletype)
2437 bundletype = btypes.get(bundletype)
2438 if bundletype not in changegroup.bundletypes:
2438 if bundletype not in changegroup.bundletypes:
2439 raise error.Abort(_('unknown bundle type specified with --type'))
2439 raise error.Abort(_('unknown bundle type specified with --type'))
2440 changegroup.writebundle(ui, bundle, bundlepath, bundletype)
2440 changegroup.writebundle(ui, bundle, bundlepath, bundletype)
2441
2441
2442 @command('debugignore', [], '[FILE]')
2442 @command('debugignore', [], '[FILE]')
2443 def debugignore(ui, repo, *files, **opts):
2443 def debugignore(ui, repo, *files, **opts):
2444 """display the combined ignore pattern and information about ignored files
2444 """display the combined ignore pattern and information about ignored files
2445
2445
2446 With no argument display the combined ignore pattern.
2446 With no argument display the combined ignore pattern.
2447
2447
2448 Given space separated file names, shows if the given file is ignored and
2448 Given space separated file names, shows if the given file is ignored and
2449 if so, show the ignore rule (file and line number) that matched it.
2449 if so, show the ignore rule (file and line number) that matched it.
2450 """
2450 """
2451 ignore = repo.dirstate._ignore
2451 ignore = repo.dirstate._ignore
2452 if not files:
2452 if not files:
2453 # Show all the patterns
2453 # Show all the patterns
2454 includepat = getattr(ignore, 'includepat', None)
2454 includepat = getattr(ignore, 'includepat', None)
2455 if includepat is not None:
2455 if includepat is not None:
2456 ui.write("%s\n" % includepat)
2456 ui.write("%s\n" % includepat)
2457 else:
2457 else:
2458 raise error.Abort(_("no ignore patterns found"))
2458 raise error.Abort(_("no ignore patterns found"))
2459 else:
2459 else:
2460 for f in files:
2460 for f in files:
2461 ignored = None
2461 ignored = None
2462 ignoredata = None
2462 ignoredata = None
2463 if f != '.':
2463 if f != '.':
2464 if ignore(f):
2464 if ignore(f):
2465 ignored = f
2465 ignored = f
2466 ignoredata = repo.dirstate._ignorefileandline(f)
2466 ignoredata = repo.dirstate._ignorefileandline(f)
2467 else:
2467 else:
2468 for p in util.finddirs(f):
2468 for p in util.finddirs(f):
2469 if ignore(p):
2469 if ignore(p):
2470 ignored = p
2470 ignored = p
2471 ignoredata = repo.dirstate._ignorefileandline(p)
2471 ignoredata = repo.dirstate._ignorefileandline(p)
2472 break
2472 break
2473 if ignored:
2473 if ignored:
2474 if ignored == f:
2474 if ignored == f:
2475 ui.write("%s is ignored\n" % f)
2475 ui.write("%s is ignored\n" % f)
2476 else:
2476 else:
2477 ui.write("%s is ignored because of containing folder %s\n"
2477 ui.write("%s is ignored because of containing folder %s\n"
2478 % (f, ignored))
2478 % (f, ignored))
2479 ignorefile, lineno, line = ignoredata
2479 ignorefile, lineno, line = ignoredata
2480 ui.write("(ignore rule in %s, line %d: '%s')\n"
2480 ui.write("(ignore rule in %s, line %d: '%s')\n"
2481 % (ignorefile, lineno, line))
2481 % (ignorefile, lineno, line))
2482 else:
2482 else:
2483 ui.write("%s is not ignored\n" % f)
2483 ui.write("%s is not ignored\n" % f)
2484
2484
2485 @command('debugindex', debugrevlogopts +
2485 @command('debugindex', debugrevlogopts +
2486 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2486 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2487 _('[-f FORMAT] -c|-m|FILE'),
2487 _('[-f FORMAT] -c|-m|FILE'),
2488 optionalrepo=True)
2488 optionalrepo=True)
2489 def debugindex(ui, repo, file_=None, **opts):
2489 def debugindex(ui, repo, file_=None, **opts):
2490 """dump the contents of an index file"""
2490 """dump the contents of an index file"""
2491 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2491 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2492 format = opts.get('format', 0)
2492 format = opts.get('format', 0)
2493 if format not in (0, 1):
2493 if format not in (0, 1):
2494 raise error.Abort(_("unknown format %d") % format)
2494 raise error.Abort(_("unknown format %d") % format)
2495
2495
2496 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2496 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2497 if generaldelta:
2497 if generaldelta:
2498 basehdr = ' delta'
2498 basehdr = ' delta'
2499 else:
2499 else:
2500 basehdr = ' base'
2500 basehdr = ' base'
2501
2501
2502 if ui.debugflag:
2502 if ui.debugflag:
2503 shortfn = hex
2503 shortfn = hex
2504 else:
2504 else:
2505 shortfn = short
2505 shortfn = short
2506
2506
2507 # There might not be anything in r, so have a sane default
2507 # There might not be anything in r, so have a sane default
2508 idlen = 12
2508 idlen = 12
2509 for i in r:
2509 for i in r:
2510 idlen = len(shortfn(r.node(i)))
2510 idlen = len(shortfn(r.node(i)))
2511 break
2511 break
2512
2512
2513 if format == 0:
2513 if format == 0:
2514 ui.write(" rev offset length " + basehdr + " linkrev"
2514 ui.write(" rev offset length " + basehdr + " linkrev"
2515 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2515 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2516 elif format == 1:
2516 elif format == 1:
2517 ui.write(" rev flag offset length"
2517 ui.write(" rev flag offset length"
2518 " size " + basehdr + " link p1 p2"
2518 " size " + basehdr + " link p1 p2"
2519 " %s\n" % "nodeid".rjust(idlen))
2519 " %s\n" % "nodeid".rjust(idlen))
2520
2520
2521 for i in r:
2521 for i in r:
2522 node = r.node(i)
2522 node = r.node(i)
2523 if generaldelta:
2523 if generaldelta:
2524 base = r.deltaparent(i)
2524 base = r.deltaparent(i)
2525 else:
2525 else:
2526 base = r.chainbase(i)
2526 base = r.chainbase(i)
2527 if format == 0:
2527 if format == 0:
2528 try:
2528 try:
2529 pp = r.parents(node)
2529 pp = r.parents(node)
2530 except Exception:
2530 except Exception:
2531 pp = [nullid, nullid]
2531 pp = [nullid, nullid]
2532 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2532 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2533 i, r.start(i), r.length(i), base, r.linkrev(i),
2533 i, r.start(i), r.length(i), base, r.linkrev(i),
2534 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2534 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2535 elif format == 1:
2535 elif format == 1:
2536 pr = r.parentrevs(i)
2536 pr = r.parentrevs(i)
2537 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2537 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2538 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2538 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2539 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2539 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2540
2540
2541 @command('debugindexdot', debugrevlogopts,
2541 @command('debugindexdot', debugrevlogopts,
2542 _('-c|-m|FILE'), optionalrepo=True)
2542 _('-c|-m|FILE'), optionalrepo=True)
2543 def debugindexdot(ui, repo, file_=None, **opts):
2543 def debugindexdot(ui, repo, file_=None, **opts):
2544 """dump an index DAG as a graphviz dot file"""
2544 """dump an index DAG as a graphviz dot file"""
2545 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
2545 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
2546 ui.write(("digraph G {\n"))
2546 ui.write(("digraph G {\n"))
2547 for i in r:
2547 for i in r:
2548 node = r.node(i)
2548 node = r.node(i)
2549 pp = r.parents(node)
2549 pp = r.parents(node)
2550 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2550 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2551 if pp[1] != nullid:
2551 if pp[1] != nullid:
2552 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2552 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2553 ui.write("}\n")
2553 ui.write("}\n")
2554
2554
2555 @command('debugdeltachain',
2555 @command('debugdeltachain',
2556 debugrevlogopts + formatteropts,
2556 debugrevlogopts + formatteropts,
2557 _('-c|-m|FILE'),
2557 _('-c|-m|FILE'),
2558 optionalrepo=True)
2558 optionalrepo=True)
2559 def debugdeltachain(ui, repo, file_=None, **opts):
2559 def debugdeltachain(ui, repo, file_=None, **opts):
2560 """dump information about delta chains in a revlog
2560 """dump information about delta chains in a revlog
2561
2561
2562 Output can be templatized. Available template keywords are:
2562 Output can be templatized. Available template keywords are:
2563
2563
2564 rev revision number
2564 rev revision number
2565 chainid delta chain identifier (numbered by unique base)
2565 chainid delta chain identifier (numbered by unique base)
2566 chainlen delta chain length to this revision
2566 chainlen delta chain length to this revision
2567 prevrev previous revision in delta chain
2567 prevrev previous revision in delta chain
2568 deltatype role of delta / how it was computed
2568 deltatype role of delta / how it was computed
2569 compsize compressed size of revision
2569 compsize compressed size of revision
2570 uncompsize uncompressed size of revision
2570 uncompsize uncompressed size of revision
2571 chainsize total size of compressed revisions in chain
2571 chainsize total size of compressed revisions in chain
2572 chainratio total chain size divided by uncompressed revision size
2572 chainratio total chain size divided by uncompressed revision size
2573 (new delta chains typically start at ratio 2.00)
2573 (new delta chains typically start at ratio 2.00)
2574 lindist linear distance from base revision in delta chain to end
2574 lindist linear distance from base revision in delta chain to end
2575 of this revision
2575 of this revision
2576 extradist total size of revisions not part of this delta chain from
2576 extradist total size of revisions not part of this delta chain from
2577 base of delta chain to end of this revision; a measurement
2577 base of delta chain to end of this revision; a measurement
2578 of how much extra data we need to read/seek across to read
2578 of how much extra data we need to read/seek across to read
2579 the delta chain for this revision
2579 the delta chain for this revision
2580 extraratio extradist divided by chainsize; another representation of
2580 extraratio extradist divided by chainsize; another representation of
2581 how much unrelated data is needed to load this delta chain
2581 how much unrelated data is needed to load this delta chain
2582 """
2582 """
2583 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
2583 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
2584 index = r.index
2584 index = r.index
2585 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2585 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2586
2586
2587 def revinfo(rev):
2587 def revinfo(rev):
2588 e = index[rev]
2588 e = index[rev]
2589 compsize = e[1]
2589 compsize = e[1]
2590 uncompsize = e[2]
2590 uncompsize = e[2]
2591 chainsize = 0
2591 chainsize = 0
2592
2592
2593 if generaldelta:
2593 if generaldelta:
2594 if e[3] == e[5]:
2594 if e[3] == e[5]:
2595 deltatype = 'p1'
2595 deltatype = 'p1'
2596 elif e[3] == e[6]:
2596 elif e[3] == e[6]:
2597 deltatype = 'p2'
2597 deltatype = 'p2'
2598 elif e[3] == rev - 1:
2598 elif e[3] == rev - 1:
2599 deltatype = 'prev'
2599 deltatype = 'prev'
2600 elif e[3] == rev:
2600 elif e[3] == rev:
2601 deltatype = 'base'
2601 deltatype = 'base'
2602 else:
2602 else:
2603 deltatype = 'other'
2603 deltatype = 'other'
2604 else:
2604 else:
2605 if e[3] == rev:
2605 if e[3] == rev:
2606 deltatype = 'base'
2606 deltatype = 'base'
2607 else:
2607 else:
2608 deltatype = 'prev'
2608 deltatype = 'prev'
2609
2609
2610 chain = r._deltachain(rev)[0]
2610 chain = r._deltachain(rev)[0]
2611 for iterrev in chain:
2611 for iterrev in chain:
2612 e = index[iterrev]
2612 e = index[iterrev]
2613 chainsize += e[1]
2613 chainsize += e[1]
2614
2614
2615 return compsize, uncompsize, deltatype, chain, chainsize
2615 return compsize, uncompsize, deltatype, chain, chainsize
2616
2616
2617 fm = ui.formatter('debugdeltachain', opts)
2617 fm = ui.formatter('debugdeltachain', opts)
2618
2618
2619 fm.plain(' rev chain# chainlen prev delta '
2619 fm.plain(' rev chain# chainlen prev delta '
2620 'size rawsize chainsize ratio lindist extradist '
2620 'size rawsize chainsize ratio lindist extradist '
2621 'extraratio\n')
2621 'extraratio\n')
2622
2622
2623 chainbases = {}
2623 chainbases = {}
2624 for rev in r:
2624 for rev in r:
2625 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
2625 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
2626 chainbase = chain[0]
2626 chainbase = chain[0]
2627 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
2627 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
2628 basestart = r.start(chainbase)
2628 basestart = r.start(chainbase)
2629 revstart = r.start(rev)
2629 revstart = r.start(rev)
2630 lineardist = revstart + comp - basestart
2630 lineardist = revstart + comp - basestart
2631 extradist = lineardist - chainsize
2631 extradist = lineardist - chainsize
2632 try:
2632 try:
2633 prevrev = chain[-2]
2633 prevrev = chain[-2]
2634 except IndexError:
2634 except IndexError:
2635 prevrev = -1
2635 prevrev = -1
2636
2636
2637 chainratio = float(chainsize) / float(uncomp)
2637 chainratio = float(chainsize) / float(uncomp)
2638 extraratio = float(extradist) / float(chainsize)
2638 extraratio = float(extradist) / float(chainsize)
2639
2639
2640 fm.startitem()
2640 fm.startitem()
2641 fm.write('rev chainid chainlen prevrev deltatype compsize '
2641 fm.write('rev chainid chainlen prevrev deltatype compsize '
2642 'uncompsize chainsize chainratio lindist extradist '
2642 'uncompsize chainsize chainratio lindist extradist '
2643 'extraratio',
2643 'extraratio',
2644 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
2644 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
2645 rev, chainid, len(chain), prevrev, deltatype, comp,
2645 rev, chainid, len(chain), prevrev, deltatype, comp,
2646 uncomp, chainsize, chainratio, lineardist, extradist,
2646 uncomp, chainsize, chainratio, lineardist, extradist,
2647 extraratio,
2647 extraratio,
2648 rev=rev, chainid=chainid, chainlen=len(chain),
2648 rev=rev, chainid=chainid, chainlen=len(chain),
2649 prevrev=prevrev, deltatype=deltatype, compsize=comp,
2649 prevrev=prevrev, deltatype=deltatype, compsize=comp,
2650 uncompsize=uncomp, chainsize=chainsize,
2650 uncompsize=uncomp, chainsize=chainsize,
2651 chainratio=chainratio, lindist=lineardist,
2651 chainratio=chainratio, lindist=lineardist,
2652 extradist=extradist, extraratio=extraratio)
2652 extradist=extradist, extraratio=extraratio)
2653
2653
2654 fm.end()
2654 fm.end()
2655
2655
2656 @command('debuginstall', [], '', norepo=True)
2656 @command('debuginstall', [], '', norepo=True)
2657 def debuginstall(ui):
2657 def debuginstall(ui):
2658 '''test Mercurial installation
2658 '''test Mercurial installation
2659
2659
2660 Returns 0 on success.
2660 Returns 0 on success.
2661 '''
2661 '''
2662
2662
2663 def writetemp(contents):
2663 def writetemp(contents):
2664 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2664 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2665 f = os.fdopen(fd, "wb")
2665 f = os.fdopen(fd, "wb")
2666 f.write(contents)
2666 f.write(contents)
2667 f.close()
2667 f.close()
2668 return name
2668 return name
2669
2669
2670 problems = 0
2670 problems = 0
2671
2671
2672 # encoding
2672 # encoding
2673 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2673 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2674 try:
2674 try:
2675 encoding.fromlocal("test")
2675 encoding.fromlocal("test")
2676 except error.Abort as inst:
2676 except error.Abort as inst:
2677 ui.write(" %s\n" % inst)
2677 ui.write(" %s\n" % inst)
2678 ui.write(_(" (check that your locale is properly set)\n"))
2678 ui.write(_(" (check that your locale is properly set)\n"))
2679 problems += 1
2679 problems += 1
2680
2680
2681 # Python
2681 # Python
2682 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2682 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2683 ui.status(_("checking Python version (%s)\n")
2683 ui.status(_("checking Python version (%s)\n")
2684 % ("%s.%s.%s" % sys.version_info[:3]))
2684 % ("%s.%s.%s" % sys.version_info[:3]))
2685 ui.status(_("checking Python lib (%s)...\n")
2685 ui.status(_("checking Python lib (%s)...\n")
2686 % os.path.dirname(os.__file__))
2686 % os.path.dirname(os.__file__))
2687
2687
2688 # compiled modules
2688 # compiled modules
2689 ui.status(_("checking installed modules (%s)...\n")
2689 ui.status(_("checking installed modules (%s)...\n")
2690 % os.path.dirname(__file__))
2690 % os.path.dirname(__file__))
2691 try:
2691 try:
2692 import bdiff, mpatch, base85, osutil
2692 import bdiff, mpatch, base85, osutil
2693 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2693 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2694 except Exception as inst:
2694 except Exception as inst:
2695 ui.write(" %s\n" % inst)
2695 ui.write(" %s\n" % inst)
2696 ui.write(_(" One or more extensions could not be found"))
2696 ui.write(_(" One or more extensions could not be found"))
2697 ui.write(_(" (check that you compiled the extensions)\n"))
2697 ui.write(_(" (check that you compiled the extensions)\n"))
2698 problems += 1
2698 problems += 1
2699
2699
2700 # templates
2700 # templates
2701 import templater
2701 import templater
2702 p = templater.templatepaths()
2702 p = templater.templatepaths()
2703 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2703 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2704 if p:
2704 if p:
2705 m = templater.templatepath("map-cmdline.default")
2705 m = templater.templatepath("map-cmdline.default")
2706 if m:
2706 if m:
2707 # template found, check if it is working
2707 # template found, check if it is working
2708 try:
2708 try:
2709 templater.templater(m)
2709 templater.templater(m)
2710 except Exception as inst:
2710 except Exception as inst:
2711 ui.write(" %s\n" % inst)
2711 ui.write(" %s\n" % inst)
2712 p = None
2712 p = None
2713 else:
2713 else:
2714 ui.write(_(" template 'default' not found\n"))
2714 ui.write(_(" template 'default' not found\n"))
2715 p = None
2715 p = None
2716 else:
2716 else:
2717 ui.write(_(" no template directories found\n"))
2717 ui.write(_(" no template directories found\n"))
2718 if not p:
2718 if not p:
2719 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2719 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2720 problems += 1
2720 problems += 1
2721
2721
2722 # editor
2722 # editor
2723 ui.status(_("checking commit editor...\n"))
2723 ui.status(_("checking commit editor...\n"))
2724 editor = ui.geteditor()
2724 editor = ui.geteditor()
2725 editor = util.expandpath(editor)
2725 editor = util.expandpath(editor)
2726 cmdpath = util.findexe(shlex.split(editor)[0])
2726 cmdpath = util.findexe(shlex.split(editor)[0])
2727 if not cmdpath:
2727 if not cmdpath:
2728 if editor == 'vi':
2728 if editor == 'vi':
2729 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2729 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2730 ui.write(_(" (specify a commit editor in your configuration"
2730 ui.write(_(" (specify a commit editor in your configuration"
2731 " file)\n"))
2731 " file)\n"))
2732 else:
2732 else:
2733 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2733 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2734 ui.write(_(" (specify a commit editor in your configuration"
2734 ui.write(_(" (specify a commit editor in your configuration"
2735 " file)\n"))
2735 " file)\n"))
2736 problems += 1
2736 problems += 1
2737
2737
2738 # check username
2738 # check username
2739 ui.status(_("checking username...\n"))
2739 ui.status(_("checking username...\n"))
2740 try:
2740 try:
2741 ui.username()
2741 ui.username()
2742 except error.Abort as e:
2742 except error.Abort as e:
2743 ui.write(" %s\n" % e)
2743 ui.write(" %s\n" % e)
2744 ui.write(_(" (specify a username in your configuration file)\n"))
2744 ui.write(_(" (specify a username in your configuration file)\n"))
2745 problems += 1
2745 problems += 1
2746
2746
2747 if not problems:
2747 if not problems:
2748 ui.status(_("no problems detected\n"))
2748 ui.status(_("no problems detected\n"))
2749 else:
2749 else:
2750 ui.write(_("%s problems detected,"
2750 ui.write(_("%s problems detected,"
2751 " please check your install!\n") % problems)
2751 " please check your install!\n") % problems)
2752
2752
2753 return problems
2753 return problems
2754
2754
2755 @command('debugknown', [], _('REPO ID...'), norepo=True)
2755 @command('debugknown', [], _('REPO ID...'), norepo=True)
2756 def debugknown(ui, repopath, *ids, **opts):
2756 def debugknown(ui, repopath, *ids, **opts):
2757 """test whether node ids are known to a repo
2757 """test whether node ids are known to a repo
2758
2758
2759 Every ID must be a full-length hex node id string. Returns a list of 0s
2759 Every ID must be a full-length hex node id string. Returns a list of 0s
2760 and 1s indicating unknown/known.
2760 and 1s indicating unknown/known.
2761 """
2761 """
2762 repo = hg.peer(ui, opts, repopath)
2762 repo = hg.peer(ui, opts, repopath)
2763 if not repo.capable('known'):
2763 if not repo.capable('known'):
2764 raise error.Abort("known() not supported by target repository")
2764 raise error.Abort("known() not supported by target repository")
2765 flags = repo.known([bin(s) for s in ids])
2765 flags = repo.known([bin(s) for s in ids])
2766 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2766 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2767
2767
2768 @command('debuglabelcomplete', [], _('LABEL...'))
2768 @command('debuglabelcomplete', [], _('LABEL...'))
2769 def debuglabelcomplete(ui, repo, *args):
2769 def debuglabelcomplete(ui, repo, *args):
2770 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2770 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2771 debugnamecomplete(ui, repo, *args)
2771 debugnamecomplete(ui, repo, *args)
2772
2772
2773 @command('debugmergestate', [], '')
2773 @command('debugmergestate', [], '')
2774 def debugmergestate(ui, repo, *args):
2774 def debugmergestate(ui, repo, *args):
2775 """print merge state
2775 """print merge state
2776
2776
2777 Use --verbose to print out information about whether v1 or v2 merge state
2777 Use --verbose to print out information about whether v1 or v2 merge state
2778 was chosen."""
2778 was chosen."""
2779 def _hashornull(h):
2779 def _hashornull(h):
2780 if h == nullhex:
2780 if h == nullhex:
2781 return 'null'
2781 return 'null'
2782 else:
2782 else:
2783 return h
2783 return h
2784
2784
2785 def printrecords(version):
2785 def printrecords(version):
2786 ui.write(('* version %s records\n') % version)
2786 ui.write(('* version %s records\n') % version)
2787 if version == 1:
2787 if version == 1:
2788 records = v1records
2788 records = v1records
2789 else:
2789 else:
2790 records = v2records
2790 records = v2records
2791
2791
2792 for rtype, record in records:
2792 for rtype, record in records:
2793 # pretty print some record types
2793 # pretty print some record types
2794 if rtype == 'L':
2794 if rtype == 'L':
2795 ui.write(('local: %s\n') % record)
2795 ui.write(('local: %s\n') % record)
2796 elif rtype == 'O':
2796 elif rtype == 'O':
2797 ui.write(('other: %s\n') % record)
2797 ui.write(('other: %s\n') % record)
2798 elif rtype == 'm':
2798 elif rtype == 'm':
2799 driver, mdstate = record.split('\0', 1)
2799 driver, mdstate = record.split('\0', 1)
2800 ui.write(('merge driver: %s (state "%s")\n')
2800 ui.write(('merge driver: %s (state "%s")\n')
2801 % (driver, mdstate))
2801 % (driver, mdstate))
2802 elif rtype in 'FDC':
2802 elif rtype in 'FDC':
2803 r = record.split('\0')
2803 r = record.split('\0')
2804 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2804 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2805 if version == 1:
2805 if version == 1:
2806 onode = 'not stored in v1 format'
2806 onode = 'not stored in v1 format'
2807 flags = r[7]
2807 flags = r[7]
2808 else:
2808 else:
2809 onode, flags = r[7:9]
2809 onode, flags = r[7:9]
2810 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
2810 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
2811 % (f, rtype, state, _hashornull(hash)))
2811 % (f, rtype, state, _hashornull(hash)))
2812 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2812 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2813 ui.write((' ancestor path: %s (node %s)\n')
2813 ui.write((' ancestor path: %s (node %s)\n')
2814 % (afile, _hashornull(anode)))
2814 % (afile, _hashornull(anode)))
2815 ui.write((' other path: %s (node %s)\n')
2815 ui.write((' other path: %s (node %s)\n')
2816 % (ofile, _hashornull(onode)))
2816 % (ofile, _hashornull(onode)))
2817 else:
2817 else:
2818 ui.write(('unrecognized entry: %s\t%s\n')
2818 ui.write(('unrecognized entry: %s\t%s\n')
2819 % (rtype, record.replace('\0', '\t')))
2819 % (rtype, record.replace('\0', '\t')))
2820
2820
2821 # Avoid mergestate.read() since it may raise an exception for unsupported
2821 # Avoid mergestate.read() since it may raise an exception for unsupported
2822 # merge state records. We shouldn't be doing this, but this is OK since this
2822 # merge state records. We shouldn't be doing this, but this is OK since this
2823 # command is pretty low-level.
2823 # command is pretty low-level.
2824 ms = mergemod.mergestate(repo)
2824 ms = mergemod.mergestate(repo)
2825
2825
2826 # sort so that reasonable information is on top
2826 # sort so that reasonable information is on top
2827 v1records = ms._readrecordsv1()
2827 v1records = ms._readrecordsv1()
2828 v2records = ms._readrecordsv2()
2828 v2records = ms._readrecordsv2()
2829 order = 'LOm'
2829 order = 'LOm'
2830 def key(r):
2830 def key(r):
2831 idx = order.find(r[0])
2831 idx = order.find(r[0])
2832 if idx == -1:
2832 if idx == -1:
2833 return (1, r[1])
2833 return (1, r[1])
2834 else:
2834 else:
2835 return (0, idx)
2835 return (0, idx)
2836 v1records.sort(key=key)
2836 v1records.sort(key=key)
2837 v2records.sort(key=key)
2837 v2records.sort(key=key)
2838
2838
2839 if not v1records and not v2records:
2839 if not v1records and not v2records:
2840 ui.write(('no merge state found\n'))
2840 ui.write(('no merge state found\n'))
2841 elif not v2records:
2841 elif not v2records:
2842 ui.note(('no version 2 merge state\n'))
2842 ui.note(('no version 2 merge state\n'))
2843 printrecords(1)
2843 printrecords(1)
2844 elif ms._v1v2match(v1records, v2records):
2844 elif ms._v1v2match(v1records, v2records):
2845 ui.note(('v1 and v2 states match: using v2\n'))
2845 ui.note(('v1 and v2 states match: using v2\n'))
2846 printrecords(2)
2846 printrecords(2)
2847 else:
2847 else:
2848 ui.note(('v1 and v2 states mismatch: using v1\n'))
2848 ui.note(('v1 and v2 states mismatch: using v1\n'))
2849 printrecords(1)
2849 printrecords(1)
2850 if ui.verbose:
2850 if ui.verbose:
2851 printrecords(2)
2851 printrecords(2)
2852
2852
2853 @command('debugnamecomplete', [], _('NAME...'))
2853 @command('debugnamecomplete', [], _('NAME...'))
2854 def debugnamecomplete(ui, repo, *args):
2854 def debugnamecomplete(ui, repo, *args):
2855 '''complete "names" - tags, open branch names, bookmark names'''
2855 '''complete "names" - tags, open branch names, bookmark names'''
2856
2856
2857 names = set()
2857 names = set()
2858 # since we previously only listed open branches, we will handle that
2858 # since we previously only listed open branches, we will handle that
2859 # specially (after this for loop)
2859 # specially (after this for loop)
2860 for name, ns in repo.names.iteritems():
2860 for name, ns in repo.names.iteritems():
2861 if name != 'branches':
2861 if name != 'branches':
2862 names.update(ns.listnames(repo))
2862 names.update(ns.listnames(repo))
2863 names.update(tag for (tag, heads, tip, closed)
2863 names.update(tag for (tag, heads, tip, closed)
2864 in repo.branchmap().iterbranches() if not closed)
2864 in repo.branchmap().iterbranches() if not closed)
2865 completions = set()
2865 completions = set()
2866 if not args:
2866 if not args:
2867 args = ['']
2867 args = ['']
2868 for a in args:
2868 for a in args:
2869 completions.update(n for n in names if n.startswith(a))
2869 completions.update(n for n in names if n.startswith(a))
2870 ui.write('\n'.join(sorted(completions)))
2870 ui.write('\n'.join(sorted(completions)))
2871 ui.write('\n')
2871 ui.write('\n')
2872
2872
2873 @command('debuglocks',
2873 @command('debuglocks',
2874 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2874 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2875 ('W', 'force-wlock', None,
2875 ('W', 'force-wlock', None,
2876 _('free the working state lock (DANGEROUS)'))],
2876 _('free the working state lock (DANGEROUS)'))],
2877 _('[OPTION]...'))
2877 _('[OPTION]...'))
2878 def debuglocks(ui, repo, **opts):
2878 def debuglocks(ui, repo, **opts):
2879 """show or modify state of locks
2879 """show or modify state of locks
2880
2880
2881 By default, this command will show which locks are held. This
2881 By default, this command will show which locks are held. This
2882 includes the user and process holding the lock, the amount of time
2882 includes the user and process holding the lock, the amount of time
2883 the lock has been held, and the machine name where the process is
2883 the lock has been held, and the machine name where the process is
2884 running if it's not local.
2884 running if it's not local.
2885
2885
2886 Locks protect the integrity of Mercurial's data, so should be
2886 Locks protect the integrity of Mercurial's data, so should be
2887 treated with care. System crashes or other interruptions may cause
2887 treated with care. System crashes or other interruptions may cause
2888 locks to not be properly released, though Mercurial will usually
2888 locks to not be properly released, though Mercurial will usually
2889 detect and remove such stale locks automatically.
2889 detect and remove such stale locks automatically.
2890
2890
2891 However, detecting stale locks may not always be possible (for
2891 However, detecting stale locks may not always be possible (for
2892 instance, on a shared filesystem). Removing locks may also be
2892 instance, on a shared filesystem). Removing locks may also be
2893 blocked by filesystem permissions.
2893 blocked by filesystem permissions.
2894
2894
2895 Returns 0 if no locks are held.
2895 Returns 0 if no locks are held.
2896
2896
2897 """
2897 """
2898
2898
2899 if opts.get('force_lock'):
2899 if opts.get('force_lock'):
2900 repo.svfs.unlink('lock')
2900 repo.svfs.unlink('lock')
2901 if opts.get('force_wlock'):
2901 if opts.get('force_wlock'):
2902 repo.vfs.unlink('wlock')
2902 repo.vfs.unlink('wlock')
2903 if opts.get('force_lock') or opts.get('force_lock'):
2903 if opts.get('force_lock') or opts.get('force_lock'):
2904 return 0
2904 return 0
2905
2905
2906 now = time.time()
2906 now = time.time()
2907 held = 0
2907 held = 0
2908
2908
2909 def report(vfs, name, method):
2909 def report(vfs, name, method):
2910 # this causes stale locks to get reaped for more accurate reporting
2910 # this causes stale locks to get reaped for more accurate reporting
2911 try:
2911 try:
2912 l = method(False)
2912 l = method(False)
2913 except error.LockHeld:
2913 except error.LockHeld:
2914 l = None
2914 l = None
2915
2915
2916 if l:
2916 if l:
2917 l.release()
2917 l.release()
2918 else:
2918 else:
2919 try:
2919 try:
2920 stat = vfs.lstat(name)
2920 stat = vfs.lstat(name)
2921 age = now - stat.st_mtime
2921 age = now - stat.st_mtime
2922 user = util.username(stat.st_uid)
2922 user = util.username(stat.st_uid)
2923 locker = vfs.readlock(name)
2923 locker = vfs.readlock(name)
2924 if ":" in locker:
2924 if ":" in locker:
2925 host, pid = locker.split(':')
2925 host, pid = locker.split(':')
2926 if host == socket.gethostname():
2926 if host == socket.gethostname():
2927 locker = 'user %s, process %s' % (user, pid)
2927 locker = 'user %s, process %s' % (user, pid)
2928 else:
2928 else:
2929 locker = 'user %s, process %s, host %s' \
2929 locker = 'user %s, process %s, host %s' \
2930 % (user, pid, host)
2930 % (user, pid, host)
2931 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
2931 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
2932 return 1
2932 return 1
2933 except OSError as e:
2933 except OSError as e:
2934 if e.errno != errno.ENOENT:
2934 if e.errno != errno.ENOENT:
2935 raise
2935 raise
2936
2936
2937 ui.write("%-6s free\n" % (name + ":"))
2937 ui.write("%-6s free\n" % (name + ":"))
2938 return 0
2938 return 0
2939
2939
2940 held += report(repo.svfs, "lock", repo.lock)
2940 held += report(repo.svfs, "lock", repo.lock)
2941 held += report(repo.vfs, "wlock", repo.wlock)
2941 held += report(repo.vfs, "wlock", repo.wlock)
2942
2942
2943 return held
2943 return held
2944
2944
2945 @command('debugobsolete',
2945 @command('debugobsolete',
2946 [('', 'flags', 0, _('markers flag')),
2946 [('', 'flags', 0, _('markers flag')),
2947 ('', 'record-parents', False,
2947 ('', 'record-parents', False,
2948 _('record parent information for the precursor')),
2948 _('record parent information for the precursor')),
2949 ('r', 'rev', [], _('display markers relevant to REV')),
2949 ('r', 'rev', [], _('display markers relevant to REV')),
2950 ] + commitopts2,
2950 ] + commitopts2,
2951 _('[OBSOLETED [REPLACEMENT ...]]'))
2951 _('[OBSOLETED [REPLACEMENT ...]]'))
2952 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2952 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2953 """create arbitrary obsolete marker
2953 """create arbitrary obsolete marker
2954
2954
2955 With no arguments, displays the list of obsolescence markers."""
2955 With no arguments, displays the list of obsolescence markers."""
2956
2956
2957 def parsenodeid(s):
2957 def parsenodeid(s):
2958 try:
2958 try:
2959 # We do not use revsingle/revrange functions here to accept
2959 # We do not use revsingle/revrange functions here to accept
2960 # arbitrary node identifiers, possibly not present in the
2960 # arbitrary node identifiers, possibly not present in the
2961 # local repository.
2961 # local repository.
2962 n = bin(s)
2962 n = bin(s)
2963 if len(n) != len(nullid):
2963 if len(n) != len(nullid):
2964 raise TypeError()
2964 raise TypeError()
2965 return n
2965 return n
2966 except TypeError:
2966 except TypeError:
2967 raise error.Abort('changeset references must be full hexadecimal '
2967 raise error.Abort('changeset references must be full hexadecimal '
2968 'node identifiers')
2968 'node identifiers')
2969
2969
2970 if precursor is not None:
2970 if precursor is not None:
2971 if opts['rev']:
2971 if opts['rev']:
2972 raise error.Abort('cannot select revision when creating marker')
2972 raise error.Abort('cannot select revision when creating marker')
2973 metadata = {}
2973 metadata = {}
2974 metadata['user'] = opts['user'] or ui.username()
2974 metadata['user'] = opts['user'] or ui.username()
2975 succs = tuple(parsenodeid(succ) for succ in successors)
2975 succs = tuple(parsenodeid(succ) for succ in successors)
2976 l = repo.lock()
2976 l = repo.lock()
2977 try:
2977 try:
2978 tr = repo.transaction('debugobsolete')
2978 tr = repo.transaction('debugobsolete')
2979 try:
2979 try:
2980 date = opts.get('date')
2980 date = opts.get('date')
2981 if date:
2981 if date:
2982 date = util.parsedate(date)
2982 date = util.parsedate(date)
2983 else:
2983 else:
2984 date = None
2984 date = None
2985 prec = parsenodeid(precursor)
2985 prec = parsenodeid(precursor)
2986 parents = None
2986 parents = None
2987 if opts['record_parents']:
2987 if opts['record_parents']:
2988 if prec not in repo.unfiltered():
2988 if prec not in repo.unfiltered():
2989 raise error.Abort('cannot used --record-parents on '
2989 raise error.Abort('cannot used --record-parents on '
2990 'unknown changesets')
2990 'unknown changesets')
2991 parents = repo.unfiltered()[prec].parents()
2991 parents = repo.unfiltered()[prec].parents()
2992 parents = tuple(p.node() for p in parents)
2992 parents = tuple(p.node() for p in parents)
2993 repo.obsstore.create(tr, prec, succs, opts['flags'],
2993 repo.obsstore.create(tr, prec, succs, opts['flags'],
2994 parents=parents, date=date,
2994 parents=parents, date=date,
2995 metadata=metadata)
2995 metadata=metadata)
2996 tr.close()
2996 tr.close()
2997 except ValueError as exc:
2997 except ValueError as exc:
2998 raise error.Abort(_('bad obsmarker input: %s') % exc)
2998 raise error.Abort(_('bad obsmarker input: %s') % exc)
2999 finally:
2999 finally:
3000 tr.release()
3000 tr.release()
3001 finally:
3001 finally:
3002 l.release()
3002 l.release()
3003 else:
3003 else:
3004 if opts['rev']:
3004 if opts['rev']:
3005 revs = scmutil.revrange(repo, opts['rev'])
3005 revs = scmutil.revrange(repo, opts['rev'])
3006 nodes = [repo[r].node() for r in revs]
3006 nodes = [repo[r].node() for r in revs]
3007 markers = list(obsolete.getmarkers(repo, nodes=nodes))
3007 markers = list(obsolete.getmarkers(repo, nodes=nodes))
3008 markers.sort(key=lambda x: x._data)
3008 markers.sort(key=lambda x: x._data)
3009 else:
3009 else:
3010 markers = obsolete.getmarkers(repo)
3010 markers = obsolete.getmarkers(repo)
3011
3011
3012 for m in markers:
3012 for m in markers:
3013 cmdutil.showmarker(ui, m)
3013 cmdutil.showmarker(ui, m)
3014
3014
3015 @command('debugpathcomplete',
3015 @command('debugpathcomplete',
3016 [('f', 'full', None, _('complete an entire path')),
3016 [('f', 'full', None, _('complete an entire path')),
3017 ('n', 'normal', None, _('show only normal files')),
3017 ('n', 'normal', None, _('show only normal files')),
3018 ('a', 'added', None, _('show only added files')),
3018 ('a', 'added', None, _('show only added files')),
3019 ('r', 'removed', None, _('show only removed files'))],
3019 ('r', 'removed', None, _('show only removed files'))],
3020 _('FILESPEC...'))
3020 _('FILESPEC...'))
3021 def debugpathcomplete(ui, repo, *specs, **opts):
3021 def debugpathcomplete(ui, repo, *specs, **opts):
3022 '''complete part or all of a tracked path
3022 '''complete part or all of a tracked path
3023
3023
3024 This command supports shells that offer path name completion. It
3024 This command supports shells that offer path name completion. It
3025 currently completes only files already known to the dirstate.
3025 currently completes only files already known to the dirstate.
3026
3026
3027 Completion extends only to the next path segment unless
3027 Completion extends only to the next path segment unless
3028 --full is specified, in which case entire paths are used.'''
3028 --full is specified, in which case entire paths are used.'''
3029
3029
3030 def complete(path, acceptable):
3030 def complete(path, acceptable):
3031 dirstate = repo.dirstate
3031 dirstate = repo.dirstate
3032 spec = os.path.normpath(os.path.join(os.getcwd(), path))
3032 spec = os.path.normpath(os.path.join(os.getcwd(), path))
3033 rootdir = repo.root + os.sep
3033 rootdir = repo.root + os.sep
3034 if spec != repo.root and not spec.startswith(rootdir):
3034 if spec != repo.root and not spec.startswith(rootdir):
3035 return [], []
3035 return [], []
3036 if os.path.isdir(spec):
3036 if os.path.isdir(spec):
3037 spec += '/'
3037 spec += '/'
3038 spec = spec[len(rootdir):]
3038 spec = spec[len(rootdir):]
3039 fixpaths = os.sep != '/'
3039 fixpaths = os.sep != '/'
3040 if fixpaths:
3040 if fixpaths:
3041 spec = spec.replace(os.sep, '/')
3041 spec = spec.replace(os.sep, '/')
3042 speclen = len(spec)
3042 speclen = len(spec)
3043 fullpaths = opts['full']
3043 fullpaths = opts['full']
3044 files, dirs = set(), set()
3044 files, dirs = set(), set()
3045 adddir, addfile = dirs.add, files.add
3045 adddir, addfile = dirs.add, files.add
3046 for f, st in dirstate.iteritems():
3046 for f, st in dirstate.iteritems():
3047 if f.startswith(spec) and st[0] in acceptable:
3047 if f.startswith(spec) and st[0] in acceptable:
3048 if fixpaths:
3048 if fixpaths:
3049 f = f.replace('/', os.sep)
3049 f = f.replace('/', os.sep)
3050 if fullpaths:
3050 if fullpaths:
3051 addfile(f)
3051 addfile(f)
3052 continue
3052 continue
3053 s = f.find(os.sep, speclen)
3053 s = f.find(os.sep, speclen)
3054 if s >= 0:
3054 if s >= 0:
3055 adddir(f[:s])
3055 adddir(f[:s])
3056 else:
3056 else:
3057 addfile(f)
3057 addfile(f)
3058 return files, dirs
3058 return files, dirs
3059
3059
3060 acceptable = ''
3060 acceptable = ''
3061 if opts['normal']:
3061 if opts['normal']:
3062 acceptable += 'nm'
3062 acceptable += 'nm'
3063 if opts['added']:
3063 if opts['added']:
3064 acceptable += 'a'
3064 acceptable += 'a'
3065 if opts['removed']:
3065 if opts['removed']:
3066 acceptable += 'r'
3066 acceptable += 'r'
3067 cwd = repo.getcwd()
3067 cwd = repo.getcwd()
3068 if not specs:
3068 if not specs:
3069 specs = ['.']
3069 specs = ['.']
3070
3070
3071 files, dirs = set(), set()
3071 files, dirs = set(), set()
3072 for spec in specs:
3072 for spec in specs:
3073 f, d = complete(spec, acceptable or 'nmar')
3073 f, d = complete(spec, acceptable or 'nmar')
3074 files.update(f)
3074 files.update(f)
3075 dirs.update(d)
3075 dirs.update(d)
3076 files.update(dirs)
3076 files.update(dirs)
3077 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
3077 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
3078 ui.write('\n')
3078 ui.write('\n')
3079
3079
3080 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
3080 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
3081 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
3081 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
3082 '''access the pushkey key/value protocol
3082 '''access the pushkey key/value protocol
3083
3083
3084 With two args, list the keys in the given namespace.
3084 With two args, list the keys in the given namespace.
3085
3085
3086 With five args, set a key to new if it currently is set to old.
3086 With five args, set a key to new if it currently is set to old.
3087 Reports success or failure.
3087 Reports success or failure.
3088 '''
3088 '''
3089
3089
3090 target = hg.peer(ui, {}, repopath)
3090 target = hg.peer(ui, {}, repopath)
3091 if keyinfo:
3091 if keyinfo:
3092 key, old, new = keyinfo
3092 key, old, new = keyinfo
3093 r = target.pushkey(namespace, key, old, new)
3093 r = target.pushkey(namespace, key, old, new)
3094 ui.status(str(r) + '\n')
3094 ui.status(str(r) + '\n')
3095 return not r
3095 return not r
3096 else:
3096 else:
3097 for k, v in sorted(target.listkeys(namespace).iteritems()):
3097 for k, v in sorted(target.listkeys(namespace).iteritems()):
3098 ui.write("%s\t%s\n" % (k.encode('string-escape'),
3098 ui.write("%s\t%s\n" % (k.encode('string-escape'),
3099 v.encode('string-escape')))
3099 v.encode('string-escape')))
3100
3100
3101 @command('debugpvec', [], _('A B'))
3101 @command('debugpvec', [], _('A B'))
3102 def debugpvec(ui, repo, a, b=None):
3102 def debugpvec(ui, repo, a, b=None):
3103 ca = scmutil.revsingle(repo, a)
3103 ca = scmutil.revsingle(repo, a)
3104 cb = scmutil.revsingle(repo, b)
3104 cb = scmutil.revsingle(repo, b)
3105 pa = pvec.ctxpvec(ca)
3105 pa = pvec.ctxpvec(ca)
3106 pb = pvec.ctxpvec(cb)
3106 pb = pvec.ctxpvec(cb)
3107 if pa == pb:
3107 if pa == pb:
3108 rel = "="
3108 rel = "="
3109 elif pa > pb:
3109 elif pa > pb:
3110 rel = ">"
3110 rel = ">"
3111 elif pa < pb:
3111 elif pa < pb:
3112 rel = "<"
3112 rel = "<"
3113 elif pa | pb:
3113 elif pa | pb:
3114 rel = "|"
3114 rel = "|"
3115 ui.write(_("a: %s\n") % pa)
3115 ui.write(_("a: %s\n") % pa)
3116 ui.write(_("b: %s\n") % pb)
3116 ui.write(_("b: %s\n") % pb)
3117 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
3117 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
3118 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
3118 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
3119 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
3119 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
3120 pa.distance(pb), rel))
3120 pa.distance(pb), rel))
3121
3121
3122 @command('debugrebuilddirstate|debugrebuildstate',
3122 @command('debugrebuilddirstate|debugrebuildstate',
3123 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
3123 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
3124 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
3124 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
3125 'the working copy parent')),
3125 'the working copy parent')),
3126 ],
3126 ],
3127 _('[-r REV]'))
3127 _('[-r REV]'))
3128 def debugrebuilddirstate(ui, repo, rev, **opts):
3128 def debugrebuilddirstate(ui, repo, rev, **opts):
3129 """rebuild the dirstate as it would look like for the given revision
3129 """rebuild the dirstate as it would look like for the given revision
3130
3130
3131 If no revision is specified the first current parent will be used.
3131 If no revision is specified the first current parent will be used.
3132
3132
3133 The dirstate will be set to the files of the given revision.
3133 The dirstate will be set to the files of the given revision.
3134 The actual working directory content or existing dirstate
3134 The actual working directory content or existing dirstate
3135 information such as adds or removes is not considered.
3135 information such as adds or removes is not considered.
3136
3136
3137 ``minimal`` will only rebuild the dirstate status for files that claim to be
3137 ``minimal`` will only rebuild the dirstate status for files that claim to be
3138 tracked but are not in the parent manifest, or that exist in the parent
3138 tracked but are not in the parent manifest, or that exist in the parent
3139 manifest but are not in the dirstate. It will not change adds, removes, or
3139 manifest but are not in the dirstate. It will not change adds, removes, or
3140 modified files that are in the working copy parent.
3140 modified files that are in the working copy parent.
3141
3141
3142 One use of this command is to make the next :hg:`status` invocation
3142 One use of this command is to make the next :hg:`status` invocation
3143 check the actual file content.
3143 check the actual file content.
3144 """
3144 """
3145 ctx = scmutil.revsingle(repo, rev)
3145 ctx = scmutil.revsingle(repo, rev)
3146 with repo.wlock():
3146 with repo.wlock():
3147 dirstate = repo.dirstate
3147 dirstate = repo.dirstate
3148 changedfiles = None
3148 changedfiles = None
3149 # See command doc for what minimal does.
3149 # See command doc for what minimal does.
3150 if opts.get('minimal'):
3150 if opts.get('minimal'):
3151 manifestfiles = set(ctx.manifest().keys())
3151 manifestfiles = set(ctx.manifest().keys())
3152 dirstatefiles = set(dirstate)
3152 dirstatefiles = set(dirstate)
3153 manifestonly = manifestfiles - dirstatefiles
3153 manifestonly = manifestfiles - dirstatefiles
3154 dsonly = dirstatefiles - manifestfiles
3154 dsonly = dirstatefiles - manifestfiles
3155 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
3155 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
3156 changedfiles = manifestonly | dsnotadded
3156 changedfiles = manifestonly | dsnotadded
3157
3157
3158 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
3158 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
3159
3159
3160 @command('debugrebuildfncache', [], '')
3160 @command('debugrebuildfncache', [], '')
3161 def debugrebuildfncache(ui, repo):
3161 def debugrebuildfncache(ui, repo):
3162 """rebuild the fncache file"""
3162 """rebuild the fncache file"""
3163 repair.rebuildfncache(ui, repo)
3163 repair.rebuildfncache(ui, repo)
3164
3164
3165 @command('debugrename',
3165 @command('debugrename',
3166 [('r', 'rev', '', _('revision to debug'), _('REV'))],
3166 [('r', 'rev', '', _('revision to debug'), _('REV'))],
3167 _('[-r REV] FILE'))
3167 _('[-r REV] FILE'))
3168 def debugrename(ui, repo, file1, *pats, **opts):
3168 def debugrename(ui, repo, file1, *pats, **opts):
3169 """dump rename information"""
3169 """dump rename information"""
3170
3170
3171 ctx = scmutil.revsingle(repo, opts.get('rev'))
3171 ctx = scmutil.revsingle(repo, opts.get('rev'))
3172 m = scmutil.match(ctx, (file1,) + pats, opts)
3172 m = scmutil.match(ctx, (file1,) + pats, opts)
3173 for abs in ctx.walk(m):
3173 for abs in ctx.walk(m):
3174 fctx = ctx[abs]
3174 fctx = ctx[abs]
3175 o = fctx.filelog().renamed(fctx.filenode())
3175 o = fctx.filelog().renamed(fctx.filenode())
3176 rel = m.rel(abs)
3176 rel = m.rel(abs)
3177 if o:
3177 if o:
3178 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
3178 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
3179 else:
3179 else:
3180 ui.write(_("%s not renamed\n") % rel)
3180 ui.write(_("%s not renamed\n") % rel)
3181
3181
3182 @command('debugrevlog', debugrevlogopts +
3182 @command('debugrevlog', debugrevlogopts +
3183 [('d', 'dump', False, _('dump index data'))],
3183 [('d', 'dump', False, _('dump index data'))],
3184 _('-c|-m|FILE'),
3184 _('-c|-m|FILE'),
3185 optionalrepo=True)
3185 optionalrepo=True)
3186 def debugrevlog(ui, repo, file_=None, **opts):
3186 def debugrevlog(ui, repo, file_=None, **opts):
3187 """show data and statistics about a revlog"""
3187 """show data and statistics about a revlog"""
3188 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
3188 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
3189
3189
3190 if opts.get("dump"):
3190 if opts.get("dump"):
3191 numrevs = len(r)
3191 numrevs = len(r)
3192 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
3192 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
3193 " rawsize totalsize compression heads chainlen\n")
3193 " rawsize totalsize compression heads chainlen\n")
3194 ts = 0
3194 ts = 0
3195 heads = set()
3195 heads = set()
3196
3196
3197 for rev in xrange(numrevs):
3197 for rev in xrange(numrevs):
3198 dbase = r.deltaparent(rev)
3198 dbase = r.deltaparent(rev)
3199 if dbase == -1:
3199 if dbase == -1:
3200 dbase = rev
3200 dbase = rev
3201 cbase = r.chainbase(rev)
3201 cbase = r.chainbase(rev)
3202 clen = r.chainlen(rev)
3202 clen = r.chainlen(rev)
3203 p1, p2 = r.parentrevs(rev)
3203 p1, p2 = r.parentrevs(rev)
3204 rs = r.rawsize(rev)
3204 rs = r.rawsize(rev)
3205 ts = ts + rs
3205 ts = ts + rs
3206 heads -= set(r.parentrevs(rev))
3206 heads -= set(r.parentrevs(rev))
3207 heads.add(rev)
3207 heads.add(rev)
3208 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
3208 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
3209 "%11d %5d %8d\n" %
3209 "%11d %5d %8d\n" %
3210 (rev, p1, p2, r.start(rev), r.end(rev),
3210 (rev, p1, p2, r.start(rev), r.end(rev),
3211 r.start(dbase), r.start(cbase),
3211 r.start(dbase), r.start(cbase),
3212 r.start(p1), r.start(p2),
3212 r.start(p1), r.start(p2),
3213 rs, ts, ts / r.end(rev), len(heads), clen))
3213 rs, ts, ts / r.end(rev), len(heads), clen))
3214 return 0
3214 return 0
3215
3215
3216 v = r.version
3216 v = r.version
3217 format = v & 0xFFFF
3217 format = v & 0xFFFF
3218 flags = []
3218 flags = []
3219 gdelta = False
3219 gdelta = False
3220 if v & revlog.REVLOGNGINLINEDATA:
3220 if v & revlog.REVLOGNGINLINEDATA:
3221 flags.append('inline')
3221 flags.append('inline')
3222 if v & revlog.REVLOGGENERALDELTA:
3222 if v & revlog.REVLOGGENERALDELTA:
3223 gdelta = True
3223 gdelta = True
3224 flags.append('generaldelta')
3224 flags.append('generaldelta')
3225 if not flags:
3225 if not flags:
3226 flags = ['(none)']
3226 flags = ['(none)']
3227
3227
3228 nummerges = 0
3228 nummerges = 0
3229 numfull = 0
3229 numfull = 0
3230 numprev = 0
3230 numprev = 0
3231 nump1 = 0
3231 nump1 = 0
3232 nump2 = 0
3232 nump2 = 0
3233 numother = 0
3233 numother = 0
3234 nump1prev = 0
3234 nump1prev = 0
3235 nump2prev = 0
3235 nump2prev = 0
3236 chainlengths = []
3236 chainlengths = []
3237
3237
3238 datasize = [None, 0, 0L]
3238 datasize = [None, 0, 0L]
3239 fullsize = [None, 0, 0L]
3239 fullsize = [None, 0, 0L]
3240 deltasize = [None, 0, 0L]
3240 deltasize = [None, 0, 0L]
3241
3241
3242 def addsize(size, l):
3242 def addsize(size, l):
3243 if l[0] is None or size < l[0]:
3243 if l[0] is None or size < l[0]:
3244 l[0] = size
3244 l[0] = size
3245 if size > l[1]:
3245 if size > l[1]:
3246 l[1] = size
3246 l[1] = size
3247 l[2] += size
3247 l[2] += size
3248
3248
3249 numrevs = len(r)
3249 numrevs = len(r)
3250 for rev in xrange(numrevs):
3250 for rev in xrange(numrevs):
3251 p1, p2 = r.parentrevs(rev)
3251 p1, p2 = r.parentrevs(rev)
3252 delta = r.deltaparent(rev)
3252 delta = r.deltaparent(rev)
3253 if format > 0:
3253 if format > 0:
3254 addsize(r.rawsize(rev), datasize)
3254 addsize(r.rawsize(rev), datasize)
3255 if p2 != nullrev:
3255 if p2 != nullrev:
3256 nummerges += 1
3256 nummerges += 1
3257 size = r.length(rev)
3257 size = r.length(rev)
3258 if delta == nullrev:
3258 if delta == nullrev:
3259 chainlengths.append(0)
3259 chainlengths.append(0)
3260 numfull += 1
3260 numfull += 1
3261 addsize(size, fullsize)
3261 addsize(size, fullsize)
3262 else:
3262 else:
3263 chainlengths.append(chainlengths[delta] + 1)
3263 chainlengths.append(chainlengths[delta] + 1)
3264 addsize(size, deltasize)
3264 addsize(size, deltasize)
3265 if delta == rev - 1:
3265 if delta == rev - 1:
3266 numprev += 1
3266 numprev += 1
3267 if delta == p1:
3267 if delta == p1:
3268 nump1prev += 1
3268 nump1prev += 1
3269 elif delta == p2:
3269 elif delta == p2:
3270 nump2prev += 1
3270 nump2prev += 1
3271 elif delta == p1:
3271 elif delta == p1:
3272 nump1 += 1
3272 nump1 += 1
3273 elif delta == p2:
3273 elif delta == p2:
3274 nump2 += 1
3274 nump2 += 1
3275 elif delta != nullrev:
3275 elif delta != nullrev:
3276 numother += 1
3276 numother += 1
3277
3277
3278 # Adjust size min value for empty cases
3278 # Adjust size min value for empty cases
3279 for size in (datasize, fullsize, deltasize):
3279 for size in (datasize, fullsize, deltasize):
3280 if size[0] is None:
3280 if size[0] is None:
3281 size[0] = 0
3281 size[0] = 0
3282
3282
3283 numdeltas = numrevs - numfull
3283 numdeltas = numrevs - numfull
3284 numoprev = numprev - nump1prev - nump2prev
3284 numoprev = numprev - nump1prev - nump2prev
3285 totalrawsize = datasize[2]
3285 totalrawsize = datasize[2]
3286 datasize[2] /= numrevs
3286 datasize[2] /= numrevs
3287 fulltotal = fullsize[2]
3287 fulltotal = fullsize[2]
3288 fullsize[2] /= numfull
3288 fullsize[2] /= numfull
3289 deltatotal = deltasize[2]
3289 deltatotal = deltasize[2]
3290 if numrevs - numfull > 0:
3290 if numrevs - numfull > 0:
3291 deltasize[2] /= numrevs - numfull
3291 deltasize[2] /= numrevs - numfull
3292 totalsize = fulltotal + deltatotal
3292 totalsize = fulltotal + deltatotal
3293 avgchainlen = sum(chainlengths) / numrevs
3293 avgchainlen = sum(chainlengths) / numrevs
3294 maxchainlen = max(chainlengths)
3294 maxchainlen = max(chainlengths)
3295 compratio = 1
3295 compratio = 1
3296 if totalsize:
3296 if totalsize:
3297 compratio = totalrawsize / totalsize
3297 compratio = totalrawsize / totalsize
3298
3298
3299 basedfmtstr = '%%%dd\n'
3299 basedfmtstr = '%%%dd\n'
3300 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3300 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3301
3301
3302 def dfmtstr(max):
3302 def dfmtstr(max):
3303 return basedfmtstr % len(str(max))
3303 return basedfmtstr % len(str(max))
3304 def pcfmtstr(max, padding=0):
3304 def pcfmtstr(max, padding=0):
3305 return basepcfmtstr % (len(str(max)), ' ' * padding)
3305 return basepcfmtstr % (len(str(max)), ' ' * padding)
3306
3306
3307 def pcfmt(value, total):
3307 def pcfmt(value, total):
3308 if total:
3308 if total:
3309 return (value, 100 * float(value) / total)
3309 return (value, 100 * float(value) / total)
3310 else:
3310 else:
3311 return value, 100.0
3311 return value, 100.0
3312
3312
3313 ui.write(('format : %d\n') % format)
3313 ui.write(('format : %d\n') % format)
3314 ui.write(('flags : %s\n') % ', '.join(flags))
3314 ui.write(('flags : %s\n') % ', '.join(flags))
3315
3315
3316 ui.write('\n')
3316 ui.write('\n')
3317 fmt = pcfmtstr(totalsize)
3317 fmt = pcfmtstr(totalsize)
3318 fmt2 = dfmtstr(totalsize)
3318 fmt2 = dfmtstr(totalsize)
3319 ui.write(('revisions : ') + fmt2 % numrevs)
3319 ui.write(('revisions : ') + fmt2 % numrevs)
3320 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3320 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3321 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3321 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3322 ui.write(('revisions : ') + fmt2 % numrevs)
3322 ui.write(('revisions : ') + fmt2 % numrevs)
3323 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3323 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3324 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3324 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3325 ui.write(('revision size : ') + fmt2 % totalsize)
3325 ui.write(('revision size : ') + fmt2 % totalsize)
3326 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3326 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3327 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3327 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3328
3328
3329 ui.write('\n')
3329 ui.write('\n')
3330 fmt = dfmtstr(max(avgchainlen, compratio))
3330 fmt = dfmtstr(max(avgchainlen, compratio))
3331 ui.write(('avg chain length : ') + fmt % avgchainlen)
3331 ui.write(('avg chain length : ') + fmt % avgchainlen)
3332 ui.write(('max chain length : ') + fmt % maxchainlen)
3332 ui.write(('max chain length : ') + fmt % maxchainlen)
3333 ui.write(('compression ratio : ') + fmt % compratio)
3333 ui.write(('compression ratio : ') + fmt % compratio)
3334
3334
3335 if format > 0:
3335 if format > 0:
3336 ui.write('\n')
3336 ui.write('\n')
3337 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
3337 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
3338 % tuple(datasize))
3338 % tuple(datasize))
3339 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
3339 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
3340 % tuple(fullsize))
3340 % tuple(fullsize))
3341 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3341 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3342 % tuple(deltasize))
3342 % tuple(deltasize))
3343
3343
3344 if numdeltas > 0:
3344 if numdeltas > 0:
3345 ui.write('\n')
3345 ui.write('\n')
3346 fmt = pcfmtstr(numdeltas)
3346 fmt = pcfmtstr(numdeltas)
3347 fmt2 = pcfmtstr(numdeltas, 4)
3347 fmt2 = pcfmtstr(numdeltas, 4)
3348 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3348 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3349 if numprev > 0:
3349 if numprev > 0:
3350 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3350 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3351 numprev))
3351 numprev))
3352 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3352 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3353 numprev))
3353 numprev))
3354 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3354 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3355 numprev))
3355 numprev))
3356 if gdelta:
3356 if gdelta:
3357 ui.write(('deltas against p1 : ')
3357 ui.write(('deltas against p1 : ')
3358 + fmt % pcfmt(nump1, numdeltas))
3358 + fmt % pcfmt(nump1, numdeltas))
3359 ui.write(('deltas against p2 : ')
3359 ui.write(('deltas against p2 : ')
3360 + fmt % pcfmt(nump2, numdeltas))
3360 + fmt % pcfmt(nump2, numdeltas))
3361 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3361 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3362 numdeltas))
3362 numdeltas))
3363
3363
3364 @command('debugrevspec',
3364 @command('debugrevspec',
3365 [('', 'optimize', None, _('print parsed tree after optimizing'))],
3365 [('', 'optimize', None, _('print parsed tree after optimizing'))],
3366 ('REVSPEC'))
3366 ('REVSPEC'))
3367 def debugrevspec(ui, repo, expr, **opts):
3367 def debugrevspec(ui, repo, expr, **opts):
3368 """parse and apply a revision specification
3368 """parse and apply a revision specification
3369
3369
3370 Use --verbose to print the parsed tree before and after aliases
3370 Use --verbose to print the parsed tree before and after aliases
3371 expansion.
3371 expansion.
3372 """
3372 """
3373 if ui.verbose:
3373 if ui.verbose:
3374 tree = revset.parse(expr, lookup=repo.__contains__)
3374 tree = revset.parse(expr, lookup=repo.__contains__)
3375 ui.note(revset.prettyformat(tree), "\n")
3375 ui.note(revset.prettyformat(tree), "\n")
3376 newtree = revset.findaliases(ui, tree)
3376 newtree = revset.findaliases(ui, tree)
3377 if newtree != tree:
3377 if newtree != tree:
3378 ui.note(revset.prettyformat(newtree), "\n")
3378 ui.note(revset.prettyformat(newtree), "\n")
3379 tree = newtree
3379 tree = newtree
3380 newtree = revset.foldconcat(tree)
3380 newtree = revset.foldconcat(tree)
3381 if newtree != tree:
3381 if newtree != tree:
3382 ui.note(revset.prettyformat(newtree), "\n")
3382 ui.note(revset.prettyformat(newtree), "\n")
3383 if opts["optimize"]:
3383 if opts["optimize"]:
3384 weight, optimizedtree = revset.optimize(newtree, True)
3384 weight, optimizedtree = revset.optimize(newtree, True)
3385 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
3385 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
3386 func = revset.match(ui, expr, repo)
3386 func = revset.match(ui, expr, repo)
3387 revs = func(repo)
3387 revs = func(repo)
3388 if ui.verbose:
3388 if ui.verbose:
3389 ui.note("* set:\n", revset.prettyformatset(revs), "\n")
3389 ui.note("* set:\n", revset.prettyformatset(revs), "\n")
3390 for c in revs:
3390 for c in revs:
3391 ui.write("%s\n" % c)
3391 ui.write("%s\n" % c)
3392
3392
3393 @command('debugsetparents', [], _('REV1 [REV2]'))
3393 @command('debugsetparents', [], _('REV1 [REV2]'))
3394 def debugsetparents(ui, repo, rev1, rev2=None):
3394 def debugsetparents(ui, repo, rev1, rev2=None):
3395 """manually set the parents of the current working directory
3395 """manually set the parents of the current working directory
3396
3396
3397 This is useful for writing repository conversion tools, but should
3397 This is useful for writing repository conversion tools, but should
3398 be used with care. For example, neither the working directory nor the
3398 be used with care. For example, neither the working directory nor the
3399 dirstate is updated, so file status may be incorrect after running this
3399 dirstate is updated, so file status may be incorrect after running this
3400 command.
3400 command.
3401
3401
3402 Returns 0 on success.
3402 Returns 0 on success.
3403 """
3403 """
3404
3404
3405 r1 = scmutil.revsingle(repo, rev1).node()
3405 r1 = scmutil.revsingle(repo, rev1).node()
3406 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3406 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3407
3407
3408 with repo.wlock():
3408 with repo.wlock():
3409 repo.dirstate.beginparentchange()
3409 repo.dirstate.beginparentchange()
3410 repo.setparents(r1, r2)
3410 repo.setparents(r1, r2)
3411 repo.dirstate.endparentchange()
3411 repo.dirstate.endparentchange()
3412
3412
3413 @command('debugdirstate|debugstate',
3413 @command('debugdirstate|debugstate',
3414 [('', 'nodates', None, _('do not display the saved mtime')),
3414 [('', 'nodates', None, _('do not display the saved mtime')),
3415 ('', 'datesort', None, _('sort by saved mtime'))],
3415 ('', 'datesort', None, _('sort by saved mtime'))],
3416 _('[OPTION]...'))
3416 _('[OPTION]...'))
3417 def debugstate(ui, repo, **opts):
3417 def debugstate(ui, repo, **opts):
3418 """show the contents of the current dirstate"""
3418 """show the contents of the current dirstate"""
3419
3419
3420 nodates = opts.get('nodates')
3420 nodates = opts.get('nodates')
3421 datesort = opts.get('datesort')
3421 datesort = opts.get('datesort')
3422
3422
3423 timestr = ""
3423 timestr = ""
3424 if datesort:
3424 if datesort:
3425 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
3425 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
3426 else:
3426 else:
3427 keyfunc = None # sort by filename
3427 keyfunc = None # sort by filename
3428 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3428 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3429 if ent[3] == -1:
3429 if ent[3] == -1:
3430 timestr = 'unset '
3430 timestr = 'unset '
3431 elif nodates:
3431 elif nodates:
3432 timestr = 'set '
3432 timestr = 'set '
3433 else:
3433 else:
3434 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3434 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3435 time.localtime(ent[3]))
3435 time.localtime(ent[3]))
3436 if ent[1] & 0o20000:
3436 if ent[1] & 0o20000:
3437 mode = 'lnk'
3437 mode = 'lnk'
3438 else:
3438 else:
3439 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3439 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3440 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
3440 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
3441 for f in repo.dirstate.copies():
3441 for f in repo.dirstate.copies():
3442 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3442 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3443
3443
3444 @command('debugsub',
3444 @command('debugsub',
3445 [('r', 'rev', '',
3445 [('r', 'rev', '',
3446 _('revision to check'), _('REV'))],
3446 _('revision to check'), _('REV'))],
3447 _('[-r REV] [REV]'))
3447 _('[-r REV] [REV]'))
3448 def debugsub(ui, repo, rev=None):
3448 def debugsub(ui, repo, rev=None):
3449 ctx = scmutil.revsingle(repo, rev, None)
3449 ctx = scmutil.revsingle(repo, rev, None)
3450 for k, v in sorted(ctx.substate.items()):
3450 for k, v in sorted(ctx.substate.items()):
3451 ui.write(('path %s\n') % k)
3451 ui.write(('path %s\n') % k)
3452 ui.write((' source %s\n') % v[0])
3452 ui.write((' source %s\n') % v[0])
3453 ui.write((' revision %s\n') % v[1])
3453 ui.write((' revision %s\n') % v[1])
3454
3454
3455 @command('debugsuccessorssets',
3455 @command('debugsuccessorssets',
3456 [],
3456 [],
3457 _('[REV]'))
3457 _('[REV]'))
3458 def debugsuccessorssets(ui, repo, *revs):
3458 def debugsuccessorssets(ui, repo, *revs):
3459 """show set of successors for revision
3459 """show set of successors for revision
3460
3460
3461 A successors set of changeset A is a consistent group of revisions that
3461 A successors set of changeset A is a consistent group of revisions that
3462 succeed A. It contains non-obsolete changesets only.
3462 succeed A. It contains non-obsolete changesets only.
3463
3463
3464 In most cases a changeset A has a single successors set containing a single
3464 In most cases a changeset A has a single successors set containing a single
3465 successor (changeset A replaced by A').
3465 successor (changeset A replaced by A').
3466
3466
3467 A changeset that is made obsolete with no successors are called "pruned".
3467 A changeset that is made obsolete with no successors are called "pruned".
3468 Such changesets have no successors sets at all.
3468 Such changesets have no successors sets at all.
3469
3469
3470 A changeset that has been "split" will have a successors set containing
3470 A changeset that has been "split" will have a successors set containing
3471 more than one successor.
3471 more than one successor.
3472
3472
3473 A changeset that has been rewritten in multiple different ways is called
3473 A changeset that has been rewritten in multiple different ways is called
3474 "divergent". Such changesets have multiple successor sets (each of which
3474 "divergent". Such changesets have multiple successor sets (each of which
3475 may also be split, i.e. have multiple successors).
3475 may also be split, i.e. have multiple successors).
3476
3476
3477 Results are displayed as follows::
3477 Results are displayed as follows::
3478
3478
3479 <rev1>
3479 <rev1>
3480 <successors-1A>
3480 <successors-1A>
3481 <rev2>
3481 <rev2>
3482 <successors-2A>
3482 <successors-2A>
3483 <successors-2B1> <successors-2B2> <successors-2B3>
3483 <successors-2B1> <successors-2B2> <successors-2B3>
3484
3484
3485 Here rev2 has two possible (i.e. divergent) successors sets. The first
3485 Here rev2 has two possible (i.e. divergent) successors sets. The first
3486 holds one element, whereas the second holds three (i.e. the changeset has
3486 holds one element, whereas the second holds three (i.e. the changeset has
3487 been split).
3487 been split).
3488 """
3488 """
3489 # passed to successorssets caching computation from one call to another
3489 # passed to successorssets caching computation from one call to another
3490 cache = {}
3490 cache = {}
3491 ctx2str = str
3491 ctx2str = str
3492 node2str = short
3492 node2str = short
3493 if ui.debug():
3493 if ui.debug():
3494 def ctx2str(ctx):
3494 def ctx2str(ctx):
3495 return ctx.hex()
3495 return ctx.hex()
3496 node2str = hex
3496 node2str = hex
3497 for rev in scmutil.revrange(repo, revs):
3497 for rev in scmutil.revrange(repo, revs):
3498 ctx = repo[rev]
3498 ctx = repo[rev]
3499 ui.write('%s\n'% ctx2str(ctx))
3499 ui.write('%s\n'% ctx2str(ctx))
3500 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3500 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3501 if succsset:
3501 if succsset:
3502 ui.write(' ')
3502 ui.write(' ')
3503 ui.write(node2str(succsset[0]))
3503 ui.write(node2str(succsset[0]))
3504 for node in succsset[1:]:
3504 for node in succsset[1:]:
3505 ui.write(' ')
3505 ui.write(' ')
3506 ui.write(node2str(node))
3506 ui.write(node2str(node))
3507 ui.write('\n')
3507 ui.write('\n')
3508
3508
3509 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3509 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3510 def debugwalk(ui, repo, *pats, **opts):
3510 def debugwalk(ui, repo, *pats, **opts):
3511 """show how files match on given patterns"""
3511 """show how files match on given patterns"""
3512 m = scmutil.match(repo[None], pats, opts)
3512 m = scmutil.match(repo[None], pats, opts)
3513 items = list(repo.walk(m))
3513 items = list(repo.walk(m))
3514 if not items:
3514 if not items:
3515 return
3515 return
3516 f = lambda fn: fn
3516 f = lambda fn: fn
3517 if ui.configbool('ui', 'slash') and os.sep != '/':
3517 if ui.configbool('ui', 'slash') and os.sep != '/':
3518 f = lambda fn: util.normpath(fn)
3518 f = lambda fn: util.normpath(fn)
3519 fmt = 'f %%-%ds %%-%ds %%s' % (
3519 fmt = 'f %%-%ds %%-%ds %%s' % (
3520 max([len(abs) for abs in items]),
3520 max([len(abs) for abs in items]),
3521 max([len(m.rel(abs)) for abs in items]))
3521 max([len(m.rel(abs)) for abs in items]))
3522 for abs in items:
3522 for abs in items:
3523 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3523 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3524 ui.write("%s\n" % line.rstrip())
3524 ui.write("%s\n" % line.rstrip())
3525
3525
3526 @command('debugwireargs',
3526 @command('debugwireargs',
3527 [('', 'three', '', 'three'),
3527 [('', 'three', '', 'three'),
3528 ('', 'four', '', 'four'),
3528 ('', 'four', '', 'four'),
3529 ('', 'five', '', 'five'),
3529 ('', 'five', '', 'five'),
3530 ] + remoteopts,
3530 ] + remoteopts,
3531 _('REPO [OPTIONS]... [ONE [TWO]]'),
3531 _('REPO [OPTIONS]... [ONE [TWO]]'),
3532 norepo=True)
3532 norepo=True)
3533 def debugwireargs(ui, repopath, *vals, **opts):
3533 def debugwireargs(ui, repopath, *vals, **opts):
3534 repo = hg.peer(ui, opts, repopath)
3534 repo = hg.peer(ui, opts, repopath)
3535 for opt in remoteopts:
3535 for opt in remoteopts:
3536 del opts[opt[1]]
3536 del opts[opt[1]]
3537 args = {}
3537 args = {}
3538 for k, v in opts.iteritems():
3538 for k, v in opts.iteritems():
3539 if v:
3539 if v:
3540 args[k] = v
3540 args[k] = v
3541 # run twice to check that we don't mess up the stream for the next command
3541 # run twice to check that we don't mess up the stream for the next command
3542 res1 = repo.debugwireargs(*vals, **args)
3542 res1 = repo.debugwireargs(*vals, **args)
3543 res2 = repo.debugwireargs(*vals, **args)
3543 res2 = repo.debugwireargs(*vals, **args)
3544 ui.write("%s\n" % res1)
3544 ui.write("%s\n" % res1)
3545 if res1 != res2:
3545 if res1 != res2:
3546 ui.warn("%s\n" % res2)
3546 ui.warn("%s\n" % res2)
3547
3547
3548 @command('^diff',
3548 @command('^diff',
3549 [('r', 'rev', [], _('revision'), _('REV')),
3549 [('r', 'rev', [], _('revision'), _('REV')),
3550 ('c', 'change', '', _('change made by revision'), _('REV'))
3550 ('c', 'change', '', _('change made by revision'), _('REV'))
3551 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3551 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3552 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3552 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3553 inferrepo=True)
3553 inferrepo=True)
3554 def diff(ui, repo, *pats, **opts):
3554 def diff(ui, repo, *pats, **opts):
3555 """diff repository (or selected files)
3555 """diff repository (or selected files)
3556
3556
3557 Show differences between revisions for the specified files.
3557 Show differences between revisions for the specified files.
3558
3558
3559 Differences between files are shown using the unified diff format.
3559 Differences between files are shown using the unified diff format.
3560
3560
3561 .. note::
3561 .. note::
3562
3562
3563 :hg:`diff` may generate unexpected results for merges, as it will
3563 :hg:`diff` may generate unexpected results for merges, as it will
3564 default to comparing against the working directory's first
3564 default to comparing against the working directory's first
3565 parent changeset if no revisions are specified.
3565 parent changeset if no revisions are specified.
3566
3566
3567 When two revision arguments are given, then changes are shown
3567 When two revision arguments are given, then changes are shown
3568 between those revisions. If only one revision is specified then
3568 between those revisions. If only one revision is specified then
3569 that revision is compared to the working directory, and, when no
3569 that revision is compared to the working directory, and, when no
3570 revisions are specified, the working directory files are compared
3570 revisions are specified, the working directory files are compared
3571 to its first parent.
3571 to its first parent.
3572
3572
3573 Alternatively you can specify -c/--change with a revision to see
3573 Alternatively you can specify -c/--change with a revision to see
3574 the changes in that changeset relative to its first parent.
3574 the changes in that changeset relative to its first parent.
3575
3575
3576 Without the -a/--text option, diff will avoid generating diffs of
3576 Without the -a/--text option, diff will avoid generating diffs of
3577 files it detects as binary. With -a, diff will generate a diff
3577 files it detects as binary. With -a, diff will generate a diff
3578 anyway, probably with undesirable results.
3578 anyway, probably with undesirable results.
3579
3579
3580 Use the -g/--git option to generate diffs in the git extended diff
3580 Use the -g/--git option to generate diffs in the git extended diff
3581 format. For more information, read :hg:`help diffs`.
3581 format. For more information, read :hg:`help diffs`.
3582
3582
3583 .. container:: verbose
3583 .. container:: verbose
3584
3584
3585 Examples:
3585 Examples:
3586
3586
3587 - compare a file in the current working directory to its parent::
3587 - compare a file in the current working directory to its parent::
3588
3588
3589 hg diff foo.c
3589 hg diff foo.c
3590
3590
3591 - compare two historical versions of a directory, with rename info::
3591 - compare two historical versions of a directory, with rename info::
3592
3592
3593 hg diff --git -r 1.0:1.2 lib/
3593 hg diff --git -r 1.0:1.2 lib/
3594
3594
3595 - get change stats relative to the last change on some date::
3595 - get change stats relative to the last change on some date::
3596
3596
3597 hg diff --stat -r "date('may 2')"
3597 hg diff --stat -r "date('may 2')"
3598
3598
3599 - diff all newly-added files that contain a keyword::
3599 - diff all newly-added files that contain a keyword::
3600
3600
3601 hg diff "set:added() and grep(GNU)"
3601 hg diff "set:added() and grep(GNU)"
3602
3602
3603 - compare a revision and its parents::
3603 - compare a revision and its parents::
3604
3604
3605 hg diff -c 9353 # compare against first parent
3605 hg diff -c 9353 # compare against first parent
3606 hg diff -r 9353^:9353 # same using revset syntax
3606 hg diff -r 9353^:9353 # same using revset syntax
3607 hg diff -r 9353^2:9353 # compare against the second parent
3607 hg diff -r 9353^2:9353 # compare against the second parent
3608
3608
3609 Returns 0 on success.
3609 Returns 0 on success.
3610 """
3610 """
3611
3611
3612 revs = opts.get('rev')
3612 revs = opts.get('rev')
3613 change = opts.get('change')
3613 change = opts.get('change')
3614 stat = opts.get('stat')
3614 stat = opts.get('stat')
3615 reverse = opts.get('reverse')
3615 reverse = opts.get('reverse')
3616
3616
3617 if revs and change:
3617 if revs and change:
3618 msg = _('cannot specify --rev and --change at the same time')
3618 msg = _('cannot specify --rev and --change at the same time')
3619 raise error.Abort(msg)
3619 raise error.Abort(msg)
3620 elif change:
3620 elif change:
3621 node2 = scmutil.revsingle(repo, change, None).node()
3621 node2 = scmutil.revsingle(repo, change, None).node()
3622 node1 = repo[node2].p1().node()
3622 node1 = repo[node2].p1().node()
3623 else:
3623 else:
3624 node1, node2 = scmutil.revpair(repo, revs)
3624 node1, node2 = scmutil.revpair(repo, revs)
3625
3625
3626 if reverse:
3626 if reverse:
3627 node1, node2 = node2, node1
3627 node1, node2 = node2, node1
3628
3628
3629 diffopts = patch.diffallopts(ui, opts)
3629 diffopts = patch.diffallopts(ui, opts)
3630 m = scmutil.match(repo[node2], pats, opts)
3630 m = scmutil.match(repo[node2], pats, opts)
3631 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3631 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3632 listsubrepos=opts.get('subrepos'),
3632 listsubrepos=opts.get('subrepos'),
3633 root=opts.get('root'))
3633 root=opts.get('root'))
3634
3634
3635 @command('^export',
3635 @command('^export',
3636 [('o', 'output', '',
3636 [('o', 'output', '',
3637 _('print output to file with formatted name'), _('FORMAT')),
3637 _('print output to file with formatted name'), _('FORMAT')),
3638 ('', 'switch-parent', None, _('diff against the second parent')),
3638 ('', 'switch-parent', None, _('diff against the second parent')),
3639 ('r', 'rev', [], _('revisions to export'), _('REV')),
3639 ('r', 'rev', [], _('revisions to export'), _('REV')),
3640 ] + diffopts,
3640 ] + diffopts,
3641 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3641 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3642 def export(ui, repo, *changesets, **opts):
3642 def export(ui, repo, *changesets, **opts):
3643 """dump the header and diffs for one or more changesets
3643 """dump the header and diffs for one or more changesets
3644
3644
3645 Print the changeset header and diffs for one or more revisions.
3645 Print the changeset header and diffs for one or more revisions.
3646 If no revision is given, the parent of the working directory is used.
3646 If no revision is given, the parent of the working directory is used.
3647
3647
3648 The information shown in the changeset header is: author, date,
3648 The information shown in the changeset header is: author, date,
3649 branch name (if non-default), changeset hash, parent(s) and commit
3649 branch name (if non-default), changeset hash, parent(s) and commit
3650 comment.
3650 comment.
3651
3651
3652 .. note::
3652 .. note::
3653
3653
3654 :hg:`export` may generate unexpected diff output for merge
3654 :hg:`export` may generate unexpected diff output for merge
3655 changesets, as it will compare the merge changeset against its
3655 changesets, as it will compare the merge changeset against its
3656 first parent only.
3656 first parent only.
3657
3657
3658 Output may be to a file, in which case the name of the file is
3658 Output may be to a file, in which case the name of the file is
3659 given using a format string. The formatting rules are as follows:
3659 given using a format string. The formatting rules are as follows:
3660
3660
3661 :``%%``: literal "%" character
3661 :``%%``: literal "%" character
3662 :``%H``: changeset hash (40 hexadecimal digits)
3662 :``%H``: changeset hash (40 hexadecimal digits)
3663 :``%N``: number of patches being generated
3663 :``%N``: number of patches being generated
3664 :``%R``: changeset revision number
3664 :``%R``: changeset revision number
3665 :``%b``: basename of the exporting repository
3665 :``%b``: basename of the exporting repository
3666 :``%h``: short-form changeset hash (12 hexadecimal digits)
3666 :``%h``: short-form changeset hash (12 hexadecimal digits)
3667 :``%m``: first line of the commit message (only alphanumeric characters)
3667 :``%m``: first line of the commit message (only alphanumeric characters)
3668 :``%n``: zero-padded sequence number, starting at 1
3668 :``%n``: zero-padded sequence number, starting at 1
3669 :``%r``: zero-padded changeset revision number
3669 :``%r``: zero-padded changeset revision number
3670
3670
3671 Without the -a/--text option, export will avoid generating diffs
3671 Without the -a/--text option, export will avoid generating diffs
3672 of files it detects as binary. With -a, export will generate a
3672 of files it detects as binary. With -a, export will generate a
3673 diff anyway, probably with undesirable results.
3673 diff anyway, probably with undesirable results.
3674
3674
3675 Use the -g/--git option to generate diffs in the git extended diff
3675 Use the -g/--git option to generate diffs in the git extended diff
3676 format. See :hg:`help diffs` for more information.
3676 format. See :hg:`help diffs` for more information.
3677
3677
3678 With the --switch-parent option, the diff will be against the
3678 With the --switch-parent option, the diff will be against the
3679 second parent. It can be useful to review a merge.
3679 second parent. It can be useful to review a merge.
3680
3680
3681 .. container:: verbose
3681 .. container:: verbose
3682
3682
3683 Examples:
3683 Examples:
3684
3684
3685 - use export and import to transplant a bugfix to the current
3685 - use export and import to transplant a bugfix to the current
3686 branch::
3686 branch::
3687
3687
3688 hg export -r 9353 | hg import -
3688 hg export -r 9353 | hg import -
3689
3689
3690 - export all the changesets between two revisions to a file with
3690 - export all the changesets between two revisions to a file with
3691 rename information::
3691 rename information::
3692
3692
3693 hg export --git -r 123:150 > changes.txt
3693 hg export --git -r 123:150 > changes.txt
3694
3694
3695 - split outgoing changes into a series of patches with
3695 - split outgoing changes into a series of patches with
3696 descriptive names::
3696 descriptive names::
3697
3697
3698 hg export -r "outgoing()" -o "%n-%m.patch"
3698 hg export -r "outgoing()" -o "%n-%m.patch"
3699
3699
3700 Returns 0 on success.
3700 Returns 0 on success.
3701 """
3701 """
3702 changesets += tuple(opts.get('rev', []))
3702 changesets += tuple(opts.get('rev', []))
3703 if not changesets:
3703 if not changesets:
3704 changesets = ['.']
3704 changesets = ['.']
3705 revs = scmutil.revrange(repo, changesets)
3705 revs = scmutil.revrange(repo, changesets)
3706 if not revs:
3706 if not revs:
3707 raise error.Abort(_("export requires at least one changeset"))
3707 raise error.Abort(_("export requires at least one changeset"))
3708 if len(revs) > 1:
3708 if len(revs) > 1:
3709 ui.note(_('exporting patches:\n'))
3709 ui.note(_('exporting patches:\n'))
3710 else:
3710 else:
3711 ui.note(_('exporting patch:\n'))
3711 ui.note(_('exporting patch:\n'))
3712 cmdutil.export(repo, revs, template=opts.get('output'),
3712 cmdutil.export(repo, revs, template=opts.get('output'),
3713 switch_parent=opts.get('switch_parent'),
3713 switch_parent=opts.get('switch_parent'),
3714 opts=patch.diffallopts(ui, opts))
3714 opts=patch.diffallopts(ui, opts))
3715
3715
3716 @command('files',
3716 @command('files',
3717 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3717 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3718 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3718 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3719 ] + walkopts + formatteropts + subrepoopts,
3719 ] + walkopts + formatteropts + subrepoopts,
3720 _('[OPTION]... [PATTERN]...'))
3720 _('[OPTION]... [PATTERN]...'))
3721 def files(ui, repo, *pats, **opts):
3721 def files(ui, repo, *pats, **opts):
3722 """list tracked files
3722 """list tracked files
3723
3723
3724 Print files under Mercurial control in the working directory or
3724 Print files under Mercurial control in the working directory or
3725 specified revision whose names match the given patterns (excluding
3725 specified revision whose names match the given patterns (excluding
3726 removed files).
3726 removed files).
3727
3727
3728 If no patterns are given to match, this command prints the names
3728 If no patterns are given to match, this command prints the names
3729 of all files under Mercurial control in the working directory.
3729 of all files under Mercurial control in the working directory.
3730
3730
3731 .. container:: verbose
3731 .. container:: verbose
3732
3732
3733 Examples:
3733 Examples:
3734
3734
3735 - list all files under the current directory::
3735 - list all files under the current directory::
3736
3736
3737 hg files .
3737 hg files .
3738
3738
3739 - shows sizes and flags for current revision::
3739 - shows sizes and flags for current revision::
3740
3740
3741 hg files -vr .
3741 hg files -vr .
3742
3742
3743 - list all files named README::
3743 - list all files named README::
3744
3744
3745 hg files -I "**/README"
3745 hg files -I "**/README"
3746
3746
3747 - list all binary files::
3747 - list all binary files::
3748
3748
3749 hg files "set:binary()"
3749 hg files "set:binary()"
3750
3750
3751 - find files containing a regular expression::
3751 - find files containing a regular expression::
3752
3752
3753 hg files "set:grep('bob')"
3753 hg files "set:grep('bob')"
3754
3754
3755 - search tracked file contents with xargs and grep::
3755 - search tracked file contents with xargs and grep::
3756
3756
3757 hg files -0 | xargs -0 grep foo
3757 hg files -0 | xargs -0 grep foo
3758
3758
3759 See :hg:`help patterns` and :hg:`help filesets` for more information
3759 See :hg:`help patterns` and :hg:`help filesets` for more information
3760 on specifying file patterns.
3760 on specifying file patterns.
3761
3761
3762 Returns 0 if a match is found, 1 otherwise.
3762 Returns 0 if a match is found, 1 otherwise.
3763
3763
3764 """
3764 """
3765 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3765 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3766
3766
3767 end = '\n'
3767 end = '\n'
3768 if opts.get('print0'):
3768 if opts.get('print0'):
3769 end = '\0'
3769 end = '\0'
3770 fm = ui.formatter('files', opts)
3770 fm = ui.formatter('files', opts)
3771 fmt = '%s' + end
3771 fmt = '%s' + end
3772
3772
3773 m = scmutil.match(ctx, pats, opts)
3773 m = scmutil.match(ctx, pats, opts)
3774 ret = cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3774 ret = cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3775
3775
3776 fm.end()
3776 fm.end()
3777
3777
3778 return ret
3778 return ret
3779
3779
3780 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3780 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3781 def forget(ui, repo, *pats, **opts):
3781 def forget(ui, repo, *pats, **opts):
3782 """forget the specified files on the next commit
3782 """forget the specified files on the next commit
3783
3783
3784 Mark the specified files so they will no longer be tracked
3784 Mark the specified files so they will no longer be tracked
3785 after the next commit.
3785 after the next commit.
3786
3786
3787 This only removes files from the current branch, not from the
3787 This only removes files from the current branch, not from the
3788 entire project history, and it does not delete them from the
3788 entire project history, and it does not delete them from the
3789 working directory.
3789 working directory.
3790
3790
3791 To delete the file from the working directory, see :hg:`remove`.
3791 To delete the file from the working directory, see :hg:`remove`.
3792
3792
3793 To undo a forget before the next commit, see :hg:`add`.
3793 To undo a forget before the next commit, see :hg:`add`.
3794
3794
3795 .. container:: verbose
3795 .. container:: verbose
3796
3796
3797 Examples:
3797 Examples:
3798
3798
3799 - forget newly-added binary files::
3799 - forget newly-added binary files::
3800
3800
3801 hg forget "set:added() and binary()"
3801 hg forget "set:added() and binary()"
3802
3802
3803 - forget files that would be excluded by .hgignore::
3803 - forget files that would be excluded by .hgignore::
3804
3804
3805 hg forget "set:hgignore()"
3805 hg forget "set:hgignore()"
3806
3806
3807 Returns 0 on success.
3807 Returns 0 on success.
3808 """
3808 """
3809
3809
3810 if not pats:
3810 if not pats:
3811 raise error.Abort(_('no files specified'))
3811 raise error.Abort(_('no files specified'))
3812
3812
3813 m = scmutil.match(repo[None], pats, opts)
3813 m = scmutil.match(repo[None], pats, opts)
3814 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3814 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3815 return rejected and 1 or 0
3815 return rejected and 1 or 0
3816
3816
3817 @command(
3817 @command(
3818 'graft',
3818 'graft',
3819 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3819 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3820 ('c', 'continue', False, _('resume interrupted graft')),
3820 ('c', 'continue', False, _('resume interrupted graft')),
3821 ('e', 'edit', False, _('invoke editor on commit messages')),
3821 ('e', 'edit', False, _('invoke editor on commit messages')),
3822 ('', 'log', None, _('append graft info to log message')),
3822 ('', 'log', None, _('append graft info to log message')),
3823 ('f', 'force', False, _('force graft')),
3823 ('f', 'force', False, _('force graft')),
3824 ('D', 'currentdate', False,
3824 ('D', 'currentdate', False,
3825 _('record the current date as commit date')),
3825 _('record the current date as commit date')),
3826 ('U', 'currentuser', False,
3826 ('U', 'currentuser', False,
3827 _('record the current user as committer'), _('DATE'))]
3827 _('record the current user as committer'), _('DATE'))]
3828 + commitopts2 + mergetoolopts + dryrunopts,
3828 + commitopts2 + mergetoolopts + dryrunopts,
3829 _('[OPTION]... [-r REV]... REV...'))
3829 _('[OPTION]... [-r REV]... REV...'))
3830 def graft(ui, repo, *revs, **opts):
3830 def graft(ui, repo, *revs, **opts):
3831 '''copy changes from other branches onto the current branch
3831 '''copy changes from other branches onto the current branch
3832
3832
3833 This command uses Mercurial's merge logic to copy individual
3833 This command uses Mercurial's merge logic to copy individual
3834 changes from other branches without merging branches in the
3834 changes from other branches without merging branches in the
3835 history graph. This is sometimes known as 'backporting' or
3835 history graph. This is sometimes known as 'backporting' or
3836 'cherry-picking'. By default, graft will copy user, date, and
3836 'cherry-picking'. By default, graft will copy user, date, and
3837 description from the source changesets.
3837 description from the source changesets.
3838
3838
3839 Changesets that are ancestors of the current revision, that have
3839 Changesets that are ancestors of the current revision, that have
3840 already been grafted, or that are merges will be skipped.
3840 already been grafted, or that are merges will be skipped.
3841
3841
3842 If --log is specified, log messages will have a comment appended
3842 If --log is specified, log messages will have a comment appended
3843 of the form::
3843 of the form::
3844
3844
3845 (grafted from CHANGESETHASH)
3845 (grafted from CHANGESETHASH)
3846
3846
3847 If --force is specified, revisions will be grafted even if they
3847 If --force is specified, revisions will be grafted even if they
3848 are already ancestors of or have been grafted to the destination.
3848 are already ancestors of or have been grafted to the destination.
3849 This is useful when the revisions have since been backed out.
3849 This is useful when the revisions have since been backed out.
3850
3850
3851 If a graft merge results in conflicts, the graft process is
3851 If a graft merge results in conflicts, the graft process is
3852 interrupted so that the current merge can be manually resolved.
3852 interrupted so that the current merge can be manually resolved.
3853 Once all conflicts are addressed, the graft process can be
3853 Once all conflicts are addressed, the graft process can be
3854 continued with the -c/--continue option.
3854 continued with the -c/--continue option.
3855
3855
3856 .. note::
3856 .. note::
3857
3857
3858 The -c/--continue option does not reapply earlier options, except
3858 The -c/--continue option does not reapply earlier options, except
3859 for --force.
3859 for --force.
3860
3860
3861 .. container:: verbose
3861 .. container:: verbose
3862
3862
3863 Examples:
3863 Examples:
3864
3864
3865 - copy a single change to the stable branch and edit its description::
3865 - copy a single change to the stable branch and edit its description::
3866
3866
3867 hg update stable
3867 hg update stable
3868 hg graft --edit 9393
3868 hg graft --edit 9393
3869
3869
3870 - graft a range of changesets with one exception, updating dates::
3870 - graft a range of changesets with one exception, updating dates::
3871
3871
3872 hg graft -D "2085::2093 and not 2091"
3872 hg graft -D "2085::2093 and not 2091"
3873
3873
3874 - continue a graft after resolving conflicts::
3874 - continue a graft after resolving conflicts::
3875
3875
3876 hg graft -c
3876 hg graft -c
3877
3877
3878 - show the source of a grafted changeset::
3878 - show the source of a grafted changeset::
3879
3879
3880 hg log --debug -r .
3880 hg log --debug -r .
3881
3881
3882 - show revisions sorted by date::
3882 - show revisions sorted by date::
3883
3883
3884 hg log -r 'sort(all(), date)'
3884 hg log -r 'sort(all(), date)'
3885
3885
3886 See :hg:`help revisions` and :hg:`help revsets` for more about
3886 See :hg:`help revisions` and :hg:`help revsets` for more about
3887 specifying revisions.
3887 specifying revisions.
3888
3888
3889 Returns 0 on successful completion.
3889 Returns 0 on successful completion.
3890 '''
3890 '''
3891 with repo.wlock():
3891 with repo.wlock():
3892 return _dograft(ui, repo, *revs, **opts)
3892 return _dograft(ui, repo, *revs, **opts)
3893
3893
3894 def _dograft(ui, repo, *revs, **opts):
3894 def _dograft(ui, repo, *revs, **opts):
3895 if revs and opts['rev']:
3895 if revs and opts['rev']:
3896 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
3896 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
3897 'revision ordering!\n'))
3897 'revision ordering!\n'))
3898
3898
3899 revs = list(revs)
3899 revs = list(revs)
3900 revs.extend(opts['rev'])
3900 revs.extend(opts['rev'])
3901
3901
3902 if not opts.get('user') and opts.get('currentuser'):
3902 if not opts.get('user') and opts.get('currentuser'):
3903 opts['user'] = ui.username()
3903 opts['user'] = ui.username()
3904 if not opts.get('date') and opts.get('currentdate'):
3904 if not opts.get('date') and opts.get('currentdate'):
3905 opts['date'] = "%d %d" % util.makedate()
3905 opts['date'] = "%d %d" % util.makedate()
3906
3906
3907 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3907 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3908
3908
3909 cont = False
3909 cont = False
3910 if opts['continue']:
3910 if opts['continue']:
3911 cont = True
3911 cont = True
3912 if revs:
3912 if revs:
3913 raise error.Abort(_("can't specify --continue and revisions"))
3913 raise error.Abort(_("can't specify --continue and revisions"))
3914 # read in unfinished revisions
3914 # read in unfinished revisions
3915 try:
3915 try:
3916 nodes = repo.vfs.read('graftstate').splitlines()
3916 nodes = repo.vfs.read('graftstate').splitlines()
3917 revs = [repo[node].rev() for node in nodes]
3917 revs = [repo[node].rev() for node in nodes]
3918 except IOError as inst:
3918 except IOError as inst:
3919 if inst.errno != errno.ENOENT:
3919 if inst.errno != errno.ENOENT:
3920 raise
3920 raise
3921 raise error.Abort(_("no graft state found, can't continue"))
3921 raise error.Abort(_("no graft state found, can't continue"))
3922 else:
3922 else:
3923 cmdutil.checkunfinished(repo)
3923 cmdutil.checkunfinished(repo)
3924 cmdutil.bailifchanged(repo)
3924 cmdutil.bailifchanged(repo)
3925 if not revs:
3925 if not revs:
3926 raise error.Abort(_('no revisions specified'))
3926 raise error.Abort(_('no revisions specified'))
3927 revs = scmutil.revrange(repo, revs)
3927 revs = scmutil.revrange(repo, revs)
3928
3928
3929 skipped = set()
3929 skipped = set()
3930 # check for merges
3930 # check for merges
3931 for rev in repo.revs('%ld and merge()', revs):
3931 for rev in repo.revs('%ld and merge()', revs):
3932 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3932 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3933 skipped.add(rev)
3933 skipped.add(rev)
3934 revs = [r for r in revs if r not in skipped]
3934 revs = [r for r in revs if r not in skipped]
3935 if not revs:
3935 if not revs:
3936 return -1
3936 return -1
3937
3937
3938 # Don't check in the --continue case, in effect retaining --force across
3938 # Don't check in the --continue case, in effect retaining --force across
3939 # --continues. That's because without --force, any revisions we decided to
3939 # --continues. That's because without --force, any revisions we decided to
3940 # skip would have been filtered out here, so they wouldn't have made their
3940 # skip would have been filtered out here, so they wouldn't have made their
3941 # way to the graftstate. With --force, any revisions we would have otherwise
3941 # way to the graftstate. With --force, any revisions we would have otherwise
3942 # skipped would not have been filtered out, and if they hadn't been applied
3942 # skipped would not have been filtered out, and if they hadn't been applied
3943 # already, they'd have been in the graftstate.
3943 # already, they'd have been in the graftstate.
3944 if not (cont or opts.get('force')):
3944 if not (cont or opts.get('force')):
3945 # check for ancestors of dest branch
3945 # check for ancestors of dest branch
3946 crev = repo['.'].rev()
3946 crev = repo['.'].rev()
3947 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3947 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3948 # Cannot use x.remove(y) on smart set, this has to be a list.
3948 # Cannot use x.remove(y) on smart set, this has to be a list.
3949 # XXX make this lazy in the future
3949 # XXX make this lazy in the future
3950 revs = list(revs)
3950 revs = list(revs)
3951 # don't mutate while iterating, create a copy
3951 # don't mutate while iterating, create a copy
3952 for rev in list(revs):
3952 for rev in list(revs):
3953 if rev in ancestors:
3953 if rev in ancestors:
3954 ui.warn(_('skipping ancestor revision %d:%s\n') %
3954 ui.warn(_('skipping ancestor revision %d:%s\n') %
3955 (rev, repo[rev]))
3955 (rev, repo[rev]))
3956 # XXX remove on list is slow
3956 # XXX remove on list is slow
3957 revs.remove(rev)
3957 revs.remove(rev)
3958 if not revs:
3958 if not revs:
3959 return -1
3959 return -1
3960
3960
3961 # analyze revs for earlier grafts
3961 # analyze revs for earlier grafts
3962 ids = {}
3962 ids = {}
3963 for ctx in repo.set("%ld", revs):
3963 for ctx in repo.set("%ld", revs):
3964 ids[ctx.hex()] = ctx.rev()
3964 ids[ctx.hex()] = ctx.rev()
3965 n = ctx.extra().get('source')
3965 n = ctx.extra().get('source')
3966 if n:
3966 if n:
3967 ids[n] = ctx.rev()
3967 ids[n] = ctx.rev()
3968
3968
3969 # check ancestors for earlier grafts
3969 # check ancestors for earlier grafts
3970 ui.debug('scanning for duplicate grafts\n')
3970 ui.debug('scanning for duplicate grafts\n')
3971
3971
3972 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3972 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3973 ctx = repo[rev]
3973 ctx = repo[rev]
3974 n = ctx.extra().get('source')
3974 n = ctx.extra().get('source')
3975 if n in ids:
3975 if n in ids:
3976 try:
3976 try:
3977 r = repo[n].rev()
3977 r = repo[n].rev()
3978 except error.RepoLookupError:
3978 except error.RepoLookupError:
3979 r = None
3979 r = None
3980 if r in revs:
3980 if r in revs:
3981 ui.warn(_('skipping revision %d:%s '
3981 ui.warn(_('skipping revision %d:%s '
3982 '(already grafted to %d:%s)\n')
3982 '(already grafted to %d:%s)\n')
3983 % (r, repo[r], rev, ctx))
3983 % (r, repo[r], rev, ctx))
3984 revs.remove(r)
3984 revs.remove(r)
3985 elif ids[n] in revs:
3985 elif ids[n] in revs:
3986 if r is None:
3986 if r is None:
3987 ui.warn(_('skipping already grafted revision %d:%s '
3987 ui.warn(_('skipping already grafted revision %d:%s '
3988 '(%d:%s also has unknown origin %s)\n')
3988 '(%d:%s also has unknown origin %s)\n')
3989 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
3989 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
3990 else:
3990 else:
3991 ui.warn(_('skipping already grafted revision %d:%s '
3991 ui.warn(_('skipping already grafted revision %d:%s '
3992 '(%d:%s also has origin %d:%s)\n')
3992 '(%d:%s also has origin %d:%s)\n')
3993 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
3993 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
3994 revs.remove(ids[n])
3994 revs.remove(ids[n])
3995 elif ctx.hex() in ids:
3995 elif ctx.hex() in ids:
3996 r = ids[ctx.hex()]
3996 r = ids[ctx.hex()]
3997 ui.warn(_('skipping already grafted revision %d:%s '
3997 ui.warn(_('skipping already grafted revision %d:%s '
3998 '(was grafted from %d:%s)\n') %
3998 '(was grafted from %d:%s)\n') %
3999 (r, repo[r], rev, ctx))
3999 (r, repo[r], rev, ctx))
4000 revs.remove(r)
4000 revs.remove(r)
4001 if not revs:
4001 if not revs:
4002 return -1
4002 return -1
4003
4003
4004 for pos, ctx in enumerate(repo.set("%ld", revs)):
4004 for pos, ctx in enumerate(repo.set("%ld", revs)):
4005 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
4005 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
4006 ctx.description().split('\n', 1)[0])
4006 ctx.description().split('\n', 1)[0])
4007 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
4007 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
4008 if names:
4008 if names:
4009 desc += ' (%s)' % ' '.join(names)
4009 desc += ' (%s)' % ' '.join(names)
4010 ui.status(_('grafting %s\n') % desc)
4010 ui.status(_('grafting %s\n') % desc)
4011 if opts.get('dry_run'):
4011 if opts.get('dry_run'):
4012 continue
4012 continue
4013
4013
4014 extra = ctx.extra().copy()
4014 extra = ctx.extra().copy()
4015 del extra['branch']
4015 del extra['branch']
4016 source = extra.get('source')
4016 source = extra.get('source')
4017 if source:
4017 if source:
4018 extra['intermediate-source'] = ctx.hex()
4018 extra['intermediate-source'] = ctx.hex()
4019 else:
4019 else:
4020 extra['source'] = ctx.hex()
4020 extra['source'] = ctx.hex()
4021 user = ctx.user()
4021 user = ctx.user()
4022 if opts.get('user'):
4022 if opts.get('user'):
4023 user = opts['user']
4023 user = opts['user']
4024 date = ctx.date()
4024 date = ctx.date()
4025 if opts.get('date'):
4025 if opts.get('date'):
4026 date = opts['date']
4026 date = opts['date']
4027 message = ctx.description()
4027 message = ctx.description()
4028 if opts.get('log'):
4028 if opts.get('log'):
4029 message += '\n(grafted from %s)' % ctx.hex()
4029 message += '\n(grafted from %s)' % ctx.hex()
4030
4030
4031 # we don't merge the first commit when continuing
4031 # we don't merge the first commit when continuing
4032 if not cont:
4032 if not cont:
4033 # perform the graft merge with p1(rev) as 'ancestor'
4033 # perform the graft merge with p1(rev) as 'ancestor'
4034 try:
4034 try:
4035 # ui.forcemerge is an internal variable, do not document
4035 # ui.forcemerge is an internal variable, do not document
4036 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4036 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4037 'graft')
4037 'graft')
4038 stats = mergemod.graft(repo, ctx, ctx.p1(),
4038 stats = mergemod.graft(repo, ctx, ctx.p1(),
4039 ['local', 'graft'])
4039 ['local', 'graft'])
4040 finally:
4040 finally:
4041 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
4041 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
4042 # report any conflicts
4042 # report any conflicts
4043 if stats and stats[3] > 0:
4043 if stats and stats[3] > 0:
4044 # write out state for --continue
4044 # write out state for --continue
4045 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
4045 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
4046 repo.vfs.write('graftstate', ''.join(nodelines))
4046 repo.vfs.write('graftstate', ''.join(nodelines))
4047 extra = ''
4047 extra = ''
4048 if opts.get('user'):
4048 if opts.get('user'):
4049 extra += ' --user %s' % opts['user']
4049 extra += ' --user %s' % opts['user']
4050 if opts.get('date'):
4050 if opts.get('date'):
4051 extra += ' --date %s' % opts['date']
4051 extra += ' --date %s' % opts['date']
4052 if opts.get('log'):
4052 if opts.get('log'):
4053 extra += ' --log'
4053 extra += ' --log'
4054 hint=_('use hg resolve and hg graft --continue%s') % extra
4054 hint=_('use hg resolve and hg graft --continue%s') % extra
4055 raise error.Abort(
4055 raise error.Abort(
4056 _("unresolved conflicts, can't continue"),
4056 _("unresolved conflicts, can't continue"),
4057 hint=hint)
4057 hint=hint)
4058 else:
4058 else:
4059 cont = False
4059 cont = False
4060
4060
4061 # commit
4061 # commit
4062 node = repo.commit(text=message, user=user,
4062 node = repo.commit(text=message, user=user,
4063 date=date, extra=extra, editor=editor)
4063 date=date, extra=extra, editor=editor)
4064 if node is None:
4064 if node is None:
4065 ui.warn(
4065 ui.warn(
4066 _('note: graft of %d:%s created no changes to commit\n') %
4066 _('note: graft of %d:%s created no changes to commit\n') %
4067 (ctx.rev(), ctx))
4067 (ctx.rev(), ctx))
4068
4068
4069 # remove state when we complete successfully
4069 # remove state when we complete successfully
4070 if not opts.get('dry_run'):
4070 if not opts.get('dry_run'):
4071 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
4071 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
4072
4072
4073 return 0
4073 return 0
4074
4074
4075 @command('grep',
4075 @command('grep',
4076 [('0', 'print0', None, _('end fields with NUL')),
4076 [('0', 'print0', None, _('end fields with NUL')),
4077 ('', 'all', None, _('print all revisions that match')),
4077 ('', 'all', None, _('print all revisions that match')),
4078 ('a', 'text', None, _('treat all files as text')),
4078 ('a', 'text', None, _('treat all files as text')),
4079 ('f', 'follow', None,
4079 ('f', 'follow', None,
4080 _('follow changeset history,'
4080 _('follow changeset history,'
4081 ' or file history across copies and renames')),
4081 ' or file history across copies and renames')),
4082 ('i', 'ignore-case', None, _('ignore case when matching')),
4082 ('i', 'ignore-case', None, _('ignore case when matching')),
4083 ('l', 'files-with-matches', None,
4083 ('l', 'files-with-matches', None,
4084 _('print only filenames and revisions that match')),
4084 _('print only filenames and revisions that match')),
4085 ('n', 'line-number', None, _('print matching line numbers')),
4085 ('n', 'line-number', None, _('print matching line numbers')),
4086 ('r', 'rev', [],
4086 ('r', 'rev', [],
4087 _('only search files changed within revision range'), _('REV')),
4087 _('only search files changed within revision range'), _('REV')),
4088 ('u', 'user', None, _('list the author (long with -v)')),
4088 ('u', 'user', None, _('list the author (long with -v)')),
4089 ('d', 'date', None, _('list the date (short with -q)')),
4089 ('d', 'date', None, _('list the date (short with -q)')),
4090 ] + walkopts,
4090 ] + walkopts,
4091 _('[OPTION]... PATTERN [FILE]...'),
4091 _('[OPTION]... PATTERN [FILE]...'),
4092 inferrepo=True)
4092 inferrepo=True)
4093 def grep(ui, repo, pattern, *pats, **opts):
4093 def grep(ui, repo, pattern, *pats, **opts):
4094 """search for a pattern in specified files and revisions
4094 """search for a pattern in specified files and revisions
4095
4095
4096 Search revisions of files for a regular expression.
4096 Search revisions of files for a regular expression.
4097
4097
4098 This command behaves differently than Unix grep. It only accepts
4098 This command behaves differently than Unix grep. It only accepts
4099 Python/Perl regexps. It searches repository history, not the
4099 Python/Perl regexps. It searches repository history, not the
4100 working directory. It always prints the revision number in which a
4100 working directory. It always prints the revision number in which a
4101 match appears.
4101 match appears.
4102
4102
4103 By default, grep only prints output for the first revision of a
4103 By default, grep only prints output for the first revision of a
4104 file in which it finds a match. To get it to print every revision
4104 file in which it finds a match. To get it to print every revision
4105 that contains a change in match status ("-" for a match that
4105 that contains a change in match status ("-" for a match that
4106 becomes a non-match, or "+" for a non-match that becomes a match),
4106 becomes a non-match, or "+" for a non-match that becomes a match),
4107 use the --all flag.
4107 use the --all flag.
4108
4108
4109 Returns 0 if a match is found, 1 otherwise.
4109 Returns 0 if a match is found, 1 otherwise.
4110 """
4110 """
4111 reflags = re.M
4111 reflags = re.M
4112 if opts.get('ignore_case'):
4112 if opts.get('ignore_case'):
4113 reflags |= re.I
4113 reflags |= re.I
4114 try:
4114 try:
4115 regexp = util.re.compile(pattern, reflags)
4115 regexp = util.re.compile(pattern, reflags)
4116 except re.error as inst:
4116 except re.error as inst:
4117 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
4117 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
4118 return 1
4118 return 1
4119 sep, eol = ':', '\n'
4119 sep, eol = ':', '\n'
4120 if opts.get('print0'):
4120 if opts.get('print0'):
4121 sep = eol = '\0'
4121 sep = eol = '\0'
4122
4122
4123 getfile = util.lrucachefunc(repo.file)
4123 getfile = util.lrucachefunc(repo.file)
4124
4124
4125 def matchlines(body):
4125 def matchlines(body):
4126 begin = 0
4126 begin = 0
4127 linenum = 0
4127 linenum = 0
4128 while begin < len(body):
4128 while begin < len(body):
4129 match = regexp.search(body, begin)
4129 match = regexp.search(body, begin)
4130 if not match:
4130 if not match:
4131 break
4131 break
4132 mstart, mend = match.span()
4132 mstart, mend = match.span()
4133 linenum += body.count('\n', begin, mstart) + 1
4133 linenum += body.count('\n', begin, mstart) + 1
4134 lstart = body.rfind('\n', begin, mstart) + 1 or begin
4134 lstart = body.rfind('\n', begin, mstart) + 1 or begin
4135 begin = body.find('\n', mend) + 1 or len(body) + 1
4135 begin = body.find('\n', mend) + 1 or len(body) + 1
4136 lend = begin - 1
4136 lend = begin - 1
4137 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
4137 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
4138
4138
4139 class linestate(object):
4139 class linestate(object):
4140 def __init__(self, line, linenum, colstart, colend):
4140 def __init__(self, line, linenum, colstart, colend):
4141 self.line = line
4141 self.line = line
4142 self.linenum = linenum
4142 self.linenum = linenum
4143 self.colstart = colstart
4143 self.colstart = colstart
4144 self.colend = colend
4144 self.colend = colend
4145
4145
4146 def __hash__(self):
4146 def __hash__(self):
4147 return hash((self.linenum, self.line))
4147 return hash((self.linenum, self.line))
4148
4148
4149 def __eq__(self, other):
4149 def __eq__(self, other):
4150 return self.line == other.line
4150 return self.line == other.line
4151
4151
4152 def __iter__(self):
4152 def __iter__(self):
4153 yield (self.line[:self.colstart], '')
4153 yield (self.line[:self.colstart], '')
4154 yield (self.line[self.colstart:self.colend], 'grep.match')
4154 yield (self.line[self.colstart:self.colend], 'grep.match')
4155 rest = self.line[self.colend:]
4155 rest = self.line[self.colend:]
4156 while rest != '':
4156 while rest != '':
4157 match = regexp.search(rest)
4157 match = regexp.search(rest)
4158 if not match:
4158 if not match:
4159 yield (rest, '')
4159 yield (rest, '')
4160 break
4160 break
4161 mstart, mend = match.span()
4161 mstart, mend = match.span()
4162 yield (rest[:mstart], '')
4162 yield (rest[:mstart], '')
4163 yield (rest[mstart:mend], 'grep.match')
4163 yield (rest[mstart:mend], 'grep.match')
4164 rest = rest[mend:]
4164 rest = rest[mend:]
4165
4165
4166 matches = {}
4166 matches = {}
4167 copies = {}
4167 copies = {}
4168 def grepbody(fn, rev, body):
4168 def grepbody(fn, rev, body):
4169 matches[rev].setdefault(fn, [])
4169 matches[rev].setdefault(fn, [])
4170 m = matches[rev][fn]
4170 m = matches[rev][fn]
4171 for lnum, cstart, cend, line in matchlines(body):
4171 for lnum, cstart, cend, line in matchlines(body):
4172 s = linestate(line, lnum, cstart, cend)
4172 s = linestate(line, lnum, cstart, cend)
4173 m.append(s)
4173 m.append(s)
4174
4174
4175 def difflinestates(a, b):
4175 def difflinestates(a, b):
4176 sm = difflib.SequenceMatcher(None, a, b)
4176 sm = difflib.SequenceMatcher(None, a, b)
4177 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
4177 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
4178 if tag == 'insert':
4178 if tag == 'insert':
4179 for i in xrange(blo, bhi):
4179 for i in xrange(blo, bhi):
4180 yield ('+', b[i])
4180 yield ('+', b[i])
4181 elif tag == 'delete':
4181 elif tag == 'delete':
4182 for i in xrange(alo, ahi):
4182 for i in xrange(alo, ahi):
4183 yield ('-', a[i])
4183 yield ('-', a[i])
4184 elif tag == 'replace':
4184 elif tag == 'replace':
4185 for i in xrange(alo, ahi):
4185 for i in xrange(alo, ahi):
4186 yield ('-', a[i])
4186 yield ('-', a[i])
4187 for i in xrange(blo, bhi):
4187 for i in xrange(blo, bhi):
4188 yield ('+', b[i])
4188 yield ('+', b[i])
4189
4189
4190 def display(fn, ctx, pstates, states):
4190 def display(fn, ctx, pstates, states):
4191 rev = ctx.rev()
4191 rev = ctx.rev()
4192 if ui.quiet:
4192 if ui.quiet:
4193 datefunc = util.shortdate
4193 datefunc = util.shortdate
4194 else:
4194 else:
4195 datefunc = util.datestr
4195 datefunc = util.datestr
4196 found = False
4196 found = False
4197 @util.cachefunc
4197 @util.cachefunc
4198 def binary():
4198 def binary():
4199 flog = getfile(fn)
4199 flog = getfile(fn)
4200 return util.binary(flog.read(ctx.filenode(fn)))
4200 return util.binary(flog.read(ctx.filenode(fn)))
4201
4201
4202 if opts.get('all'):
4202 if opts.get('all'):
4203 iter = difflinestates(pstates, states)
4203 iter = difflinestates(pstates, states)
4204 else:
4204 else:
4205 iter = [('', l) for l in states]
4205 iter = [('', l) for l in states]
4206 for change, l in iter:
4206 for change, l in iter:
4207 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
4207 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
4208
4208
4209 if opts.get('line_number'):
4209 if opts.get('line_number'):
4210 cols.append((str(l.linenum), 'grep.linenumber'))
4210 cols.append((str(l.linenum), 'grep.linenumber'))
4211 if opts.get('all'):
4211 if opts.get('all'):
4212 cols.append((change, 'grep.change'))
4212 cols.append((change, 'grep.change'))
4213 if opts.get('user'):
4213 if opts.get('user'):
4214 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
4214 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
4215 if opts.get('date'):
4215 if opts.get('date'):
4216 cols.append((datefunc(ctx.date()), 'grep.date'))
4216 cols.append((datefunc(ctx.date()), 'grep.date'))
4217 for col, label in cols[:-1]:
4217 for col, label in cols[:-1]:
4218 ui.write(col, label=label)
4218 ui.write(col, label=label)
4219 ui.write(sep, label='grep.sep')
4219 ui.write(sep, label='grep.sep')
4220 ui.write(cols[-1][0], label=cols[-1][1])
4220 ui.write(cols[-1][0], label=cols[-1][1])
4221 if not opts.get('files_with_matches'):
4221 if not opts.get('files_with_matches'):
4222 ui.write(sep, label='grep.sep')
4222 ui.write(sep, label='grep.sep')
4223 if not opts.get('text') and binary():
4223 if not opts.get('text') and binary():
4224 ui.write(" Binary file matches")
4224 ui.write(" Binary file matches")
4225 else:
4225 else:
4226 for s, label in l:
4226 for s, label in l:
4227 ui.write(s, label=label)
4227 ui.write(s, label=label)
4228 ui.write(eol)
4228 ui.write(eol)
4229 found = True
4229 found = True
4230 if opts.get('files_with_matches'):
4230 if opts.get('files_with_matches'):
4231 break
4231 break
4232 return found
4232 return found
4233
4233
4234 skip = {}
4234 skip = {}
4235 revfiles = {}
4235 revfiles = {}
4236 matchfn = scmutil.match(repo[None], pats, opts)
4236 matchfn = scmutil.match(repo[None], pats, opts)
4237 found = False
4237 found = False
4238 follow = opts.get('follow')
4238 follow = opts.get('follow')
4239
4239
4240 def prep(ctx, fns):
4240 def prep(ctx, fns):
4241 rev = ctx.rev()
4241 rev = ctx.rev()
4242 pctx = ctx.p1()
4242 pctx = ctx.p1()
4243 parent = pctx.rev()
4243 parent = pctx.rev()
4244 matches.setdefault(rev, {})
4244 matches.setdefault(rev, {})
4245 matches.setdefault(parent, {})
4245 matches.setdefault(parent, {})
4246 files = revfiles.setdefault(rev, [])
4246 files = revfiles.setdefault(rev, [])
4247 for fn in fns:
4247 for fn in fns:
4248 flog = getfile(fn)
4248 flog = getfile(fn)
4249 try:
4249 try:
4250 fnode = ctx.filenode(fn)
4250 fnode = ctx.filenode(fn)
4251 except error.LookupError:
4251 except error.LookupError:
4252 continue
4252 continue
4253
4253
4254 copied = flog.renamed(fnode)
4254 copied = flog.renamed(fnode)
4255 copy = follow and copied and copied[0]
4255 copy = follow and copied and copied[0]
4256 if copy:
4256 if copy:
4257 copies.setdefault(rev, {})[fn] = copy
4257 copies.setdefault(rev, {})[fn] = copy
4258 if fn in skip:
4258 if fn in skip:
4259 if copy:
4259 if copy:
4260 skip[copy] = True
4260 skip[copy] = True
4261 continue
4261 continue
4262 files.append(fn)
4262 files.append(fn)
4263
4263
4264 if fn not in matches[rev]:
4264 if fn not in matches[rev]:
4265 grepbody(fn, rev, flog.read(fnode))
4265 grepbody(fn, rev, flog.read(fnode))
4266
4266
4267 pfn = copy or fn
4267 pfn = copy or fn
4268 if pfn not in matches[parent]:
4268 if pfn not in matches[parent]:
4269 try:
4269 try:
4270 fnode = pctx.filenode(pfn)
4270 fnode = pctx.filenode(pfn)
4271 grepbody(pfn, parent, flog.read(fnode))
4271 grepbody(pfn, parent, flog.read(fnode))
4272 except error.LookupError:
4272 except error.LookupError:
4273 pass
4273 pass
4274
4274
4275 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4275 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4276 rev = ctx.rev()
4276 rev = ctx.rev()
4277 parent = ctx.p1().rev()
4277 parent = ctx.p1().rev()
4278 for fn in sorted(revfiles.get(rev, [])):
4278 for fn in sorted(revfiles.get(rev, [])):
4279 states = matches[rev][fn]
4279 states = matches[rev][fn]
4280 copy = copies.get(rev, {}).get(fn)
4280 copy = copies.get(rev, {}).get(fn)
4281 if fn in skip:
4281 if fn in skip:
4282 if copy:
4282 if copy:
4283 skip[copy] = True
4283 skip[copy] = True
4284 continue
4284 continue
4285 pstates = matches.get(parent, {}).get(copy or fn, [])
4285 pstates = matches.get(parent, {}).get(copy or fn, [])
4286 if pstates or states:
4286 if pstates or states:
4287 r = display(fn, ctx, pstates, states)
4287 r = display(fn, ctx, pstates, states)
4288 found = found or r
4288 found = found or r
4289 if r and not opts.get('all'):
4289 if r and not opts.get('all'):
4290 skip[fn] = True
4290 skip[fn] = True
4291 if copy:
4291 if copy:
4292 skip[copy] = True
4292 skip[copy] = True
4293 del matches[rev]
4293 del matches[rev]
4294 del revfiles[rev]
4294 del revfiles[rev]
4295
4295
4296 return not found
4296 return not found
4297
4297
4298 @command('heads',
4298 @command('heads',
4299 [('r', 'rev', '',
4299 [('r', 'rev', '',
4300 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
4300 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
4301 ('t', 'topo', False, _('show topological heads only')),
4301 ('t', 'topo', False, _('show topological heads only')),
4302 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
4302 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
4303 ('c', 'closed', False, _('show normal and closed branch heads')),
4303 ('c', 'closed', False, _('show normal and closed branch heads')),
4304 ] + templateopts,
4304 ] + templateopts,
4305 _('[-ct] [-r STARTREV] [REV]...'))
4305 _('[-ct] [-r STARTREV] [REV]...'))
4306 def heads(ui, repo, *branchrevs, **opts):
4306 def heads(ui, repo, *branchrevs, **opts):
4307 """show branch heads
4307 """show branch heads
4308
4308
4309 With no arguments, show all open branch heads in the repository.
4309 With no arguments, show all open branch heads in the repository.
4310 Branch heads are changesets that have no descendants on the
4310 Branch heads are changesets that have no descendants on the
4311 same branch. They are where development generally takes place and
4311 same branch. They are where development generally takes place and
4312 are the usual targets for update and merge operations.
4312 are the usual targets for update and merge operations.
4313
4313
4314 If one or more REVs are given, only open branch heads on the
4314 If one or more REVs are given, only open branch heads on the
4315 branches associated with the specified changesets are shown. This
4315 branches associated with the specified changesets are shown. This
4316 means that you can use :hg:`heads .` to see the heads on the
4316 means that you can use :hg:`heads .` to see the heads on the
4317 currently checked-out branch.
4317 currently checked-out branch.
4318
4318
4319 If -c/--closed is specified, also show branch heads marked closed
4319 If -c/--closed is specified, also show branch heads marked closed
4320 (see :hg:`commit --close-branch`).
4320 (see :hg:`commit --close-branch`).
4321
4321
4322 If STARTREV is specified, only those heads that are descendants of
4322 If STARTREV is specified, only those heads that are descendants of
4323 STARTREV will be displayed.
4323 STARTREV will be displayed.
4324
4324
4325 If -t/--topo is specified, named branch mechanics will be ignored and only
4325 If -t/--topo is specified, named branch mechanics will be ignored and only
4326 topological heads (changesets with no children) will be shown.
4326 topological heads (changesets with no children) will be shown.
4327
4327
4328 Returns 0 if matching heads are found, 1 if not.
4328 Returns 0 if matching heads are found, 1 if not.
4329 """
4329 """
4330
4330
4331 start = None
4331 start = None
4332 if 'rev' in opts:
4332 if 'rev' in opts:
4333 start = scmutil.revsingle(repo, opts['rev'], None).node()
4333 start = scmutil.revsingle(repo, opts['rev'], None).node()
4334
4334
4335 if opts.get('topo'):
4335 if opts.get('topo'):
4336 heads = [repo[h] for h in repo.heads(start)]
4336 heads = [repo[h] for h in repo.heads(start)]
4337 else:
4337 else:
4338 heads = []
4338 heads = []
4339 for branch in repo.branchmap():
4339 for branch in repo.branchmap():
4340 heads += repo.branchheads(branch, start, opts.get('closed'))
4340 heads += repo.branchheads(branch, start, opts.get('closed'))
4341 heads = [repo[h] for h in heads]
4341 heads = [repo[h] for h in heads]
4342
4342
4343 if branchrevs:
4343 if branchrevs:
4344 branches = set(repo[br].branch() for br in branchrevs)
4344 branches = set(repo[br].branch() for br in branchrevs)
4345 heads = [h for h in heads if h.branch() in branches]
4345 heads = [h for h in heads if h.branch() in branches]
4346
4346
4347 if opts.get('active') and branchrevs:
4347 if opts.get('active') and branchrevs:
4348 dagheads = repo.heads(start)
4348 dagheads = repo.heads(start)
4349 heads = [h for h in heads if h.node() in dagheads]
4349 heads = [h for h in heads if h.node() in dagheads]
4350
4350
4351 if branchrevs:
4351 if branchrevs:
4352 haveheads = set(h.branch() for h in heads)
4352 haveheads = set(h.branch() for h in heads)
4353 if branches - haveheads:
4353 if branches - haveheads:
4354 headless = ', '.join(b for b in branches - haveheads)
4354 headless = ', '.join(b for b in branches - haveheads)
4355 msg = _('no open branch heads found on branches %s')
4355 msg = _('no open branch heads found on branches %s')
4356 if opts.get('rev'):
4356 if opts.get('rev'):
4357 msg += _(' (started at %s)') % opts['rev']
4357 msg += _(' (started at %s)') % opts['rev']
4358 ui.warn((msg + '\n') % headless)
4358 ui.warn((msg + '\n') % headless)
4359
4359
4360 if not heads:
4360 if not heads:
4361 return 1
4361 return 1
4362
4362
4363 heads = sorted(heads, key=lambda x: -x.rev())
4363 heads = sorted(heads, key=lambda x: -x.rev())
4364 displayer = cmdutil.show_changeset(ui, repo, opts)
4364 displayer = cmdutil.show_changeset(ui, repo, opts)
4365 for ctx in heads:
4365 for ctx in heads:
4366 displayer.show(ctx)
4366 displayer.show(ctx)
4367 displayer.close()
4367 displayer.close()
4368
4368
4369 @command('help',
4369 @command('help',
4370 [('e', 'extension', None, _('show only help for extensions')),
4370 [('e', 'extension', None, _('show only help for extensions')),
4371 ('c', 'command', None, _('show only help for commands')),
4371 ('c', 'command', None, _('show only help for commands')),
4372 ('k', 'keyword', None, _('show topics matching keyword')),
4372 ('k', 'keyword', None, _('show topics matching keyword')),
4373 ('s', 'system', [], _('show help for specific platform(s)')),
4373 ('s', 'system', [], _('show help for specific platform(s)')),
4374 ],
4374 ],
4375 _('[-ecks] [TOPIC]'),
4375 _('[-ecks] [TOPIC]'),
4376 norepo=True)
4376 norepo=True)
4377 def help_(ui, name=None, **opts):
4377 def help_(ui, name=None, **opts):
4378 """show help for a given topic or a help overview
4378 """show help for a given topic or a help overview
4379
4379
4380 With no arguments, print a list of commands with short help messages.
4380 With no arguments, print a list of commands with short help messages.
4381
4381
4382 Given a topic, extension, or command name, print help for that
4382 Given a topic, extension, or command name, print help for that
4383 topic.
4383 topic.
4384
4384
4385 Returns 0 if successful.
4385 Returns 0 if successful.
4386 """
4386 """
4387
4387
4388 textwidth = min(ui.termwidth(), 80) - 2
4388 textwidth = min(ui.termwidth(), 80) - 2
4389
4389
4390 keep = opts.get('system') or []
4390 keep = opts.get('system') or []
4391 if len(keep) == 0:
4391 if len(keep) == 0:
4392 if sys.platform.startswith('win'):
4392 if sys.platform.startswith('win'):
4393 keep.append('windows')
4393 keep.append('windows')
4394 elif sys.platform == 'OpenVMS':
4394 elif sys.platform == 'OpenVMS':
4395 keep.append('vms')
4395 keep.append('vms')
4396 elif sys.platform == 'plan9':
4396 elif sys.platform == 'plan9':
4397 keep.append('plan9')
4397 keep.append('plan9')
4398 else:
4398 else:
4399 keep.append('unix')
4399 keep.append('unix')
4400 keep.append(sys.platform.lower())
4400 keep.append(sys.platform.lower())
4401 if ui.verbose:
4401 if ui.verbose:
4402 keep.append('verbose')
4402 keep.append('verbose')
4403
4403
4404 section = None
4404 section = None
4405 subtopic = None
4405 subtopic = None
4406 if name and '.' in name:
4406 if name and '.' in name:
4407 name, section = name.split('.', 1)
4407 name, section = name.split('.', 1)
4408 section = section.lower()
4408 section = section.lower()
4409 if '.' in section:
4409 if '.' in section:
4410 subtopic, section = section.split('.', 1)
4410 subtopic, section = section.split('.', 1)
4411 else:
4411 else:
4412 subtopic = section
4412 subtopic = section
4413
4413
4414 text = help.help_(ui, name, subtopic=subtopic, **opts)
4414 text = help.help_(ui, name, subtopic=subtopic, **opts)
4415
4415
4416 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4416 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4417 section=section)
4417 section=section)
4418
4418
4419 # We could have been given a weird ".foo" section without a name
4419 # We could have been given a weird ".foo" section without a name
4420 # to look for, or we could have simply failed to found "foo.bar"
4420 # to look for, or we could have simply failed to found "foo.bar"
4421 # because bar isn't a section of foo
4421 # because bar isn't a section of foo
4422 if section and not (formatted and name):
4422 if section and not (formatted and name):
4423 raise error.Abort(_("help section not found"))
4423 raise error.Abort(_("help section not found"))
4424
4424
4425 if 'verbose' in pruned:
4425 if 'verbose' in pruned:
4426 keep.append('omitted')
4426 keep.append('omitted')
4427 else:
4427 else:
4428 keep.append('notomitted')
4428 keep.append('notomitted')
4429 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4429 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4430 section=section)
4430 section=section)
4431 ui.write(formatted)
4431 ui.write(formatted)
4432
4432
4433
4433
4434 @command('identify|id',
4434 @command('identify|id',
4435 [('r', 'rev', '',
4435 [('r', 'rev', '',
4436 _('identify the specified revision'), _('REV')),
4436 _('identify the specified revision'), _('REV')),
4437 ('n', 'num', None, _('show local revision number')),
4437 ('n', 'num', None, _('show local revision number')),
4438 ('i', 'id', None, _('show global revision id')),
4438 ('i', 'id', None, _('show global revision id')),
4439 ('b', 'branch', None, _('show branch')),
4439 ('b', 'branch', None, _('show branch')),
4440 ('t', 'tags', None, _('show tags')),
4440 ('t', 'tags', None, _('show tags')),
4441 ('B', 'bookmarks', None, _('show bookmarks')),
4441 ('B', 'bookmarks', None, _('show bookmarks')),
4442 ] + remoteopts,
4442 ] + remoteopts,
4443 _('[-nibtB] [-r REV] [SOURCE]'),
4443 _('[-nibtB] [-r REV] [SOURCE]'),
4444 optionalrepo=True)
4444 optionalrepo=True)
4445 def identify(ui, repo, source=None, rev=None,
4445 def identify(ui, repo, source=None, rev=None,
4446 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4446 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4447 """identify the working directory or specified revision
4447 """identify the working directory or specified revision
4448
4448
4449 Print a summary identifying the repository state at REV using one or
4449 Print a summary identifying the repository state at REV using one or
4450 two parent hash identifiers, followed by a "+" if the working
4450 two parent hash identifiers, followed by a "+" if the working
4451 directory has uncommitted changes, the branch name (if not default),
4451 directory has uncommitted changes, the branch name (if not default),
4452 a list of tags, and a list of bookmarks.
4452 a list of tags, and a list of bookmarks.
4453
4453
4454 When REV is not given, print a summary of the current state of the
4454 When REV is not given, print a summary of the current state of the
4455 repository.
4455 repository.
4456
4456
4457 Specifying a path to a repository root or Mercurial bundle will
4457 Specifying a path to a repository root or Mercurial bundle will
4458 cause lookup to operate on that repository/bundle.
4458 cause lookup to operate on that repository/bundle.
4459
4459
4460 .. container:: verbose
4460 .. container:: verbose
4461
4461
4462 Examples:
4462 Examples:
4463
4463
4464 - generate a build identifier for the working directory::
4464 - generate a build identifier for the working directory::
4465
4465
4466 hg id --id > build-id.dat
4466 hg id --id > build-id.dat
4467
4467
4468 - find the revision corresponding to a tag::
4468 - find the revision corresponding to a tag::
4469
4469
4470 hg id -n -r 1.3
4470 hg id -n -r 1.3
4471
4471
4472 - check the most recent revision of a remote repository::
4472 - check the most recent revision of a remote repository::
4473
4473
4474 hg id -r tip http://selenic.com/hg/
4474 hg id -r tip http://selenic.com/hg/
4475
4475
4476 See :hg:`log` for generating more information about specific revisions,
4476 See :hg:`log` for generating more information about specific revisions,
4477 including full hash identifiers.
4477 including full hash identifiers.
4478
4478
4479 Returns 0 if successful.
4479 Returns 0 if successful.
4480 """
4480 """
4481
4481
4482 if not repo and not source:
4482 if not repo and not source:
4483 raise error.Abort(_("there is no Mercurial repository here "
4483 raise error.Abort(_("there is no Mercurial repository here "
4484 "(.hg not found)"))
4484 "(.hg not found)"))
4485
4485
4486 if ui.debugflag:
4486 if ui.debugflag:
4487 hexfunc = hex
4487 hexfunc = hex
4488 else:
4488 else:
4489 hexfunc = short
4489 hexfunc = short
4490 default = not (num or id or branch or tags or bookmarks)
4490 default = not (num or id or branch or tags or bookmarks)
4491 output = []
4491 output = []
4492 revs = []
4492 revs = []
4493
4493
4494 if source:
4494 if source:
4495 source, branches = hg.parseurl(ui.expandpath(source))
4495 source, branches = hg.parseurl(ui.expandpath(source))
4496 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4496 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4497 repo = peer.local()
4497 repo = peer.local()
4498 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4498 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4499
4499
4500 if not repo:
4500 if not repo:
4501 if num or branch or tags:
4501 if num or branch or tags:
4502 raise error.Abort(
4502 raise error.Abort(
4503 _("can't query remote revision number, branch, or tags"))
4503 _("can't query remote revision number, branch, or tags"))
4504 if not rev and revs:
4504 if not rev and revs:
4505 rev = revs[0]
4505 rev = revs[0]
4506 if not rev:
4506 if not rev:
4507 rev = "tip"
4507 rev = "tip"
4508
4508
4509 remoterev = peer.lookup(rev)
4509 remoterev = peer.lookup(rev)
4510 if default or id:
4510 if default or id:
4511 output = [hexfunc(remoterev)]
4511 output = [hexfunc(remoterev)]
4512
4512
4513 def getbms():
4513 def getbms():
4514 bms = []
4514 bms = []
4515
4515
4516 if 'bookmarks' in peer.listkeys('namespaces'):
4516 if 'bookmarks' in peer.listkeys('namespaces'):
4517 hexremoterev = hex(remoterev)
4517 hexremoterev = hex(remoterev)
4518 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4518 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4519 if bmr == hexremoterev]
4519 if bmr == hexremoterev]
4520
4520
4521 return sorted(bms)
4521 return sorted(bms)
4522
4522
4523 if bookmarks:
4523 if bookmarks:
4524 output.extend(getbms())
4524 output.extend(getbms())
4525 elif default and not ui.quiet:
4525 elif default and not ui.quiet:
4526 # multiple bookmarks for a single parent separated by '/'
4526 # multiple bookmarks for a single parent separated by '/'
4527 bm = '/'.join(getbms())
4527 bm = '/'.join(getbms())
4528 if bm:
4528 if bm:
4529 output.append(bm)
4529 output.append(bm)
4530 else:
4530 else:
4531 ctx = scmutil.revsingle(repo, rev, None)
4531 ctx = scmutil.revsingle(repo, rev, None)
4532
4532
4533 if ctx.rev() is None:
4533 if ctx.rev() is None:
4534 ctx = repo[None]
4534 ctx = repo[None]
4535 parents = ctx.parents()
4535 parents = ctx.parents()
4536 taglist = []
4536 taglist = []
4537 for p in parents:
4537 for p in parents:
4538 taglist.extend(p.tags())
4538 taglist.extend(p.tags())
4539
4539
4540 changed = ""
4540 changed = ""
4541 if default or id or num:
4541 if default or id or num:
4542 if (any(repo.status())
4542 if (any(repo.status())
4543 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4543 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4544 changed = '+'
4544 changed = '+'
4545 if default or id:
4545 if default or id:
4546 output = ["%s%s" %
4546 output = ["%s%s" %
4547 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4547 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4548 if num:
4548 if num:
4549 output.append("%s%s" %
4549 output.append("%s%s" %
4550 ('+'.join([str(p.rev()) for p in parents]), changed))
4550 ('+'.join([str(p.rev()) for p in parents]), changed))
4551 else:
4551 else:
4552 if default or id:
4552 if default or id:
4553 output = [hexfunc(ctx.node())]
4553 output = [hexfunc(ctx.node())]
4554 if num:
4554 if num:
4555 output.append(str(ctx.rev()))
4555 output.append(str(ctx.rev()))
4556 taglist = ctx.tags()
4556 taglist = ctx.tags()
4557
4557
4558 if default and not ui.quiet:
4558 if default and not ui.quiet:
4559 b = ctx.branch()
4559 b = ctx.branch()
4560 if b != 'default':
4560 if b != 'default':
4561 output.append("(%s)" % b)
4561 output.append("(%s)" % b)
4562
4562
4563 # multiple tags for a single parent separated by '/'
4563 # multiple tags for a single parent separated by '/'
4564 t = '/'.join(taglist)
4564 t = '/'.join(taglist)
4565 if t:
4565 if t:
4566 output.append(t)
4566 output.append(t)
4567
4567
4568 # multiple bookmarks for a single parent separated by '/'
4568 # multiple bookmarks for a single parent separated by '/'
4569 bm = '/'.join(ctx.bookmarks())
4569 bm = '/'.join(ctx.bookmarks())
4570 if bm:
4570 if bm:
4571 output.append(bm)
4571 output.append(bm)
4572 else:
4572 else:
4573 if branch:
4573 if branch:
4574 output.append(ctx.branch())
4574 output.append(ctx.branch())
4575
4575
4576 if tags:
4576 if tags:
4577 output.extend(taglist)
4577 output.extend(taglist)
4578
4578
4579 if bookmarks:
4579 if bookmarks:
4580 output.extend(ctx.bookmarks())
4580 output.extend(ctx.bookmarks())
4581
4581
4582 ui.write("%s\n" % ' '.join(output))
4582 ui.write("%s\n" % ' '.join(output))
4583
4583
4584 @command('import|patch',
4584 @command('import|patch',
4585 [('p', 'strip', 1,
4585 [('p', 'strip', 1,
4586 _('directory strip option for patch. This has the same '
4586 _('directory strip option for patch. This has the same '
4587 'meaning as the corresponding patch option'), _('NUM')),
4587 'meaning as the corresponding patch option'), _('NUM')),
4588 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4588 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4589 ('e', 'edit', False, _('invoke editor on commit messages')),
4589 ('e', 'edit', False, _('invoke editor on commit messages')),
4590 ('f', 'force', None,
4590 ('f', 'force', None,
4591 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4591 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4592 ('', 'no-commit', None,
4592 ('', 'no-commit', None,
4593 _("don't commit, just update the working directory")),
4593 _("don't commit, just update the working directory")),
4594 ('', 'bypass', None,
4594 ('', 'bypass', None,
4595 _("apply patch without touching the working directory")),
4595 _("apply patch without touching the working directory")),
4596 ('', 'partial', None,
4596 ('', 'partial', None,
4597 _('commit even if some hunks fail')),
4597 _('commit even if some hunks fail')),
4598 ('', 'exact', None,
4598 ('', 'exact', None,
4599 _('apply patch to the nodes from which it was generated')),
4599 _('apply patch to the nodes from which it was generated')),
4600 ('', 'prefix', '',
4600 ('', 'prefix', '',
4601 _('apply patch to subdirectory'), _('DIR')),
4601 _('apply patch to subdirectory'), _('DIR')),
4602 ('', 'import-branch', None,
4602 ('', 'import-branch', None,
4603 _('use any branch information in patch (implied by --exact)'))] +
4603 _('use any branch information in patch (implied by --exact)'))] +
4604 commitopts + commitopts2 + similarityopts,
4604 commitopts + commitopts2 + similarityopts,
4605 _('[OPTION]... PATCH...'))
4605 _('[OPTION]... PATCH...'))
4606 def import_(ui, repo, patch1=None, *patches, **opts):
4606 def import_(ui, repo, patch1=None, *patches, **opts):
4607 """import an ordered set of patches
4607 """import an ordered set of patches
4608
4608
4609 Import a list of patches and commit them individually (unless
4609 Import a list of patches and commit them individually (unless
4610 --no-commit is specified).
4610 --no-commit is specified).
4611
4611
4612 To read a patch from standard input, use "-" as the patch name. If
4612 To read a patch from standard input, use "-" as the patch name. If
4613 a URL is specified, the patch will be downloaded from there.
4613 a URL is specified, the patch will be downloaded from there.
4614
4614
4615 Import first applies changes to the working directory (unless
4615 Import first applies changes to the working directory (unless
4616 --bypass is specified), import will abort if there are outstanding
4616 --bypass is specified), import will abort if there are outstanding
4617 changes.
4617 changes.
4618
4618
4619 Use --bypass to apply and commit patches directly to the
4619 Use --bypass to apply and commit patches directly to the
4620 repository, without affecting the working directory. Without
4620 repository, without affecting the working directory. Without
4621 --exact, patches will be applied on top of the working directory
4621 --exact, patches will be applied on top of the working directory
4622 parent revision.
4622 parent revision.
4623
4623
4624 You can import a patch straight from a mail message. Even patches
4624 You can import a patch straight from a mail message. Even patches
4625 as attachments work (to use the body part, it must have type
4625 as attachments work (to use the body part, it must have type
4626 text/plain or text/x-patch). From and Subject headers of email
4626 text/plain or text/x-patch). From and Subject headers of email
4627 message are used as default committer and commit message. All
4627 message are used as default committer and commit message. All
4628 text/plain body parts before first diff are added to the commit
4628 text/plain body parts before first diff are added to the commit
4629 message.
4629 message.
4630
4630
4631 If the imported patch was generated by :hg:`export`, user and
4631 If the imported patch was generated by :hg:`export`, user and
4632 description from patch override values from message headers and
4632 description from patch override values from message headers and
4633 body. Values given on command line with -m/--message and -u/--user
4633 body. Values given on command line with -m/--message and -u/--user
4634 override these.
4634 override these.
4635
4635
4636 If --exact is specified, import will set the working directory to
4636 If --exact is specified, import will set the working directory to
4637 the parent of each patch before applying it, and will abort if the
4637 the parent of each patch before applying it, and will abort if the
4638 resulting changeset has a different ID than the one recorded in
4638 resulting changeset has a different ID than the one recorded in
4639 the patch. This may happen due to character set problems or other
4639 the patch. This may happen due to character set problems or other
4640 deficiencies in the text patch format.
4640 deficiencies in the text patch format.
4641
4641
4642 Use --partial to ensure a changeset will be created from the patch
4642 Use --partial to ensure a changeset will be created from the patch
4643 even if some hunks fail to apply. Hunks that fail to apply will be
4643 even if some hunks fail to apply. Hunks that fail to apply will be
4644 written to a <target-file>.rej file. Conflicts can then be resolved
4644 written to a <target-file>.rej file. Conflicts can then be resolved
4645 by hand before :hg:`commit --amend` is run to update the created
4645 by hand before :hg:`commit --amend` is run to update the created
4646 changeset. This flag exists to let people import patches that
4646 changeset. This flag exists to let people import patches that
4647 partially apply without losing the associated metadata (author,
4647 partially apply without losing the associated metadata (author,
4648 date, description, ...).
4648 date, description, ...).
4649
4649
4650 .. note::
4650 .. note::
4651
4651
4652 When no hunks apply cleanly, :hg:`import --partial` will create
4652 When no hunks apply cleanly, :hg:`import --partial` will create
4653 an empty changeset, importing only the patch metadata.
4653 an empty changeset, importing only the patch metadata.
4654
4654
4655 With -s/--similarity, hg will attempt to discover renames and
4655 With -s/--similarity, hg will attempt to discover renames and
4656 copies in the patch in the same way as :hg:`addremove`.
4656 copies in the patch in the same way as :hg:`addremove`.
4657
4657
4658 It is possible to use external patch programs to perform the patch
4658 It is possible to use external patch programs to perform the patch
4659 by setting the ``ui.patch`` configuration option. For the default
4659 by setting the ``ui.patch`` configuration option. For the default
4660 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4660 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4661 See :hg:`help config` for more information about configuration
4661 See :hg:`help config` for more information about configuration
4662 files and how to use these options.
4662 files and how to use these options.
4663
4663
4664 See :hg:`help dates` for a list of formats valid for -d/--date.
4664 See :hg:`help dates` for a list of formats valid for -d/--date.
4665
4665
4666 .. container:: verbose
4666 .. container:: verbose
4667
4667
4668 Examples:
4668 Examples:
4669
4669
4670 - import a traditional patch from a website and detect renames::
4670 - import a traditional patch from a website and detect renames::
4671
4671
4672 hg import -s 80 http://example.com/bugfix.patch
4672 hg import -s 80 http://example.com/bugfix.patch
4673
4673
4674 - import a changeset from an hgweb server::
4674 - import a changeset from an hgweb server::
4675
4675
4676 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4676 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4677
4677
4678 - import all the patches in an Unix-style mbox::
4678 - import all the patches in an Unix-style mbox::
4679
4679
4680 hg import incoming-patches.mbox
4680 hg import incoming-patches.mbox
4681
4681
4682 - attempt to exactly restore an exported changeset (not always
4682 - attempt to exactly restore an exported changeset (not always
4683 possible)::
4683 possible)::
4684
4684
4685 hg import --exact proposed-fix.patch
4685 hg import --exact proposed-fix.patch
4686
4686
4687 - use an external tool to apply a patch which is too fuzzy for
4687 - use an external tool to apply a patch which is too fuzzy for
4688 the default internal tool.
4688 the default internal tool.
4689
4689
4690 hg import --config ui.patch="patch --merge" fuzzy.patch
4690 hg import --config ui.patch="patch --merge" fuzzy.patch
4691
4691
4692 - change the default fuzzing from 2 to a less strict 7
4692 - change the default fuzzing from 2 to a less strict 7
4693
4693
4694 hg import --config ui.fuzz=7 fuzz.patch
4694 hg import --config ui.fuzz=7 fuzz.patch
4695
4695
4696 Returns 0 on success, 1 on partial success (see --partial).
4696 Returns 0 on success, 1 on partial success (see --partial).
4697 """
4697 """
4698
4698
4699 if not patch1:
4699 if not patch1:
4700 raise error.Abort(_('need at least one patch to import'))
4700 raise error.Abort(_('need at least one patch to import'))
4701
4701
4702 patches = (patch1,) + patches
4702 patches = (patch1,) + patches
4703
4703
4704 date = opts.get('date')
4704 date = opts.get('date')
4705 if date:
4705 if date:
4706 opts['date'] = util.parsedate(date)
4706 opts['date'] = util.parsedate(date)
4707
4707
4708 exact = opts.get('exact')
4708 exact = opts.get('exact')
4709 update = not opts.get('bypass')
4709 update = not opts.get('bypass')
4710 if not update and opts.get('no_commit'):
4710 if not update and opts.get('no_commit'):
4711 raise error.Abort(_('cannot use --no-commit with --bypass'))
4711 raise error.Abort(_('cannot use --no-commit with --bypass'))
4712 try:
4712 try:
4713 sim = float(opts.get('similarity') or 0)
4713 sim = float(opts.get('similarity') or 0)
4714 except ValueError:
4714 except ValueError:
4715 raise error.Abort(_('similarity must be a number'))
4715 raise error.Abort(_('similarity must be a number'))
4716 if sim < 0 or sim > 100:
4716 if sim < 0 or sim > 100:
4717 raise error.Abort(_('similarity must be between 0 and 100'))
4717 raise error.Abort(_('similarity must be between 0 and 100'))
4718 if sim and not update:
4718 if sim and not update:
4719 raise error.Abort(_('cannot use --similarity with --bypass'))
4719 raise error.Abort(_('cannot use --similarity with --bypass'))
4720 if exact:
4720 if exact:
4721 if opts.get('edit'):
4721 if opts.get('edit'):
4722 raise error.Abort(_('cannot use --exact with --edit'))
4722 raise error.Abort(_('cannot use --exact with --edit'))
4723 if opts.get('prefix'):
4723 if opts.get('prefix'):
4724 raise error.Abort(_('cannot use --exact with --prefix'))
4724 raise error.Abort(_('cannot use --exact with --prefix'))
4725
4725
4726 base = opts["base"]
4726 base = opts["base"]
4727 wlock = dsguard = lock = tr = None
4727 wlock = dsguard = lock = tr = None
4728 msgs = []
4728 msgs = []
4729 ret = 0
4729 ret = 0
4730
4730
4731
4731
4732 try:
4732 try:
4733 wlock = repo.wlock()
4733 wlock = repo.wlock()
4734
4734
4735 if update:
4735 if update:
4736 cmdutil.checkunfinished(repo)
4736 cmdutil.checkunfinished(repo)
4737 if (exact or not opts.get('force')):
4737 if (exact or not opts.get('force')):
4738 cmdutil.bailifchanged(repo)
4738 cmdutil.bailifchanged(repo)
4739
4739
4740 if not opts.get('no_commit'):
4740 if not opts.get('no_commit'):
4741 lock = repo.lock()
4741 lock = repo.lock()
4742 tr = repo.transaction('import')
4742 tr = repo.transaction('import')
4743 else:
4743 else:
4744 dsguard = cmdutil.dirstateguard(repo, 'import')
4744 dsguard = cmdutil.dirstateguard(repo, 'import')
4745 parents = repo[None].parents()
4745 parents = repo[None].parents()
4746 for patchurl in patches:
4746 for patchurl in patches:
4747 if patchurl == '-':
4747 if patchurl == '-':
4748 ui.status(_('applying patch from stdin\n'))
4748 ui.status(_('applying patch from stdin\n'))
4749 patchfile = ui.fin
4749 patchfile = ui.fin
4750 patchurl = 'stdin' # for error message
4750 patchurl = 'stdin' # for error message
4751 else:
4751 else:
4752 patchurl = os.path.join(base, patchurl)
4752 patchurl = os.path.join(base, patchurl)
4753 ui.status(_('applying %s\n') % patchurl)
4753 ui.status(_('applying %s\n') % patchurl)
4754 patchfile = hg.openpath(ui, patchurl)
4754 patchfile = hg.openpath(ui, patchurl)
4755
4755
4756 haspatch = False
4756 haspatch = False
4757 for hunk in patch.split(patchfile):
4757 for hunk in patch.split(patchfile):
4758 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4758 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4759 parents, opts,
4759 parents, opts,
4760 msgs, hg.clean)
4760 msgs, hg.clean)
4761 if msg:
4761 if msg:
4762 haspatch = True
4762 haspatch = True
4763 ui.note(msg + '\n')
4763 ui.note(msg + '\n')
4764 if update or exact:
4764 if update or exact:
4765 parents = repo[None].parents()
4765 parents = repo[None].parents()
4766 else:
4766 else:
4767 parents = [repo[node]]
4767 parents = [repo[node]]
4768 if rej:
4768 if rej:
4769 ui.write_err(_("patch applied partially\n"))
4769 ui.write_err(_("patch applied partially\n"))
4770 ui.write_err(_("(fix the .rej files and run "
4770 ui.write_err(_("(fix the .rej files and run "
4771 "`hg commit --amend`)\n"))
4771 "`hg commit --amend`)\n"))
4772 ret = 1
4772 ret = 1
4773 break
4773 break
4774
4774
4775 if not haspatch:
4775 if not haspatch:
4776 raise error.Abort(_('%s: no diffs found') % patchurl)
4776 raise error.Abort(_('%s: no diffs found') % patchurl)
4777
4777
4778 if tr:
4778 if tr:
4779 tr.close()
4779 tr.close()
4780 if msgs:
4780 if msgs:
4781 repo.savecommitmessage('\n* * *\n'.join(msgs))
4781 repo.savecommitmessage('\n* * *\n'.join(msgs))
4782 if dsguard:
4782 if dsguard:
4783 dsguard.close()
4783 dsguard.close()
4784 return ret
4784 return ret
4785 finally:
4785 finally:
4786 if tr:
4786 if tr:
4787 tr.release()
4787 tr.release()
4788 release(lock, dsguard, wlock)
4788 release(lock, dsguard, wlock)
4789
4789
4790 @command('incoming|in',
4790 @command('incoming|in',
4791 [('f', 'force', None,
4791 [('f', 'force', None,
4792 _('run even if remote repository is unrelated')),
4792 _('run even if remote repository is unrelated')),
4793 ('n', 'newest-first', None, _('show newest record first')),
4793 ('n', 'newest-first', None, _('show newest record first')),
4794 ('', 'bundle', '',
4794 ('', 'bundle', '',
4795 _('file to store the bundles into'), _('FILE')),
4795 _('file to store the bundles into'), _('FILE')),
4796 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4796 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4797 ('B', 'bookmarks', False, _("compare bookmarks")),
4797 ('B', 'bookmarks', False, _("compare bookmarks")),
4798 ('b', 'branch', [],
4798 ('b', 'branch', [],
4799 _('a specific branch you would like to pull'), _('BRANCH')),
4799 _('a specific branch you would like to pull'), _('BRANCH')),
4800 ] + logopts + remoteopts + subrepoopts,
4800 ] + logopts + remoteopts + subrepoopts,
4801 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4801 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4802 def incoming(ui, repo, source="default", **opts):
4802 def incoming(ui, repo, source="default", **opts):
4803 """show new changesets found in source
4803 """show new changesets found in source
4804
4804
4805 Show new changesets found in the specified path/URL or the default
4805 Show new changesets found in the specified path/URL or the default
4806 pull location. These are the changesets that would have been pulled
4806 pull location. These are the changesets that would have been pulled
4807 if a pull at the time you issued this command.
4807 if a pull at the time you issued this command.
4808
4808
4809 See pull for valid source format details.
4809 See pull for valid source format details.
4810
4810
4811 .. container:: verbose
4811 .. container:: verbose
4812
4812
4813 With -B/--bookmarks, the result of bookmark comparison between
4813 With -B/--bookmarks, the result of bookmark comparison between
4814 local and remote repositories is displayed. With -v/--verbose,
4814 local and remote repositories is displayed. With -v/--verbose,
4815 status is also displayed for each bookmark like below::
4815 status is also displayed for each bookmark like below::
4816
4816
4817 BM1 01234567890a added
4817 BM1 01234567890a added
4818 BM2 1234567890ab advanced
4818 BM2 1234567890ab advanced
4819 BM3 234567890abc diverged
4819 BM3 234567890abc diverged
4820 BM4 34567890abcd changed
4820 BM4 34567890abcd changed
4821
4821
4822 The action taken locally when pulling depends on the
4822 The action taken locally when pulling depends on the
4823 status of each bookmark:
4823 status of each bookmark:
4824
4824
4825 :``added``: pull will create it
4825 :``added``: pull will create it
4826 :``advanced``: pull will update it
4826 :``advanced``: pull will update it
4827 :``diverged``: pull will create a divergent bookmark
4827 :``diverged``: pull will create a divergent bookmark
4828 :``changed``: result depends on remote changesets
4828 :``changed``: result depends on remote changesets
4829
4829
4830 From the point of view of pulling behavior, bookmark
4830 From the point of view of pulling behavior, bookmark
4831 existing only in the remote repository are treated as ``added``,
4831 existing only in the remote repository are treated as ``added``,
4832 even if it is in fact locally deleted.
4832 even if it is in fact locally deleted.
4833
4833
4834 .. container:: verbose
4834 .. container:: verbose
4835
4835
4836 For remote repository, using --bundle avoids downloading the
4836 For remote repository, using --bundle avoids downloading the
4837 changesets twice if the incoming is followed by a pull.
4837 changesets twice if the incoming is followed by a pull.
4838
4838
4839 Examples:
4839 Examples:
4840
4840
4841 - show incoming changes with patches and full description::
4841 - show incoming changes with patches and full description::
4842
4842
4843 hg incoming -vp
4843 hg incoming -vp
4844
4844
4845 - show incoming changes excluding merges, store a bundle::
4845 - show incoming changes excluding merges, store a bundle::
4846
4846
4847 hg in -vpM --bundle incoming.hg
4847 hg in -vpM --bundle incoming.hg
4848 hg pull incoming.hg
4848 hg pull incoming.hg
4849
4849
4850 - briefly list changes inside a bundle::
4850 - briefly list changes inside a bundle::
4851
4851
4852 hg in changes.hg -T "{desc|firstline}\\n"
4852 hg in changes.hg -T "{desc|firstline}\\n"
4853
4853
4854 Returns 0 if there are incoming changes, 1 otherwise.
4854 Returns 0 if there are incoming changes, 1 otherwise.
4855 """
4855 """
4856 if opts.get('graph'):
4856 if opts.get('graph'):
4857 cmdutil.checkunsupportedgraphflags([], opts)
4857 cmdutil.checkunsupportedgraphflags([], opts)
4858 def display(other, chlist, displayer):
4858 def display(other, chlist, displayer):
4859 revdag = cmdutil.graphrevs(other, chlist, opts)
4859 revdag = cmdutil.graphrevs(other, chlist, opts)
4860 cmdutil.displaygraph(ui, repo, revdag, displayer,
4860 cmdutil.displaygraph(ui, repo, revdag, displayer,
4861 graphmod.asciiedges)
4861 graphmod.asciiedges)
4862
4862
4863 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4863 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4864 return 0
4864 return 0
4865
4865
4866 if opts.get('bundle') and opts.get('subrepos'):
4866 if opts.get('bundle') and opts.get('subrepos'):
4867 raise error.Abort(_('cannot combine --bundle and --subrepos'))
4867 raise error.Abort(_('cannot combine --bundle and --subrepos'))
4868
4868
4869 if opts.get('bookmarks'):
4869 if opts.get('bookmarks'):
4870 source, branches = hg.parseurl(ui.expandpath(source),
4870 source, branches = hg.parseurl(ui.expandpath(source),
4871 opts.get('branch'))
4871 opts.get('branch'))
4872 other = hg.peer(repo, opts, source)
4872 other = hg.peer(repo, opts, source)
4873 if 'bookmarks' not in other.listkeys('namespaces'):
4873 if 'bookmarks' not in other.listkeys('namespaces'):
4874 ui.warn(_("remote doesn't support bookmarks\n"))
4874 ui.warn(_("remote doesn't support bookmarks\n"))
4875 return 0
4875 return 0
4876 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4876 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4877 return bookmarks.incoming(ui, repo, other)
4877 return bookmarks.incoming(ui, repo, other)
4878
4878
4879 repo._subtoppath = ui.expandpath(source)
4879 repo._subtoppath = ui.expandpath(source)
4880 try:
4880 try:
4881 return hg.incoming(ui, repo, source, opts)
4881 return hg.incoming(ui, repo, source, opts)
4882 finally:
4882 finally:
4883 del repo._subtoppath
4883 del repo._subtoppath
4884
4884
4885
4885
4886 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4886 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4887 norepo=True)
4887 norepo=True)
4888 def init(ui, dest=".", **opts):
4888 def init(ui, dest=".", **opts):
4889 """create a new repository in the given directory
4889 """create a new repository in the given directory
4890
4890
4891 Initialize a new repository in the given directory. If the given
4891 Initialize a new repository in the given directory. If the given
4892 directory does not exist, it will be created.
4892 directory does not exist, it will be created.
4893
4893
4894 If no directory is given, the current directory is used.
4894 If no directory is given, the current directory is used.
4895
4895
4896 It is possible to specify an ``ssh://`` URL as the destination.
4896 It is possible to specify an ``ssh://`` URL as the destination.
4897 See :hg:`help urls` for more information.
4897 See :hg:`help urls` for more information.
4898
4898
4899 Returns 0 on success.
4899 Returns 0 on success.
4900 """
4900 """
4901 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4901 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4902
4902
4903 @command('locate',
4903 @command('locate',
4904 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4904 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4905 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4905 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4906 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4906 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4907 ] + walkopts,
4907 ] + walkopts,
4908 _('[OPTION]... [PATTERN]...'))
4908 _('[OPTION]... [PATTERN]...'))
4909 def locate(ui, repo, *pats, **opts):
4909 def locate(ui, repo, *pats, **opts):
4910 """locate files matching specific patterns (DEPRECATED)
4910 """locate files matching specific patterns (DEPRECATED)
4911
4911
4912 Print files under Mercurial control in the working directory whose
4912 Print files under Mercurial control in the working directory whose
4913 names match the given patterns.
4913 names match the given patterns.
4914
4914
4915 By default, this command searches all directories in the working
4915 By default, this command searches all directories in the working
4916 directory. To search just the current directory and its
4916 directory. To search just the current directory and its
4917 subdirectories, use "--include .".
4917 subdirectories, use "--include .".
4918
4918
4919 If no patterns are given to match, this command prints the names
4919 If no patterns are given to match, this command prints the names
4920 of all files under Mercurial control in the working directory.
4920 of all files under Mercurial control in the working directory.
4921
4921
4922 If you want to feed the output of this command into the "xargs"
4922 If you want to feed the output of this command into the "xargs"
4923 command, use the -0 option to both this command and "xargs". This
4923 command, use the -0 option to both this command and "xargs". This
4924 will avoid the problem of "xargs" treating single filenames that
4924 will avoid the problem of "xargs" treating single filenames that
4925 contain whitespace as multiple filenames.
4925 contain whitespace as multiple filenames.
4926
4926
4927 See :hg:`help files` for a more versatile command.
4927 See :hg:`help files` for a more versatile command.
4928
4928
4929 Returns 0 if a match is found, 1 otherwise.
4929 Returns 0 if a match is found, 1 otherwise.
4930 """
4930 """
4931 if opts.get('print0'):
4931 if opts.get('print0'):
4932 end = '\0'
4932 end = '\0'
4933 else:
4933 else:
4934 end = '\n'
4934 end = '\n'
4935 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4935 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4936
4936
4937 ret = 1
4937 ret = 1
4938 ctx = repo[rev]
4938 ctx = repo[rev]
4939 m = scmutil.match(ctx, pats, opts, default='relglob',
4939 m = scmutil.match(ctx, pats, opts, default='relglob',
4940 badfn=lambda x, y: False)
4940 badfn=lambda x, y: False)
4941
4941
4942 for abs in ctx.matches(m):
4942 for abs in ctx.matches(m):
4943 if opts.get('fullpath'):
4943 if opts.get('fullpath'):
4944 ui.write(repo.wjoin(abs), end)
4944 ui.write(repo.wjoin(abs), end)
4945 else:
4945 else:
4946 ui.write(((pats and m.rel(abs)) or abs), end)
4946 ui.write(((pats and m.rel(abs)) or abs), end)
4947 ret = 0
4947 ret = 0
4948
4948
4949 return ret
4949 return ret
4950
4950
4951 @command('^log|history',
4951 @command('^log|history',
4952 [('f', 'follow', None,
4952 [('f', 'follow', None,
4953 _('follow changeset history, or file history across copies and renames')),
4953 _('follow changeset history, or file history across copies and renames')),
4954 ('', 'follow-first', None,
4954 ('', 'follow-first', None,
4955 _('only follow the first parent of merge changesets (DEPRECATED)')),
4955 _('only follow the first parent of merge changesets (DEPRECATED)')),
4956 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4956 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4957 ('C', 'copies', None, _('show copied files')),
4957 ('C', 'copies', None, _('show copied files')),
4958 ('k', 'keyword', [],
4958 ('k', 'keyword', [],
4959 _('do case-insensitive search for a given text'), _('TEXT')),
4959 _('do case-insensitive search for a given text'), _('TEXT')),
4960 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4960 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4961 ('', 'removed', None, _('include revisions where files were removed')),
4961 ('', 'removed', None, _('include revisions where files were removed')),
4962 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4962 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4963 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4963 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4964 ('', 'only-branch', [],
4964 ('', 'only-branch', [],
4965 _('show only changesets within the given named branch (DEPRECATED)'),
4965 _('show only changesets within the given named branch (DEPRECATED)'),
4966 _('BRANCH')),
4966 _('BRANCH')),
4967 ('b', 'branch', [],
4967 ('b', 'branch', [],
4968 _('show changesets within the given named branch'), _('BRANCH')),
4968 _('show changesets within the given named branch'), _('BRANCH')),
4969 ('P', 'prune', [],
4969 ('P', 'prune', [],
4970 _('do not display revision or any of its ancestors'), _('REV')),
4970 _('do not display revision or any of its ancestors'), _('REV')),
4971 ] + logopts + walkopts,
4971 ] + logopts + walkopts,
4972 _('[OPTION]... [FILE]'),
4972 _('[OPTION]... [FILE]'),
4973 inferrepo=True)
4973 inferrepo=True)
4974 def log(ui, repo, *pats, **opts):
4974 def log(ui, repo, *pats, **opts):
4975 """show revision history of entire repository or files
4975 """show revision history of entire repository or files
4976
4976
4977 Print the revision history of the specified files or the entire
4977 Print the revision history of the specified files or the entire
4978 project.
4978 project.
4979
4979
4980 If no revision range is specified, the default is ``tip:0`` unless
4980 If no revision range is specified, the default is ``tip:0`` unless
4981 --follow is set, in which case the working directory parent is
4981 --follow is set, in which case the working directory parent is
4982 used as the starting revision.
4982 used as the starting revision.
4983
4983
4984 File history is shown without following rename or copy history of
4984 File history is shown without following rename or copy history of
4985 files. Use -f/--follow with a filename to follow history across
4985 files. Use -f/--follow with a filename to follow history across
4986 renames and copies. --follow without a filename will only show
4986 renames and copies. --follow without a filename will only show
4987 ancestors or descendants of the starting revision.
4987 ancestors or descendants of the starting revision.
4988
4988
4989 By default this command prints revision number and changeset id,
4989 By default this command prints revision number and changeset id,
4990 tags, non-trivial parents, user, date and time, and a summary for
4990 tags, non-trivial parents, user, date and time, and a summary for
4991 each commit. When the -v/--verbose switch is used, the list of
4991 each commit. When the -v/--verbose switch is used, the list of
4992 changed files and full commit message are shown.
4992 changed files and full commit message are shown.
4993
4993
4994 With --graph the revisions are shown as an ASCII art DAG with the most
4994 With --graph the revisions are shown as an ASCII art DAG with the most
4995 recent changeset at the top.
4995 recent changeset at the top.
4996 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4996 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4997 and '+' represents a fork where the changeset from the lines below is a
4997 and '+' represents a fork where the changeset from the lines below is a
4998 parent of the 'o' merge on the same line.
4998 parent of the 'o' merge on the same line.
4999
4999
5000 .. note::
5000 .. note::
5001
5001
5002 :hg:`log --patch` may generate unexpected diff output for merge
5002 :hg:`log --patch` may generate unexpected diff output for merge
5003 changesets, as it will only compare the merge changeset against
5003 changesets, as it will only compare the merge changeset against
5004 its first parent. Also, only files different from BOTH parents
5004 its first parent. Also, only files different from BOTH parents
5005 will appear in files:.
5005 will appear in files:.
5006
5006
5007 .. note::
5007 .. note::
5008
5008
5009 For performance reasons, :hg:`log FILE` may omit duplicate changes
5009 For performance reasons, :hg:`log FILE` may omit duplicate changes
5010 made on branches and will not show removals or mode changes. To
5010 made on branches and will not show removals or mode changes. To
5011 see all such changes, use the --removed switch.
5011 see all such changes, use the --removed switch.
5012
5012
5013 .. container:: verbose
5013 .. container:: verbose
5014
5014
5015 Some examples:
5015 Some examples:
5016
5016
5017 - changesets with full descriptions and file lists::
5017 - changesets with full descriptions and file lists::
5018
5018
5019 hg log -v
5019 hg log -v
5020
5020
5021 - changesets ancestral to the working directory::
5021 - changesets ancestral to the working directory::
5022
5022
5023 hg log -f
5023 hg log -f
5024
5024
5025 - last 10 commits on the current branch::
5025 - last 10 commits on the current branch::
5026
5026
5027 hg log -l 10 -b .
5027 hg log -l 10 -b .
5028
5028
5029 - changesets showing all modifications of a file, including removals::
5029 - changesets showing all modifications of a file, including removals::
5030
5030
5031 hg log --removed file.c
5031 hg log --removed file.c
5032
5032
5033 - all changesets that touch a directory, with diffs, excluding merges::
5033 - all changesets that touch a directory, with diffs, excluding merges::
5034
5034
5035 hg log -Mp lib/
5035 hg log -Mp lib/
5036
5036
5037 - all revision numbers that match a keyword::
5037 - all revision numbers that match a keyword::
5038
5038
5039 hg log -k bug --template "{rev}\\n"
5039 hg log -k bug --template "{rev}\\n"
5040
5040
5041 - the full hash identifier of the working directory parent::
5041 - the full hash identifier of the working directory parent::
5042
5042
5043 hg log -r . --template "{node}\\n"
5043 hg log -r . --template "{node}\\n"
5044
5044
5045 - list available log templates::
5045 - list available log templates::
5046
5046
5047 hg log -T list
5047 hg log -T list
5048
5048
5049 - check if a given changeset is included in a tagged release::
5049 - check if a given changeset is included in a tagged release::
5050
5050
5051 hg log -r "a21ccf and ancestor(1.9)"
5051 hg log -r "a21ccf and ancestor(1.9)"
5052
5052
5053 - find all changesets by some user in a date range::
5053 - find all changesets by some user in a date range::
5054
5054
5055 hg log -k alice -d "may 2008 to jul 2008"
5055 hg log -k alice -d "may 2008 to jul 2008"
5056
5056
5057 - summary of all changesets after the last tag::
5057 - summary of all changesets after the last tag::
5058
5058
5059 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
5059 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
5060
5060
5061 See :hg:`help dates` for a list of formats valid for -d/--date.
5061 See :hg:`help dates` for a list of formats valid for -d/--date.
5062
5062
5063 See :hg:`help revisions` and :hg:`help revsets` for more about
5063 See :hg:`help revisions` and :hg:`help revsets` for more about
5064 specifying and ordering revisions.
5064 specifying and ordering revisions.
5065
5065
5066 See :hg:`help templates` for more about pre-packaged styles and
5066 See :hg:`help templates` for more about pre-packaged styles and
5067 specifying custom templates.
5067 specifying custom templates.
5068
5068
5069 Returns 0 on success.
5069 Returns 0 on success.
5070
5070
5071 """
5071 """
5072 if opts.get('follow') and opts.get('rev'):
5072 if opts.get('follow') and opts.get('rev'):
5073 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
5073 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
5074 del opts['follow']
5074 del opts['follow']
5075
5075
5076 if opts.get('graph'):
5076 if opts.get('graph'):
5077 return cmdutil.graphlog(ui, repo, *pats, **opts)
5077 return cmdutil.graphlog(ui, repo, *pats, **opts)
5078
5078
5079 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
5079 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
5080 limit = cmdutil.loglimit(opts)
5080 limit = cmdutil.loglimit(opts)
5081 count = 0
5081 count = 0
5082
5082
5083 getrenamed = None
5083 getrenamed = None
5084 if opts.get('copies'):
5084 if opts.get('copies'):
5085 endrev = None
5085 endrev = None
5086 if opts.get('rev'):
5086 if opts.get('rev'):
5087 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
5087 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
5088 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
5088 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
5089
5089
5090 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5090 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5091 for rev in revs:
5091 for rev in revs:
5092 if count == limit:
5092 if count == limit:
5093 break
5093 break
5094 ctx = repo[rev]
5094 ctx = repo[rev]
5095 copies = None
5095 copies = None
5096 if getrenamed is not None and rev:
5096 if getrenamed is not None and rev:
5097 copies = []
5097 copies = []
5098 for fn in ctx.files():
5098 for fn in ctx.files():
5099 rename = getrenamed(fn, rev)
5099 rename = getrenamed(fn, rev)
5100 if rename:
5100 if rename:
5101 copies.append((fn, rename[0]))
5101 copies.append((fn, rename[0]))
5102 if filematcher:
5102 if filematcher:
5103 revmatchfn = filematcher(ctx.rev())
5103 revmatchfn = filematcher(ctx.rev())
5104 else:
5104 else:
5105 revmatchfn = None
5105 revmatchfn = None
5106 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
5106 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
5107 if displayer.flush(ctx):
5107 if displayer.flush(ctx):
5108 count += 1
5108 count += 1
5109
5109
5110 displayer.close()
5110 displayer.close()
5111
5111
5112 @command('manifest',
5112 @command('manifest',
5113 [('r', 'rev', '', _('revision to display'), _('REV')),
5113 [('r', 'rev', '', _('revision to display'), _('REV')),
5114 ('', 'all', False, _("list files from all revisions"))]
5114 ('', 'all', False, _("list files from all revisions"))]
5115 + formatteropts,
5115 + formatteropts,
5116 _('[-r REV]'))
5116 _('[-r REV]'))
5117 def manifest(ui, repo, node=None, rev=None, **opts):
5117 def manifest(ui, repo, node=None, rev=None, **opts):
5118 """output the current or given revision of the project manifest
5118 """output the current or given revision of the project manifest
5119
5119
5120 Print a list of version controlled files for the given revision.
5120 Print a list of version controlled files for the given revision.
5121 If no revision is given, the first parent of the working directory
5121 If no revision is given, the first parent of the working directory
5122 is used, or the null revision if no revision is checked out.
5122 is used, or the null revision if no revision is checked out.
5123
5123
5124 With -v, print file permissions, symlink and executable bits.
5124 With -v, print file permissions, symlink and executable bits.
5125 With --debug, print file revision hashes.
5125 With --debug, print file revision hashes.
5126
5126
5127 If option --all is specified, the list of all files from all revisions
5127 If option --all is specified, the list of all files from all revisions
5128 is printed. This includes deleted and renamed files.
5128 is printed. This includes deleted and renamed files.
5129
5129
5130 Returns 0 on success.
5130 Returns 0 on success.
5131 """
5131 """
5132
5132
5133 fm = ui.formatter('manifest', opts)
5133 fm = ui.formatter('manifest', opts)
5134
5134
5135 if opts.get('all'):
5135 if opts.get('all'):
5136 if rev or node:
5136 if rev or node:
5137 raise error.Abort(_("can't specify a revision with --all"))
5137 raise error.Abort(_("can't specify a revision with --all"))
5138
5138
5139 res = []
5139 res = []
5140 prefix = "data/"
5140 prefix = "data/"
5141 suffix = ".i"
5141 suffix = ".i"
5142 plen = len(prefix)
5142 plen = len(prefix)
5143 slen = len(suffix)
5143 slen = len(suffix)
5144 with repo.lock():
5144 with repo.lock():
5145 for fn, b, size in repo.store.datafiles():
5145 for fn, b, size in repo.store.datafiles():
5146 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
5146 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
5147 res.append(fn[plen:-slen])
5147 res.append(fn[plen:-slen])
5148 for f in res:
5148 for f in res:
5149 fm.startitem()
5149 fm.startitem()
5150 fm.write("path", '%s\n', f)
5150 fm.write("path", '%s\n', f)
5151 fm.end()
5151 fm.end()
5152 return
5152 return
5153
5153
5154 if rev and node:
5154 if rev and node:
5155 raise error.Abort(_("please specify just one revision"))
5155 raise error.Abort(_("please specify just one revision"))
5156
5156
5157 if not node:
5157 if not node:
5158 node = rev
5158 node = rev
5159
5159
5160 char = {'l': '@', 'x': '*', '': ''}
5160 char = {'l': '@', 'x': '*', '': ''}
5161 mode = {'l': '644', 'x': '755', '': '644'}
5161 mode = {'l': '644', 'x': '755', '': '644'}
5162 ctx = scmutil.revsingle(repo, node)
5162 ctx = scmutil.revsingle(repo, node)
5163 mf = ctx.manifest()
5163 mf = ctx.manifest()
5164 for f in ctx:
5164 for f in ctx:
5165 fm.startitem()
5165 fm.startitem()
5166 fl = ctx[f].flags()
5166 fl = ctx[f].flags()
5167 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
5167 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
5168 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
5168 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
5169 fm.write('path', '%s\n', f)
5169 fm.write('path', '%s\n', f)
5170 fm.end()
5170 fm.end()
5171
5171
5172 @command('^merge',
5172 @command('^merge',
5173 [('f', 'force', None,
5173 [('f', 'force', None,
5174 _('force a merge including outstanding changes (DEPRECATED)')),
5174 _('force a merge including outstanding changes (DEPRECATED)')),
5175 ('r', 'rev', '', _('revision to merge'), _('REV')),
5175 ('r', 'rev', '', _('revision to merge'), _('REV')),
5176 ('P', 'preview', None,
5176 ('P', 'preview', None,
5177 _('review revisions to merge (no merge is performed)'))
5177 _('review revisions to merge (no merge is performed)'))
5178 ] + mergetoolopts,
5178 ] + mergetoolopts,
5179 _('[-P] [-f] [[-r] REV]'))
5179 _('[-P] [-f] [[-r] REV]'))
5180 def merge(ui, repo, node=None, **opts):
5180 def merge(ui, repo, node=None, **opts):
5181 """merge another revision into working directory
5181 """merge another revision into working directory
5182
5182
5183 The current working directory is updated with all changes made in
5183 The current working directory is updated with all changes made in
5184 the requested revision since the last common predecessor revision.
5184 the requested revision since the last common predecessor revision.
5185
5185
5186 Files that changed between either parent are marked as changed for
5186 Files that changed between either parent are marked as changed for
5187 the next commit and a commit must be performed before any further
5187 the next commit and a commit must be performed before any further
5188 updates to the repository are allowed. The next commit will have
5188 updates to the repository are allowed. The next commit will have
5189 two parents.
5189 two parents.
5190
5190
5191 ``--tool`` can be used to specify the merge tool used for file
5191 ``--tool`` can be used to specify the merge tool used for file
5192 merges. It overrides the HGMERGE environment variable and your
5192 merges. It overrides the HGMERGE environment variable and your
5193 configuration files. See :hg:`help merge-tools` for options.
5193 configuration files. See :hg:`help merge-tools` for options.
5194
5194
5195 If no revision is specified, the working directory's parent is a
5195 If no revision is specified, the working directory's parent is a
5196 head revision, and the current branch contains exactly one other
5196 head revision, and the current branch contains exactly one other
5197 head, the other head is merged with by default. Otherwise, an
5197 head, the other head is merged with by default. Otherwise, an
5198 explicit revision with which to merge with must be provided.
5198 explicit revision with which to merge with must be provided.
5199
5199
5200 See :hg:`help resolve` for information on handling file conflicts.
5200 See :hg:`help resolve` for information on handling file conflicts.
5201
5201
5202 To undo an uncommitted merge, use :hg:`update --clean .` which
5202 To undo an uncommitted merge, use :hg:`update --clean .` which
5203 will check out a clean copy of the original merge parent, losing
5203 will check out a clean copy of the original merge parent, losing
5204 all changes.
5204 all changes.
5205
5205
5206 Returns 0 on success, 1 if there are unresolved files.
5206 Returns 0 on success, 1 if there are unresolved files.
5207 """
5207 """
5208
5208
5209 if opts.get('rev') and node:
5209 if opts.get('rev') and node:
5210 raise error.Abort(_("please specify just one revision"))
5210 raise error.Abort(_("please specify just one revision"))
5211 if not node:
5211 if not node:
5212 node = opts.get('rev')
5212 node = opts.get('rev')
5213
5213
5214 if node:
5214 if node:
5215 node = scmutil.revsingle(repo, node).node()
5215 node = scmutil.revsingle(repo, node).node()
5216
5216
5217 if not node:
5217 if not node:
5218 node = repo[destutil.destmerge(repo)].node()
5218 node = repo[destutil.destmerge(repo)].node()
5219
5219
5220 if opts.get('preview'):
5220 if opts.get('preview'):
5221 # find nodes that are ancestors of p2 but not of p1
5221 # find nodes that are ancestors of p2 but not of p1
5222 p1 = repo.lookup('.')
5222 p1 = repo.lookup('.')
5223 p2 = repo.lookup(node)
5223 p2 = repo.lookup(node)
5224 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
5224 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
5225
5225
5226 displayer = cmdutil.show_changeset(ui, repo, opts)
5226 displayer = cmdutil.show_changeset(ui, repo, opts)
5227 for node in nodes:
5227 for node in nodes:
5228 displayer.show(repo[node])
5228 displayer.show(repo[node])
5229 displayer.close()
5229 displayer.close()
5230 return 0
5230 return 0
5231
5231
5232 try:
5232 try:
5233 # ui.forcemerge is an internal variable, do not document
5233 # ui.forcemerge is an internal variable, do not document
5234 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
5234 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
5235 return hg.merge(repo, node, force=opts.get('force'))
5235 return hg.merge(repo, node, force=opts.get('force'))
5236 finally:
5236 finally:
5237 ui.setconfig('ui', 'forcemerge', '', 'merge')
5237 ui.setconfig('ui', 'forcemerge', '', 'merge')
5238
5238
5239 @command('outgoing|out',
5239 @command('outgoing|out',
5240 [('f', 'force', None, _('run even when the destination is unrelated')),
5240 [('f', 'force', None, _('run even when the destination is unrelated')),
5241 ('r', 'rev', [],
5241 ('r', 'rev', [],
5242 _('a changeset intended to be included in the destination'), _('REV')),
5242 _('a changeset intended to be included in the destination'), _('REV')),
5243 ('n', 'newest-first', None, _('show newest record first')),
5243 ('n', 'newest-first', None, _('show newest record first')),
5244 ('B', 'bookmarks', False, _('compare bookmarks')),
5244 ('B', 'bookmarks', False, _('compare bookmarks')),
5245 ('b', 'branch', [], _('a specific branch you would like to push'),
5245 ('b', 'branch', [], _('a specific branch you would like to push'),
5246 _('BRANCH')),
5246 _('BRANCH')),
5247 ] + logopts + remoteopts + subrepoopts,
5247 ] + logopts + remoteopts + subrepoopts,
5248 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
5248 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
5249 def outgoing(ui, repo, dest=None, **opts):
5249 def outgoing(ui, repo, dest=None, **opts):
5250 """show changesets not found in the destination
5250 """show changesets not found in the destination
5251
5251
5252 Show changesets not found in the specified destination repository
5252 Show changesets not found in the specified destination repository
5253 or the default push location. These are the changesets that would
5253 or the default push location. These are the changesets that would
5254 be pushed if a push was requested.
5254 be pushed if a push was requested.
5255
5255
5256 See pull for details of valid destination formats.
5256 See pull for details of valid destination formats.
5257
5257
5258 .. container:: verbose
5258 .. container:: verbose
5259
5259
5260 With -B/--bookmarks, the result of bookmark comparison between
5260 With -B/--bookmarks, the result of bookmark comparison between
5261 local and remote repositories is displayed. With -v/--verbose,
5261 local and remote repositories is displayed. With -v/--verbose,
5262 status is also displayed for each bookmark like below::
5262 status is also displayed for each bookmark like below::
5263
5263
5264 BM1 01234567890a added
5264 BM1 01234567890a added
5265 BM2 deleted
5265 BM2 deleted
5266 BM3 234567890abc advanced
5266 BM3 234567890abc advanced
5267 BM4 34567890abcd diverged
5267 BM4 34567890abcd diverged
5268 BM5 4567890abcde changed
5268 BM5 4567890abcde changed
5269
5269
5270 The action taken when pushing depends on the
5270 The action taken when pushing depends on the
5271 status of each bookmark:
5271 status of each bookmark:
5272
5272
5273 :``added``: push with ``-B`` will create it
5273 :``added``: push with ``-B`` will create it
5274 :``deleted``: push with ``-B`` will delete it
5274 :``deleted``: push with ``-B`` will delete it
5275 :``advanced``: push will update it
5275 :``advanced``: push will update it
5276 :``diverged``: push with ``-B`` will update it
5276 :``diverged``: push with ``-B`` will update it
5277 :``changed``: push with ``-B`` will update it
5277 :``changed``: push with ``-B`` will update it
5278
5278
5279 From the point of view of pushing behavior, bookmarks
5279 From the point of view of pushing behavior, bookmarks
5280 existing only in the remote repository are treated as
5280 existing only in the remote repository are treated as
5281 ``deleted``, even if it is in fact added remotely.
5281 ``deleted``, even if it is in fact added remotely.
5282
5282
5283 Returns 0 if there are outgoing changes, 1 otherwise.
5283 Returns 0 if there are outgoing changes, 1 otherwise.
5284 """
5284 """
5285 if opts.get('graph'):
5285 if opts.get('graph'):
5286 cmdutil.checkunsupportedgraphflags([], opts)
5286 cmdutil.checkunsupportedgraphflags([], opts)
5287 o, other = hg._outgoing(ui, repo, dest, opts)
5287 o, other = hg._outgoing(ui, repo, dest, opts)
5288 if not o:
5288 if not o:
5289 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5289 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5290 return
5290 return
5291
5291
5292 revdag = cmdutil.graphrevs(repo, o, opts)
5292 revdag = cmdutil.graphrevs(repo, o, opts)
5293 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5293 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5294 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
5294 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
5295 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5295 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5296 return 0
5296 return 0
5297
5297
5298 if opts.get('bookmarks'):
5298 if opts.get('bookmarks'):
5299 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5299 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5300 dest, branches = hg.parseurl(dest, opts.get('branch'))
5300 dest, branches = hg.parseurl(dest, opts.get('branch'))
5301 other = hg.peer(repo, opts, dest)
5301 other = hg.peer(repo, opts, dest)
5302 if 'bookmarks' not in other.listkeys('namespaces'):
5302 if 'bookmarks' not in other.listkeys('namespaces'):
5303 ui.warn(_("remote doesn't support bookmarks\n"))
5303 ui.warn(_("remote doesn't support bookmarks\n"))
5304 return 0
5304 return 0
5305 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
5305 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
5306 return bookmarks.outgoing(ui, repo, other)
5306 return bookmarks.outgoing(ui, repo, other)
5307
5307
5308 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
5308 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
5309 try:
5309 try:
5310 return hg.outgoing(ui, repo, dest, opts)
5310 return hg.outgoing(ui, repo, dest, opts)
5311 finally:
5311 finally:
5312 del repo._subtoppath
5312 del repo._subtoppath
5313
5313
5314 @command('parents',
5314 @command('parents',
5315 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
5315 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
5316 ] + templateopts,
5316 ] + templateopts,
5317 _('[-r REV] [FILE]'),
5317 _('[-r REV] [FILE]'),
5318 inferrepo=True)
5318 inferrepo=True)
5319 def parents(ui, repo, file_=None, **opts):
5319 def parents(ui, repo, file_=None, **opts):
5320 """show the parents of the working directory or revision (DEPRECATED)
5320 """show the parents of the working directory or revision (DEPRECATED)
5321
5321
5322 Print the working directory's parent revisions. If a revision is
5322 Print the working directory's parent revisions. If a revision is
5323 given via -r/--rev, the parent of that revision will be printed.
5323 given via -r/--rev, the parent of that revision will be printed.
5324 If a file argument is given, the revision in which the file was
5324 If a file argument is given, the revision in which the file was
5325 last changed (before the working directory revision or the
5325 last changed (before the working directory revision or the
5326 argument to --rev if given) is printed.
5326 argument to --rev if given) is printed.
5327
5327
5328 This command is equivalent to::
5328 This command is equivalent to::
5329
5329
5330 hg log -r "p1()+p2()" or
5330 hg log -r "p1()+p2()" or
5331 hg log -r "p1(REV)+p2(REV)" or
5331 hg log -r "p1(REV)+p2(REV)" or
5332 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5332 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5333 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5333 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5334
5334
5335 See :hg:`summary` and :hg:`help revsets` for related information.
5335 See :hg:`summary` and :hg:`help revsets` for related information.
5336
5336
5337 Returns 0 on success.
5337 Returns 0 on success.
5338 """
5338 """
5339
5339
5340 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5340 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5341
5341
5342 if file_:
5342 if file_:
5343 m = scmutil.match(ctx, (file_,), opts)
5343 m = scmutil.match(ctx, (file_,), opts)
5344 if m.anypats() or len(m.files()) != 1:
5344 if m.anypats() or len(m.files()) != 1:
5345 raise error.Abort(_('can only specify an explicit filename'))
5345 raise error.Abort(_('can only specify an explicit filename'))
5346 file_ = m.files()[0]
5346 file_ = m.files()[0]
5347 filenodes = []
5347 filenodes = []
5348 for cp in ctx.parents():
5348 for cp in ctx.parents():
5349 if not cp:
5349 if not cp:
5350 continue
5350 continue
5351 try:
5351 try:
5352 filenodes.append(cp.filenode(file_))
5352 filenodes.append(cp.filenode(file_))
5353 except error.LookupError:
5353 except error.LookupError:
5354 pass
5354 pass
5355 if not filenodes:
5355 if not filenodes:
5356 raise error.Abort(_("'%s' not found in manifest!") % file_)
5356 raise error.Abort(_("'%s' not found in manifest!") % file_)
5357 p = []
5357 p = []
5358 for fn in filenodes:
5358 for fn in filenodes:
5359 fctx = repo.filectx(file_, fileid=fn)
5359 fctx = repo.filectx(file_, fileid=fn)
5360 p.append(fctx.node())
5360 p.append(fctx.node())
5361 else:
5361 else:
5362 p = [cp.node() for cp in ctx.parents()]
5362 p = [cp.node() for cp in ctx.parents()]
5363
5363
5364 displayer = cmdutil.show_changeset(ui, repo, opts)
5364 displayer = cmdutil.show_changeset(ui, repo, opts)
5365 for n in p:
5365 for n in p:
5366 if n != nullid:
5366 if n != nullid:
5367 displayer.show(repo[n])
5367 displayer.show(repo[n])
5368 displayer.close()
5368 displayer.close()
5369
5369
5370 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
5370 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
5371 def paths(ui, repo, search=None, **opts):
5371 def paths(ui, repo, search=None, **opts):
5372 """show aliases for remote repositories
5372 """show aliases for remote repositories
5373
5373
5374 Show definition of symbolic path name NAME. If no name is given,
5374 Show definition of symbolic path name NAME. If no name is given,
5375 show definition of all available names.
5375 show definition of all available names.
5376
5376
5377 Option -q/--quiet suppresses all output when searching for NAME
5377 Option -q/--quiet suppresses all output when searching for NAME
5378 and shows only the path names when listing all definitions.
5378 and shows only the path names when listing all definitions.
5379
5379
5380 Path names are defined in the [paths] section of your
5380 Path names are defined in the [paths] section of your
5381 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5381 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5382 repository, ``.hg/hgrc`` is used, too.
5382 repository, ``.hg/hgrc`` is used, too.
5383
5383
5384 The path names ``default`` and ``default-push`` have a special
5384 The path names ``default`` and ``default-push`` have a special
5385 meaning. When performing a push or pull operation, they are used
5385 meaning. When performing a push or pull operation, they are used
5386 as fallbacks if no location is specified on the command-line.
5386 as fallbacks if no location is specified on the command-line.
5387 When ``default-push`` is set, it will be used for push and
5387 When ``default-push`` is set, it will be used for push and
5388 ``default`` will be used for pull; otherwise ``default`` is used
5388 ``default`` will be used for pull; otherwise ``default`` is used
5389 as the fallback for both. When cloning a repository, the clone
5389 as the fallback for both. When cloning a repository, the clone
5390 source is written as ``default`` in ``.hg/hgrc``.
5390 source is written as ``default`` in ``.hg/hgrc``.
5391
5391
5392 .. note::
5392 .. note::
5393
5393
5394 ``default`` and ``default-push`` apply to all inbound (e.g.
5394 ``default`` and ``default-push`` apply to all inbound (e.g.
5395 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5395 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5396 and :hg:`bundle`) operations.
5396 and :hg:`bundle`) operations.
5397
5397
5398 See :hg:`help urls` for more information.
5398 See :hg:`help urls` for more information.
5399
5399
5400 Returns 0 on success.
5400 Returns 0 on success.
5401 """
5401 """
5402 if search:
5402 if search:
5403 pathitems = [(name, path) for name, path in ui.paths.iteritems()
5403 pathitems = [(name, path) for name, path in ui.paths.iteritems()
5404 if name == search]
5404 if name == search]
5405 else:
5405 else:
5406 pathitems = sorted(ui.paths.iteritems())
5406 pathitems = sorted(ui.paths.iteritems())
5407
5407
5408 fm = ui.formatter('paths', opts)
5408 fm = ui.formatter('paths', opts)
5409 if fm:
5409 if fm:
5410 hidepassword = str
5410 hidepassword = str
5411 else:
5411 else:
5412 hidepassword = util.hidepassword
5412 hidepassword = util.hidepassword
5413 if ui.quiet:
5413 if ui.quiet:
5414 namefmt = '%s\n'
5414 namefmt = '%s\n'
5415 else:
5415 else:
5416 namefmt = '%s = '
5416 namefmt = '%s = '
5417 showsubopts = not search and not ui.quiet
5417 showsubopts = not search and not ui.quiet
5418
5418
5419 for name, path in pathitems:
5419 for name, path in pathitems:
5420 fm.startitem()
5420 fm.startitem()
5421 fm.condwrite(not search, 'name', namefmt, name)
5421 fm.condwrite(not search, 'name', namefmt, name)
5422 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
5422 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
5423 for subopt, value in sorted(path.suboptions.items()):
5423 for subopt, value in sorted(path.suboptions.items()):
5424 assert subopt not in ('name', 'url')
5424 assert subopt not in ('name', 'url')
5425 if showsubopts:
5425 if showsubopts:
5426 fm.plain('%s:%s = ' % (name, subopt))
5426 fm.plain('%s:%s = ' % (name, subopt))
5427 fm.condwrite(showsubopts, subopt, '%s\n', value)
5427 fm.condwrite(showsubopts, subopt, '%s\n', value)
5428
5428
5429 fm.end()
5429 fm.end()
5430
5430
5431 if search and not pathitems:
5431 if search and not pathitems:
5432 if not ui.quiet:
5432 if not ui.quiet:
5433 ui.warn(_("not found!\n"))
5433 ui.warn(_("not found!\n"))
5434 return 1
5434 return 1
5435 else:
5435 else:
5436 return 0
5436 return 0
5437
5437
5438 @command('phase',
5438 @command('phase',
5439 [('p', 'public', False, _('set changeset phase to public')),
5439 [('p', 'public', False, _('set changeset phase to public')),
5440 ('d', 'draft', False, _('set changeset phase to draft')),
5440 ('d', 'draft', False, _('set changeset phase to draft')),
5441 ('s', 'secret', False, _('set changeset phase to secret')),
5441 ('s', 'secret', False, _('set changeset phase to secret')),
5442 ('f', 'force', False, _('allow to move boundary backward')),
5442 ('f', 'force', False, _('allow to move boundary backward')),
5443 ('r', 'rev', [], _('target revision'), _('REV')),
5443 ('r', 'rev', [], _('target revision'), _('REV')),
5444 ],
5444 ],
5445 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5445 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5446 def phase(ui, repo, *revs, **opts):
5446 def phase(ui, repo, *revs, **opts):
5447 """set or show the current phase name
5447 """set or show the current phase name
5448
5448
5449 With no argument, show the phase name of the current revision(s).
5449 With no argument, show the phase name of the current revision(s).
5450
5450
5451 With one of -p/--public, -d/--draft or -s/--secret, change the
5451 With one of -p/--public, -d/--draft or -s/--secret, change the
5452 phase value of the specified revisions.
5452 phase value of the specified revisions.
5453
5453
5454 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
5454 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
5455 lower phase to an higher phase. Phases are ordered as follows::
5455 lower phase to an higher phase. Phases are ordered as follows::
5456
5456
5457 public < draft < secret
5457 public < draft < secret
5458
5458
5459 Returns 0 on success, 1 if some phases could not be changed.
5459 Returns 0 on success, 1 if some phases could not be changed.
5460
5460
5461 (For more information about the phases concept, see :hg:`help phases`.)
5461 (For more information about the phases concept, see :hg:`help phases`.)
5462 """
5462 """
5463 # search for a unique phase argument
5463 # search for a unique phase argument
5464 targetphase = None
5464 targetphase = None
5465 for idx, name in enumerate(phases.phasenames):
5465 for idx, name in enumerate(phases.phasenames):
5466 if opts[name]:
5466 if opts[name]:
5467 if targetphase is not None:
5467 if targetphase is not None:
5468 raise error.Abort(_('only one phase can be specified'))
5468 raise error.Abort(_('only one phase can be specified'))
5469 targetphase = idx
5469 targetphase = idx
5470
5470
5471 # look for specified revision
5471 # look for specified revision
5472 revs = list(revs)
5472 revs = list(revs)
5473 revs.extend(opts['rev'])
5473 revs.extend(opts['rev'])
5474 if not revs:
5474 if not revs:
5475 # display both parents as the second parent phase can influence
5475 # display both parents as the second parent phase can influence
5476 # the phase of a merge commit
5476 # the phase of a merge commit
5477 revs = [c.rev() for c in repo[None].parents()]
5477 revs = [c.rev() for c in repo[None].parents()]
5478
5478
5479 revs = scmutil.revrange(repo, revs)
5479 revs = scmutil.revrange(repo, revs)
5480
5480
5481 lock = None
5481 lock = None
5482 ret = 0
5482 ret = 0
5483 if targetphase is None:
5483 if targetphase is None:
5484 # display
5484 # display
5485 for r in revs:
5485 for r in revs:
5486 ctx = repo[r]
5486 ctx = repo[r]
5487 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5487 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5488 else:
5488 else:
5489 tr = None
5489 tr = None
5490 lock = repo.lock()
5490 lock = repo.lock()
5491 try:
5491 try:
5492 tr = repo.transaction("phase")
5492 tr = repo.transaction("phase")
5493 # set phase
5493 # set phase
5494 if not revs:
5494 if not revs:
5495 raise error.Abort(_('empty revision set'))
5495 raise error.Abort(_('empty revision set'))
5496 nodes = [repo[r].node() for r in revs]
5496 nodes = [repo[r].node() for r in revs]
5497 # moving revision from public to draft may hide them
5497 # moving revision from public to draft may hide them
5498 # We have to check result on an unfiltered repository
5498 # We have to check result on an unfiltered repository
5499 unfi = repo.unfiltered()
5499 unfi = repo.unfiltered()
5500 getphase = unfi._phasecache.phase
5500 getphase = unfi._phasecache.phase
5501 olddata = [getphase(unfi, r) for r in unfi]
5501 olddata = [getphase(unfi, r) for r in unfi]
5502 phases.advanceboundary(repo, tr, targetphase, nodes)
5502 phases.advanceboundary(repo, tr, targetphase, nodes)
5503 if opts['force']:
5503 if opts['force']:
5504 phases.retractboundary(repo, tr, targetphase, nodes)
5504 phases.retractboundary(repo, tr, targetphase, nodes)
5505 tr.close()
5505 tr.close()
5506 finally:
5506 finally:
5507 if tr is not None:
5507 if tr is not None:
5508 tr.release()
5508 tr.release()
5509 lock.release()
5509 lock.release()
5510 getphase = unfi._phasecache.phase
5510 getphase = unfi._phasecache.phase
5511 newdata = [getphase(unfi, r) for r in unfi]
5511 newdata = [getphase(unfi, r) for r in unfi]
5512 changes = sum(newdata[r] != olddata[r] for r in unfi)
5512 changes = sum(newdata[r] != olddata[r] for r in unfi)
5513 cl = unfi.changelog
5513 cl = unfi.changelog
5514 rejected = [n for n in nodes
5514 rejected = [n for n in nodes
5515 if newdata[cl.rev(n)] < targetphase]
5515 if newdata[cl.rev(n)] < targetphase]
5516 if rejected:
5516 if rejected:
5517 ui.warn(_('cannot move %i changesets to a higher '
5517 ui.warn(_('cannot move %i changesets to a higher '
5518 'phase, use --force\n') % len(rejected))
5518 'phase, use --force\n') % len(rejected))
5519 ret = 1
5519 ret = 1
5520 if changes:
5520 if changes:
5521 msg = _('phase changed for %i changesets\n') % changes
5521 msg = _('phase changed for %i changesets\n') % changes
5522 if ret:
5522 if ret:
5523 ui.status(msg)
5523 ui.status(msg)
5524 else:
5524 else:
5525 ui.note(msg)
5525 ui.note(msg)
5526 else:
5526 else:
5527 ui.warn(_('no phases changed\n'))
5527 ui.warn(_('no phases changed\n'))
5528 return ret
5528 return ret
5529
5529
5530 def postincoming(ui, repo, modheads, optupdate, checkout):
5530 def postincoming(ui, repo, modheads, optupdate, checkout):
5531 if modheads == 0:
5531 if modheads == 0:
5532 return
5532 return
5533 if optupdate:
5533 if optupdate:
5534 try:
5534 try:
5535 brev = checkout
5535 brev = checkout
5536 movemarkfrom = None
5536 movemarkfrom = None
5537 if not checkout:
5537 if not checkout:
5538 updata = destutil.destupdate(repo)
5538 updata = destutil.destupdate(repo)
5539 checkout, movemarkfrom, brev = updata
5539 checkout, movemarkfrom, brev = updata
5540 ret = hg.update(repo, checkout)
5540 ret = hg.update(repo, checkout)
5541 except error.UpdateAbort as inst:
5541 except error.UpdateAbort as inst:
5542 msg = _("not updating: %s") % str(inst)
5542 msg = _("not updating: %s") % str(inst)
5543 hint = inst.hint
5543 hint = inst.hint
5544 raise error.UpdateAbort(msg, hint=hint)
5544 raise error.UpdateAbort(msg, hint=hint)
5545 if not ret and not checkout:
5545 if not ret and movemarkfrom:
5546 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5546 if movemarkfrom == repo['.'].node():
5547 pass # no-op update
5548 elif bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5547 ui.status(_("updating bookmark %s\n") % repo._activebookmark)
5549 ui.status(_("updating bookmark %s\n") % repo._activebookmark)
5548 return ret
5550 return ret
5549 if modheads > 1:
5551 if modheads > 1:
5550 currentbranchheads = len(repo.branchheads())
5552 currentbranchheads = len(repo.branchheads())
5551 if currentbranchheads == modheads:
5553 if currentbranchheads == modheads:
5552 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5554 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5553 elif currentbranchheads > 1:
5555 elif currentbranchheads > 1:
5554 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5556 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5555 "merge)\n"))
5557 "merge)\n"))
5556 else:
5558 else:
5557 ui.status(_("(run 'hg heads' to see heads)\n"))
5559 ui.status(_("(run 'hg heads' to see heads)\n"))
5558 else:
5560 else:
5559 ui.status(_("(run 'hg update' to get a working copy)\n"))
5561 ui.status(_("(run 'hg update' to get a working copy)\n"))
5560
5562
5561 @command('^pull',
5563 @command('^pull',
5562 [('u', 'update', None,
5564 [('u', 'update', None,
5563 _('update to new branch head if changesets were pulled')),
5565 _('update to new branch head if changesets were pulled')),
5564 ('f', 'force', None, _('run even when remote repository is unrelated')),
5566 ('f', 'force', None, _('run even when remote repository is unrelated')),
5565 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5567 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5566 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5568 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5567 ('b', 'branch', [], _('a specific branch you would like to pull'),
5569 ('b', 'branch', [], _('a specific branch you would like to pull'),
5568 _('BRANCH')),
5570 _('BRANCH')),
5569 ] + remoteopts,
5571 ] + remoteopts,
5570 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5572 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5571 def pull(ui, repo, source="default", **opts):
5573 def pull(ui, repo, source="default", **opts):
5572 """pull changes from the specified source
5574 """pull changes from the specified source
5573
5575
5574 Pull changes from a remote repository to a local one.
5576 Pull changes from a remote repository to a local one.
5575
5577
5576 This finds all changes from the repository at the specified path
5578 This finds all changes from the repository at the specified path
5577 or URL and adds them to a local repository (the current one unless
5579 or URL and adds them to a local repository (the current one unless
5578 -R is specified). By default, this does not update the copy of the
5580 -R is specified). By default, this does not update the copy of the
5579 project in the working directory.
5581 project in the working directory.
5580
5582
5581 Use :hg:`incoming` if you want to see what would have been added
5583 Use :hg:`incoming` if you want to see what would have been added
5582 by a pull at the time you issued this command. If you then decide
5584 by a pull at the time you issued this command. If you then decide
5583 to add those changes to the repository, you should use :hg:`pull
5585 to add those changes to the repository, you should use :hg:`pull
5584 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5586 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5585
5587
5586 If SOURCE is omitted, the 'default' path will be used.
5588 If SOURCE is omitted, the 'default' path will be used.
5587 See :hg:`help urls` for more information.
5589 See :hg:`help urls` for more information.
5588
5590
5589 Returns 0 on success, 1 if an update had unresolved files.
5591 Returns 0 on success, 1 if an update had unresolved files.
5590 """
5592 """
5591 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5593 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5592 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5594 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5593 other = hg.peer(repo, opts, source)
5595 other = hg.peer(repo, opts, source)
5594 try:
5596 try:
5595 revs, checkout = hg.addbranchrevs(repo, other, branches,
5597 revs, checkout = hg.addbranchrevs(repo, other, branches,
5596 opts.get('rev'))
5598 opts.get('rev'))
5597
5599
5598
5600
5599 pullopargs = {}
5601 pullopargs = {}
5600 if opts.get('bookmark'):
5602 if opts.get('bookmark'):
5601 if not revs:
5603 if not revs:
5602 revs = []
5604 revs = []
5603 # The list of bookmark used here is not the one used to actually
5605 # The list of bookmark used here is not the one used to actually
5604 # update the bookmark name. This can result in the revision pulled
5606 # update the bookmark name. This can result in the revision pulled
5605 # not ending up with the name of the bookmark because of a race
5607 # not ending up with the name of the bookmark because of a race
5606 # condition on the server. (See issue 4689 for details)
5608 # condition on the server. (See issue 4689 for details)
5607 remotebookmarks = other.listkeys('bookmarks')
5609 remotebookmarks = other.listkeys('bookmarks')
5608 pullopargs['remotebookmarks'] = remotebookmarks
5610 pullopargs['remotebookmarks'] = remotebookmarks
5609 for b in opts['bookmark']:
5611 for b in opts['bookmark']:
5610 if b not in remotebookmarks:
5612 if b not in remotebookmarks:
5611 raise error.Abort(_('remote bookmark %s not found!') % b)
5613 raise error.Abort(_('remote bookmark %s not found!') % b)
5612 revs.append(remotebookmarks[b])
5614 revs.append(remotebookmarks[b])
5613
5615
5614 if revs:
5616 if revs:
5615 try:
5617 try:
5616 # When 'rev' is a bookmark name, we cannot guarantee that it
5618 # When 'rev' is a bookmark name, we cannot guarantee that it
5617 # will be updated with that name because of a race condition
5619 # will be updated with that name because of a race condition
5618 # server side. (See issue 4689 for details)
5620 # server side. (See issue 4689 for details)
5619 oldrevs = revs
5621 oldrevs = revs
5620 revs = [] # actually, nodes
5622 revs = [] # actually, nodes
5621 for r in oldrevs:
5623 for r in oldrevs:
5622 node = other.lookup(r)
5624 node = other.lookup(r)
5623 revs.append(node)
5625 revs.append(node)
5624 if r == checkout:
5626 if r == checkout:
5625 checkout = node
5627 checkout = node
5626 except error.CapabilityError:
5628 except error.CapabilityError:
5627 err = _("other repository doesn't support revision lookup, "
5629 err = _("other repository doesn't support revision lookup, "
5628 "so a rev cannot be specified.")
5630 "so a rev cannot be specified.")
5629 raise error.Abort(err)
5631 raise error.Abort(err)
5630
5632
5631 pullopargs.update(opts.get('opargs', {}))
5633 pullopargs.update(opts.get('opargs', {}))
5632 modheads = exchange.pull(repo, other, heads=revs,
5634 modheads = exchange.pull(repo, other, heads=revs,
5633 force=opts.get('force'),
5635 force=opts.get('force'),
5634 bookmarks=opts.get('bookmark', ()),
5636 bookmarks=opts.get('bookmark', ()),
5635 opargs=pullopargs).cgresult
5637 opargs=pullopargs).cgresult
5636 if checkout:
5638 if checkout:
5637 checkout = str(repo.changelog.rev(checkout))
5639 checkout = str(repo.changelog.rev(checkout))
5638 repo._subtoppath = source
5640 repo._subtoppath = source
5639 try:
5641 try:
5640 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
5642 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
5641
5643
5642 finally:
5644 finally:
5643 del repo._subtoppath
5645 del repo._subtoppath
5644
5646
5645 finally:
5647 finally:
5646 other.close()
5648 other.close()
5647 return ret
5649 return ret
5648
5650
5649 @command('^push',
5651 @command('^push',
5650 [('f', 'force', None, _('force push')),
5652 [('f', 'force', None, _('force push')),
5651 ('r', 'rev', [],
5653 ('r', 'rev', [],
5652 _('a changeset intended to be included in the destination'),
5654 _('a changeset intended to be included in the destination'),
5653 _('REV')),
5655 _('REV')),
5654 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5656 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5655 ('b', 'branch', [],
5657 ('b', 'branch', [],
5656 _('a specific branch you would like to push'), _('BRANCH')),
5658 _('a specific branch you would like to push'), _('BRANCH')),
5657 ('', 'new-branch', False, _('allow pushing a new branch')),
5659 ('', 'new-branch', False, _('allow pushing a new branch')),
5658 ] + remoteopts,
5660 ] + remoteopts,
5659 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5661 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5660 def push(ui, repo, dest=None, **opts):
5662 def push(ui, repo, dest=None, **opts):
5661 """push changes to the specified destination
5663 """push changes to the specified destination
5662
5664
5663 Push changesets from the local repository to the specified
5665 Push changesets from the local repository to the specified
5664 destination.
5666 destination.
5665
5667
5666 This operation is symmetrical to pull: it is identical to a pull
5668 This operation is symmetrical to pull: it is identical to a pull
5667 in the destination repository from the current one.
5669 in the destination repository from the current one.
5668
5670
5669 By default, push will not allow creation of new heads at the
5671 By default, push will not allow creation of new heads at the
5670 destination, since multiple heads would make it unclear which head
5672 destination, since multiple heads would make it unclear which head
5671 to use. In this situation, it is recommended to pull and merge
5673 to use. In this situation, it is recommended to pull and merge
5672 before pushing.
5674 before pushing.
5673
5675
5674 Use --new-branch if you want to allow push to create a new named
5676 Use --new-branch if you want to allow push to create a new named
5675 branch that is not present at the destination. This allows you to
5677 branch that is not present at the destination. This allows you to
5676 only create a new branch without forcing other changes.
5678 only create a new branch without forcing other changes.
5677
5679
5678 .. note::
5680 .. note::
5679
5681
5680 Extra care should be taken with the -f/--force option,
5682 Extra care should be taken with the -f/--force option,
5681 which will push all new heads on all branches, an action which will
5683 which will push all new heads on all branches, an action which will
5682 almost always cause confusion for collaborators.
5684 almost always cause confusion for collaborators.
5683
5685
5684 If -r/--rev is used, the specified revision and all its ancestors
5686 If -r/--rev is used, the specified revision and all its ancestors
5685 will be pushed to the remote repository.
5687 will be pushed to the remote repository.
5686
5688
5687 If -B/--bookmark is used, the specified bookmarked revision, its
5689 If -B/--bookmark is used, the specified bookmarked revision, its
5688 ancestors, and the bookmark will be pushed to the remote
5690 ancestors, and the bookmark will be pushed to the remote
5689 repository.
5691 repository.
5690
5692
5691 Please see :hg:`help urls` for important details about ``ssh://``
5693 Please see :hg:`help urls` for important details about ``ssh://``
5692 URLs. If DESTINATION is omitted, a default path will be used.
5694 URLs. If DESTINATION is omitted, a default path will be used.
5693
5695
5694 Returns 0 if push was successful, 1 if nothing to push.
5696 Returns 0 if push was successful, 1 if nothing to push.
5695 """
5697 """
5696
5698
5697 if opts.get('bookmark'):
5699 if opts.get('bookmark'):
5698 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5700 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5699 for b in opts['bookmark']:
5701 for b in opts['bookmark']:
5700 # translate -B options to -r so changesets get pushed
5702 # translate -B options to -r so changesets get pushed
5701 if b in repo._bookmarks:
5703 if b in repo._bookmarks:
5702 opts.setdefault('rev', []).append(b)
5704 opts.setdefault('rev', []).append(b)
5703 else:
5705 else:
5704 # if we try to push a deleted bookmark, translate it to null
5706 # if we try to push a deleted bookmark, translate it to null
5705 # this lets simultaneous -r, -b options continue working
5707 # this lets simultaneous -r, -b options continue working
5706 opts.setdefault('rev', []).append("null")
5708 opts.setdefault('rev', []).append("null")
5707
5709
5708 path = ui.paths.getpath(dest, default=('default-push', 'default'))
5710 path = ui.paths.getpath(dest, default=('default-push', 'default'))
5709 if not path:
5711 if not path:
5710 raise error.Abort(_('default repository not configured!'),
5712 raise error.Abort(_('default repository not configured!'),
5711 hint=_('see the "path" section in "hg help config"'))
5713 hint=_('see the "path" section in "hg help config"'))
5712 dest = path.pushloc or path.loc
5714 dest = path.pushloc or path.loc
5713 branches = (path.branch, opts.get('branch') or [])
5715 branches = (path.branch, opts.get('branch') or [])
5714 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5716 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5715 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5717 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5716 other = hg.peer(repo, opts, dest)
5718 other = hg.peer(repo, opts, dest)
5717
5719
5718 if revs:
5720 if revs:
5719 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5721 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5720 if not revs:
5722 if not revs:
5721 raise error.Abort(_("specified revisions evaluate to an empty set"),
5723 raise error.Abort(_("specified revisions evaluate to an empty set"),
5722 hint=_("use different revision arguments"))
5724 hint=_("use different revision arguments"))
5723
5725
5724 repo._subtoppath = dest
5726 repo._subtoppath = dest
5725 try:
5727 try:
5726 # push subrepos depth-first for coherent ordering
5728 # push subrepos depth-first for coherent ordering
5727 c = repo['']
5729 c = repo['']
5728 subs = c.substate # only repos that are committed
5730 subs = c.substate # only repos that are committed
5729 for s in sorted(subs):
5731 for s in sorted(subs):
5730 result = c.sub(s).push(opts)
5732 result = c.sub(s).push(opts)
5731 if result == 0:
5733 if result == 0:
5732 return not result
5734 return not result
5733 finally:
5735 finally:
5734 del repo._subtoppath
5736 del repo._subtoppath
5735 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5737 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5736 newbranch=opts.get('new_branch'),
5738 newbranch=opts.get('new_branch'),
5737 bookmarks=opts.get('bookmark', ()),
5739 bookmarks=opts.get('bookmark', ()),
5738 opargs=opts.get('opargs'))
5740 opargs=opts.get('opargs'))
5739
5741
5740 result = not pushop.cgresult
5742 result = not pushop.cgresult
5741
5743
5742 if pushop.bkresult is not None:
5744 if pushop.bkresult is not None:
5743 if pushop.bkresult == 2:
5745 if pushop.bkresult == 2:
5744 result = 2
5746 result = 2
5745 elif not result and pushop.bkresult:
5747 elif not result and pushop.bkresult:
5746 result = 2
5748 result = 2
5747
5749
5748 return result
5750 return result
5749
5751
5750 @command('recover', [])
5752 @command('recover', [])
5751 def recover(ui, repo):
5753 def recover(ui, repo):
5752 """roll back an interrupted transaction
5754 """roll back an interrupted transaction
5753
5755
5754 Recover from an interrupted commit or pull.
5756 Recover from an interrupted commit or pull.
5755
5757
5756 This command tries to fix the repository status after an
5758 This command tries to fix the repository status after an
5757 interrupted operation. It should only be necessary when Mercurial
5759 interrupted operation. It should only be necessary when Mercurial
5758 suggests it.
5760 suggests it.
5759
5761
5760 Returns 0 if successful, 1 if nothing to recover or verify fails.
5762 Returns 0 if successful, 1 if nothing to recover or verify fails.
5761 """
5763 """
5762 if repo.recover():
5764 if repo.recover():
5763 return hg.verify(repo)
5765 return hg.verify(repo)
5764 return 1
5766 return 1
5765
5767
5766 @command('^remove|rm',
5768 @command('^remove|rm',
5767 [('A', 'after', None, _('record delete for missing files')),
5769 [('A', 'after', None, _('record delete for missing files')),
5768 ('f', 'force', None,
5770 ('f', 'force', None,
5769 _('remove (and delete) file even if added or modified')),
5771 _('remove (and delete) file even if added or modified')),
5770 ] + subrepoopts + walkopts,
5772 ] + subrepoopts + walkopts,
5771 _('[OPTION]... FILE...'),
5773 _('[OPTION]... FILE...'),
5772 inferrepo=True)
5774 inferrepo=True)
5773 def remove(ui, repo, *pats, **opts):
5775 def remove(ui, repo, *pats, **opts):
5774 """remove the specified files on the next commit
5776 """remove the specified files on the next commit
5775
5777
5776 Schedule the indicated files for removal from the current branch.
5778 Schedule the indicated files for removal from the current branch.
5777
5779
5778 This command schedules the files to be removed at the next commit.
5780 This command schedules the files to be removed at the next commit.
5779 To undo a remove before that, see :hg:`revert`. To undo added
5781 To undo a remove before that, see :hg:`revert`. To undo added
5780 files, see :hg:`forget`.
5782 files, see :hg:`forget`.
5781
5783
5782 .. container:: verbose
5784 .. container:: verbose
5783
5785
5784 -A/--after can be used to remove only files that have already
5786 -A/--after can be used to remove only files that have already
5785 been deleted, -f/--force can be used to force deletion, and -Af
5787 been deleted, -f/--force can be used to force deletion, and -Af
5786 can be used to remove files from the next revision without
5788 can be used to remove files from the next revision without
5787 deleting them from the working directory.
5789 deleting them from the working directory.
5788
5790
5789 The following table details the behavior of remove for different
5791 The following table details the behavior of remove for different
5790 file states (columns) and option combinations (rows). The file
5792 file states (columns) and option combinations (rows). The file
5791 states are Added [A], Clean [C], Modified [M] and Missing [!]
5793 states are Added [A], Clean [C], Modified [M] and Missing [!]
5792 (as reported by :hg:`status`). The actions are Warn, Remove
5794 (as reported by :hg:`status`). The actions are Warn, Remove
5793 (from branch) and Delete (from disk):
5795 (from branch) and Delete (from disk):
5794
5796
5795 ========= == == == ==
5797 ========= == == == ==
5796 opt/state A C M !
5798 opt/state A C M !
5797 ========= == == == ==
5799 ========= == == == ==
5798 none W RD W R
5800 none W RD W R
5799 -f R RD RD R
5801 -f R RD RD R
5800 -A W W W R
5802 -A W W W R
5801 -Af R R R R
5803 -Af R R R R
5802 ========= == == == ==
5804 ========= == == == ==
5803
5805
5804 .. note::
5806 .. note::
5805
5807
5806 :hg:`remove` never deletes files in Added [A] state from the
5808 :hg:`remove` never deletes files in Added [A] state from the
5807 working directory, not even if ``--force`` is specified.
5809 working directory, not even if ``--force`` is specified.
5808
5810
5809 Returns 0 on success, 1 if any warnings encountered.
5811 Returns 0 on success, 1 if any warnings encountered.
5810 """
5812 """
5811
5813
5812 after, force = opts.get('after'), opts.get('force')
5814 after, force = opts.get('after'), opts.get('force')
5813 if not pats and not after:
5815 if not pats and not after:
5814 raise error.Abort(_('no files specified'))
5816 raise error.Abort(_('no files specified'))
5815
5817
5816 m = scmutil.match(repo[None], pats, opts)
5818 m = scmutil.match(repo[None], pats, opts)
5817 subrepos = opts.get('subrepos')
5819 subrepos = opts.get('subrepos')
5818 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5820 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5819
5821
5820 @command('rename|move|mv',
5822 @command('rename|move|mv',
5821 [('A', 'after', None, _('record a rename that has already occurred')),
5823 [('A', 'after', None, _('record a rename that has already occurred')),
5822 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5824 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5823 ] + walkopts + dryrunopts,
5825 ] + walkopts + dryrunopts,
5824 _('[OPTION]... SOURCE... DEST'))
5826 _('[OPTION]... SOURCE... DEST'))
5825 def rename(ui, repo, *pats, **opts):
5827 def rename(ui, repo, *pats, **opts):
5826 """rename files; equivalent of copy + remove
5828 """rename files; equivalent of copy + remove
5827
5829
5828 Mark dest as copies of sources; mark sources for deletion. If dest
5830 Mark dest as copies of sources; mark sources for deletion. If dest
5829 is a directory, copies are put in that directory. If dest is a
5831 is a directory, copies are put in that directory. If dest is a
5830 file, there can only be one source.
5832 file, there can only be one source.
5831
5833
5832 By default, this command copies the contents of files as they
5834 By default, this command copies the contents of files as they
5833 exist in the working directory. If invoked with -A/--after, the
5835 exist in the working directory. If invoked with -A/--after, the
5834 operation is recorded, but no copying is performed.
5836 operation is recorded, but no copying is performed.
5835
5837
5836 This command takes effect at the next commit. To undo a rename
5838 This command takes effect at the next commit. To undo a rename
5837 before that, see :hg:`revert`.
5839 before that, see :hg:`revert`.
5838
5840
5839 Returns 0 on success, 1 if errors are encountered.
5841 Returns 0 on success, 1 if errors are encountered.
5840 """
5842 """
5841 with repo.wlock(False):
5843 with repo.wlock(False):
5842 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5844 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5843
5845
5844 @command('resolve',
5846 @command('resolve',
5845 [('a', 'all', None, _('select all unresolved files')),
5847 [('a', 'all', None, _('select all unresolved files')),
5846 ('l', 'list', None, _('list state of files needing merge')),
5848 ('l', 'list', None, _('list state of files needing merge')),
5847 ('m', 'mark', None, _('mark files as resolved')),
5849 ('m', 'mark', None, _('mark files as resolved')),
5848 ('u', 'unmark', None, _('mark files as unresolved')),
5850 ('u', 'unmark', None, _('mark files as unresolved')),
5849 ('n', 'no-status', None, _('hide status prefix'))]
5851 ('n', 'no-status', None, _('hide status prefix'))]
5850 + mergetoolopts + walkopts + formatteropts,
5852 + mergetoolopts + walkopts + formatteropts,
5851 _('[OPTION]... [FILE]...'),
5853 _('[OPTION]... [FILE]...'),
5852 inferrepo=True)
5854 inferrepo=True)
5853 def resolve(ui, repo, *pats, **opts):
5855 def resolve(ui, repo, *pats, **opts):
5854 """redo merges or set/view the merge status of files
5856 """redo merges or set/view the merge status of files
5855
5857
5856 Merges with unresolved conflicts are often the result of
5858 Merges with unresolved conflicts are often the result of
5857 non-interactive merging using the ``internal:merge`` configuration
5859 non-interactive merging using the ``internal:merge`` configuration
5858 setting, or a command-line merge tool like ``diff3``. The resolve
5860 setting, or a command-line merge tool like ``diff3``. The resolve
5859 command is used to manage the files involved in a merge, after
5861 command is used to manage the files involved in a merge, after
5860 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5862 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5861 working directory must have two parents). See :hg:`help
5863 working directory must have two parents). See :hg:`help
5862 merge-tools` for information on configuring merge tools.
5864 merge-tools` for information on configuring merge tools.
5863
5865
5864 The resolve command can be used in the following ways:
5866 The resolve command can be used in the following ways:
5865
5867
5866 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5868 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5867 files, discarding any previous merge attempts. Re-merging is not
5869 files, discarding any previous merge attempts. Re-merging is not
5868 performed for files already marked as resolved. Use ``--all/-a``
5870 performed for files already marked as resolved. Use ``--all/-a``
5869 to select all unresolved files. ``--tool`` can be used to specify
5871 to select all unresolved files. ``--tool`` can be used to specify
5870 the merge tool used for the given files. It overrides the HGMERGE
5872 the merge tool used for the given files. It overrides the HGMERGE
5871 environment variable and your configuration files. Previous file
5873 environment variable and your configuration files. Previous file
5872 contents are saved with a ``.orig`` suffix.
5874 contents are saved with a ``.orig`` suffix.
5873
5875
5874 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5876 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5875 (e.g. after having manually fixed-up the files). The default is
5877 (e.g. after having manually fixed-up the files). The default is
5876 to mark all unresolved files.
5878 to mark all unresolved files.
5877
5879
5878 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5880 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5879 default is to mark all resolved files.
5881 default is to mark all resolved files.
5880
5882
5881 - :hg:`resolve -l`: list files which had or still have conflicts.
5883 - :hg:`resolve -l`: list files which had or still have conflicts.
5882 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5884 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5883
5885
5884 .. note::
5886 .. note::
5885
5887
5886 Mercurial will not let you commit files with unresolved merge
5888 Mercurial will not let you commit files with unresolved merge
5887 conflicts. You must use :hg:`resolve -m ...` before you can
5889 conflicts. You must use :hg:`resolve -m ...` before you can
5888 commit after a conflicting merge.
5890 commit after a conflicting merge.
5889
5891
5890 Returns 0 on success, 1 if any files fail a resolve attempt.
5892 Returns 0 on success, 1 if any files fail a resolve attempt.
5891 """
5893 """
5892
5894
5893 all, mark, unmark, show, nostatus = \
5895 all, mark, unmark, show, nostatus = \
5894 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5896 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5895
5897
5896 if (show and (mark or unmark)) or (mark and unmark):
5898 if (show and (mark or unmark)) or (mark and unmark):
5897 raise error.Abort(_("too many options specified"))
5899 raise error.Abort(_("too many options specified"))
5898 if pats and all:
5900 if pats and all:
5899 raise error.Abort(_("can't specify --all and patterns"))
5901 raise error.Abort(_("can't specify --all and patterns"))
5900 if not (all or pats or show or mark or unmark):
5902 if not (all or pats or show or mark or unmark):
5901 raise error.Abort(_('no files or directories specified'),
5903 raise error.Abort(_('no files or directories specified'),
5902 hint=('use --all to re-merge all unresolved files'))
5904 hint=('use --all to re-merge all unresolved files'))
5903
5905
5904 if show:
5906 if show:
5905 fm = ui.formatter('resolve', opts)
5907 fm = ui.formatter('resolve', opts)
5906 ms = mergemod.mergestate.read(repo)
5908 ms = mergemod.mergestate.read(repo)
5907 m = scmutil.match(repo[None], pats, opts)
5909 m = scmutil.match(repo[None], pats, opts)
5908 for f in ms:
5910 for f in ms:
5909 if not m(f):
5911 if not m(f):
5910 continue
5912 continue
5911 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
5913 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
5912 'd': 'driverresolved'}[ms[f]]
5914 'd': 'driverresolved'}[ms[f]]
5913 fm.startitem()
5915 fm.startitem()
5914 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
5916 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
5915 fm.write('path', '%s\n', f, label=l)
5917 fm.write('path', '%s\n', f, label=l)
5916 fm.end()
5918 fm.end()
5917 return 0
5919 return 0
5918
5920
5919 with repo.wlock():
5921 with repo.wlock():
5920 ms = mergemod.mergestate.read(repo)
5922 ms = mergemod.mergestate.read(repo)
5921
5923
5922 if not (ms.active() or repo.dirstate.p2() != nullid):
5924 if not (ms.active() or repo.dirstate.p2() != nullid):
5923 raise error.Abort(
5925 raise error.Abort(
5924 _('resolve command not applicable when not merging'))
5926 _('resolve command not applicable when not merging'))
5925
5927
5926 wctx = repo[None]
5928 wctx = repo[None]
5927
5929
5928 if ms.mergedriver and ms.mdstate() == 'u':
5930 if ms.mergedriver and ms.mdstate() == 'u':
5929 proceed = mergemod.driverpreprocess(repo, ms, wctx)
5931 proceed = mergemod.driverpreprocess(repo, ms, wctx)
5930 ms.commit()
5932 ms.commit()
5931 # allow mark and unmark to go through
5933 # allow mark and unmark to go through
5932 if not mark and not unmark and not proceed:
5934 if not mark and not unmark and not proceed:
5933 return 1
5935 return 1
5934
5936
5935 m = scmutil.match(wctx, pats, opts)
5937 m = scmutil.match(wctx, pats, opts)
5936 ret = 0
5938 ret = 0
5937 didwork = False
5939 didwork = False
5938 runconclude = False
5940 runconclude = False
5939
5941
5940 tocomplete = []
5942 tocomplete = []
5941 for f in ms:
5943 for f in ms:
5942 if not m(f):
5944 if not m(f):
5943 continue
5945 continue
5944
5946
5945 didwork = True
5947 didwork = True
5946
5948
5947 # don't let driver-resolved files be marked, and run the conclude
5949 # don't let driver-resolved files be marked, and run the conclude
5948 # step if asked to resolve
5950 # step if asked to resolve
5949 if ms[f] == "d":
5951 if ms[f] == "d":
5950 exact = m.exact(f)
5952 exact = m.exact(f)
5951 if mark:
5953 if mark:
5952 if exact:
5954 if exact:
5953 ui.warn(_('not marking %s as it is driver-resolved\n')
5955 ui.warn(_('not marking %s as it is driver-resolved\n')
5954 % f)
5956 % f)
5955 elif unmark:
5957 elif unmark:
5956 if exact:
5958 if exact:
5957 ui.warn(_('not unmarking %s as it is driver-resolved\n')
5959 ui.warn(_('not unmarking %s as it is driver-resolved\n')
5958 % f)
5960 % f)
5959 else:
5961 else:
5960 runconclude = True
5962 runconclude = True
5961 continue
5963 continue
5962
5964
5963 if mark:
5965 if mark:
5964 ms.mark(f, "r")
5966 ms.mark(f, "r")
5965 elif unmark:
5967 elif unmark:
5966 ms.mark(f, "u")
5968 ms.mark(f, "u")
5967 else:
5969 else:
5968 # backup pre-resolve (merge uses .orig for its own purposes)
5970 # backup pre-resolve (merge uses .orig for its own purposes)
5969 a = repo.wjoin(f)
5971 a = repo.wjoin(f)
5970 try:
5972 try:
5971 util.copyfile(a, a + ".resolve")
5973 util.copyfile(a, a + ".resolve")
5972 except (IOError, OSError) as inst:
5974 except (IOError, OSError) as inst:
5973 if inst.errno != errno.ENOENT:
5975 if inst.errno != errno.ENOENT:
5974 raise
5976 raise
5975
5977
5976 try:
5978 try:
5977 # preresolve file
5979 # preresolve file
5978 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5980 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5979 'resolve')
5981 'resolve')
5980 complete, r = ms.preresolve(f, wctx)
5982 complete, r = ms.preresolve(f, wctx)
5981 if not complete:
5983 if not complete:
5982 tocomplete.append(f)
5984 tocomplete.append(f)
5983 elif r:
5985 elif r:
5984 ret = 1
5986 ret = 1
5985 finally:
5987 finally:
5986 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5988 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5987 ms.commit()
5989 ms.commit()
5988
5990
5989 # replace filemerge's .orig file with our resolve file, but only
5991 # replace filemerge's .orig file with our resolve file, but only
5990 # for merges that are complete
5992 # for merges that are complete
5991 if complete:
5993 if complete:
5992 try:
5994 try:
5993 util.rename(a + ".resolve",
5995 util.rename(a + ".resolve",
5994 scmutil.origpath(ui, repo, a))
5996 scmutil.origpath(ui, repo, a))
5995 except OSError as inst:
5997 except OSError as inst:
5996 if inst.errno != errno.ENOENT:
5998 if inst.errno != errno.ENOENT:
5997 raise
5999 raise
5998
6000
5999 for f in tocomplete:
6001 for f in tocomplete:
6000 try:
6002 try:
6001 # resolve file
6003 # resolve file
6002 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6004 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6003 'resolve')
6005 'resolve')
6004 r = ms.resolve(f, wctx)
6006 r = ms.resolve(f, wctx)
6005 if r:
6007 if r:
6006 ret = 1
6008 ret = 1
6007 finally:
6009 finally:
6008 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6010 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6009 ms.commit()
6011 ms.commit()
6010
6012
6011 # replace filemerge's .orig file with our resolve file
6013 # replace filemerge's .orig file with our resolve file
6012 a = repo.wjoin(f)
6014 a = repo.wjoin(f)
6013 try:
6015 try:
6014 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
6016 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
6015 except OSError as inst:
6017 except OSError as inst:
6016 if inst.errno != errno.ENOENT:
6018 if inst.errno != errno.ENOENT:
6017 raise
6019 raise
6018
6020
6019 ms.commit()
6021 ms.commit()
6020 ms.recordactions()
6022 ms.recordactions()
6021
6023
6022 if not didwork and pats:
6024 if not didwork and pats:
6023 ui.warn(_("arguments do not match paths that need resolving\n"))
6025 ui.warn(_("arguments do not match paths that need resolving\n"))
6024 elif ms.mergedriver and ms.mdstate() != 's':
6026 elif ms.mergedriver and ms.mdstate() != 's':
6025 # run conclude step when either a driver-resolved file is requested
6027 # run conclude step when either a driver-resolved file is requested
6026 # or there are no driver-resolved files
6028 # or there are no driver-resolved files
6027 # we can't use 'ret' to determine whether any files are unresolved
6029 # we can't use 'ret' to determine whether any files are unresolved
6028 # because we might not have tried to resolve some
6030 # because we might not have tried to resolve some
6029 if ((runconclude or not list(ms.driverresolved()))
6031 if ((runconclude or not list(ms.driverresolved()))
6030 and not list(ms.unresolved())):
6032 and not list(ms.unresolved())):
6031 proceed = mergemod.driverconclude(repo, ms, wctx)
6033 proceed = mergemod.driverconclude(repo, ms, wctx)
6032 ms.commit()
6034 ms.commit()
6033 if not proceed:
6035 if not proceed:
6034 return 1
6036 return 1
6035
6037
6036 # Nudge users into finishing an unfinished operation
6038 # Nudge users into finishing an unfinished operation
6037 unresolvedf = list(ms.unresolved())
6039 unresolvedf = list(ms.unresolved())
6038 driverresolvedf = list(ms.driverresolved())
6040 driverresolvedf = list(ms.driverresolved())
6039 if not unresolvedf and not driverresolvedf:
6041 if not unresolvedf and not driverresolvedf:
6040 ui.status(_('(no more unresolved files)\n'))
6042 ui.status(_('(no more unresolved files)\n'))
6041 cmdutil.checkafterresolved(repo)
6043 cmdutil.checkafterresolved(repo)
6042 elif not unresolvedf:
6044 elif not unresolvedf:
6043 ui.status(_('(no more unresolved files -- '
6045 ui.status(_('(no more unresolved files -- '
6044 'run "hg resolve --all" to conclude)\n'))
6046 'run "hg resolve --all" to conclude)\n'))
6045
6047
6046 return ret
6048 return ret
6047
6049
6048 @command('revert',
6050 @command('revert',
6049 [('a', 'all', None, _('revert all changes when no arguments given')),
6051 [('a', 'all', None, _('revert all changes when no arguments given')),
6050 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6052 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6051 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
6053 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
6052 ('C', 'no-backup', None, _('do not save backup copies of files')),
6054 ('C', 'no-backup', None, _('do not save backup copies of files')),
6053 ('i', 'interactive', None,
6055 ('i', 'interactive', None,
6054 _('interactively select the changes (EXPERIMENTAL)')),
6056 _('interactively select the changes (EXPERIMENTAL)')),
6055 ] + walkopts + dryrunopts,
6057 ] + walkopts + dryrunopts,
6056 _('[OPTION]... [-r REV] [NAME]...'))
6058 _('[OPTION]... [-r REV] [NAME]...'))
6057 def revert(ui, repo, *pats, **opts):
6059 def revert(ui, repo, *pats, **opts):
6058 """restore files to their checkout state
6060 """restore files to their checkout state
6059
6061
6060 .. note::
6062 .. note::
6061
6063
6062 To check out earlier revisions, you should use :hg:`update REV`.
6064 To check out earlier revisions, you should use :hg:`update REV`.
6063 To cancel an uncommitted merge (and lose your changes),
6065 To cancel an uncommitted merge (and lose your changes),
6064 use :hg:`update --clean .`.
6066 use :hg:`update --clean .`.
6065
6067
6066 With no revision specified, revert the specified files or directories
6068 With no revision specified, revert the specified files or directories
6067 to the contents they had in the parent of the working directory.
6069 to the contents they had in the parent of the working directory.
6068 This restores the contents of files to an unmodified
6070 This restores the contents of files to an unmodified
6069 state and unschedules adds, removes, copies, and renames. If the
6071 state and unschedules adds, removes, copies, and renames. If the
6070 working directory has two parents, you must explicitly specify a
6072 working directory has two parents, you must explicitly specify a
6071 revision.
6073 revision.
6072
6074
6073 Using the -r/--rev or -d/--date options, revert the given files or
6075 Using the -r/--rev or -d/--date options, revert the given files or
6074 directories to their states as of a specific revision. Because
6076 directories to their states as of a specific revision. Because
6075 revert does not change the working directory parents, this will
6077 revert does not change the working directory parents, this will
6076 cause these files to appear modified. This can be helpful to "back
6078 cause these files to appear modified. This can be helpful to "back
6077 out" some or all of an earlier change. See :hg:`backout` for a
6079 out" some or all of an earlier change. See :hg:`backout` for a
6078 related method.
6080 related method.
6079
6081
6080 Modified files are saved with a .orig suffix before reverting.
6082 Modified files are saved with a .orig suffix before reverting.
6081 To disable these backups, use --no-backup.
6083 To disable these backups, use --no-backup.
6082
6084
6083 See :hg:`help dates` for a list of formats valid for -d/--date.
6085 See :hg:`help dates` for a list of formats valid for -d/--date.
6084
6086
6085 See :hg:`help backout` for a way to reverse the effect of an
6087 See :hg:`help backout` for a way to reverse the effect of an
6086 earlier changeset.
6088 earlier changeset.
6087
6089
6088 Returns 0 on success.
6090 Returns 0 on success.
6089 """
6091 """
6090
6092
6091 if opts.get("date"):
6093 if opts.get("date"):
6092 if opts.get("rev"):
6094 if opts.get("rev"):
6093 raise error.Abort(_("you can't specify a revision and a date"))
6095 raise error.Abort(_("you can't specify a revision and a date"))
6094 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6096 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6095
6097
6096 parent, p2 = repo.dirstate.parents()
6098 parent, p2 = repo.dirstate.parents()
6097 if not opts.get('rev') and p2 != nullid:
6099 if not opts.get('rev') and p2 != nullid:
6098 # revert after merge is a trap for new users (issue2915)
6100 # revert after merge is a trap for new users (issue2915)
6099 raise error.Abort(_('uncommitted merge with no revision specified'),
6101 raise error.Abort(_('uncommitted merge with no revision specified'),
6100 hint=_('use "hg update" or see "hg help revert"'))
6102 hint=_('use "hg update" or see "hg help revert"'))
6101
6103
6102 ctx = scmutil.revsingle(repo, opts.get('rev'))
6104 ctx = scmutil.revsingle(repo, opts.get('rev'))
6103
6105
6104 if (not (pats or opts.get('include') or opts.get('exclude') or
6106 if (not (pats or opts.get('include') or opts.get('exclude') or
6105 opts.get('all') or opts.get('interactive'))):
6107 opts.get('all') or opts.get('interactive'))):
6106 msg = _("no files or directories specified")
6108 msg = _("no files or directories specified")
6107 if p2 != nullid:
6109 if p2 != nullid:
6108 hint = _("uncommitted merge, use --all to discard all changes,"
6110 hint = _("uncommitted merge, use --all to discard all changes,"
6109 " or 'hg update -C .' to abort the merge")
6111 " or 'hg update -C .' to abort the merge")
6110 raise error.Abort(msg, hint=hint)
6112 raise error.Abort(msg, hint=hint)
6111 dirty = any(repo.status())
6113 dirty = any(repo.status())
6112 node = ctx.node()
6114 node = ctx.node()
6113 if node != parent:
6115 if node != parent:
6114 if dirty:
6116 if dirty:
6115 hint = _("uncommitted changes, use --all to discard all"
6117 hint = _("uncommitted changes, use --all to discard all"
6116 " changes, or 'hg update %s' to update") % ctx.rev()
6118 " changes, or 'hg update %s' to update") % ctx.rev()
6117 else:
6119 else:
6118 hint = _("use --all to revert all files,"
6120 hint = _("use --all to revert all files,"
6119 " or 'hg update %s' to update") % ctx.rev()
6121 " or 'hg update %s' to update") % ctx.rev()
6120 elif dirty:
6122 elif dirty:
6121 hint = _("uncommitted changes, use --all to discard all changes")
6123 hint = _("uncommitted changes, use --all to discard all changes")
6122 else:
6124 else:
6123 hint = _("use --all to revert all files")
6125 hint = _("use --all to revert all files")
6124 raise error.Abort(msg, hint=hint)
6126 raise error.Abort(msg, hint=hint)
6125
6127
6126 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
6128 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
6127
6129
6128 @command('rollback', dryrunopts +
6130 @command('rollback', dryrunopts +
6129 [('f', 'force', False, _('ignore safety measures'))])
6131 [('f', 'force', False, _('ignore safety measures'))])
6130 def rollback(ui, repo, **opts):
6132 def rollback(ui, repo, **opts):
6131 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6133 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6132
6134
6133 Please use :hg:`commit --amend` instead of rollback to correct
6135 Please use :hg:`commit --amend` instead of rollback to correct
6134 mistakes in the last commit.
6136 mistakes in the last commit.
6135
6137
6136 This command should be used with care. There is only one level of
6138 This command should be used with care. There is only one level of
6137 rollback, and there is no way to undo a rollback. It will also
6139 rollback, and there is no way to undo a rollback. It will also
6138 restore the dirstate at the time of the last transaction, losing
6140 restore the dirstate at the time of the last transaction, losing
6139 any dirstate changes since that time. This command does not alter
6141 any dirstate changes since that time. This command does not alter
6140 the working directory.
6142 the working directory.
6141
6143
6142 Transactions are used to encapsulate the effects of all commands
6144 Transactions are used to encapsulate the effects of all commands
6143 that create new changesets or propagate existing changesets into a
6145 that create new changesets or propagate existing changesets into a
6144 repository.
6146 repository.
6145
6147
6146 .. container:: verbose
6148 .. container:: verbose
6147
6149
6148 For example, the following commands are transactional, and their
6150 For example, the following commands are transactional, and their
6149 effects can be rolled back:
6151 effects can be rolled back:
6150
6152
6151 - commit
6153 - commit
6152 - import
6154 - import
6153 - pull
6155 - pull
6154 - push (with this repository as the destination)
6156 - push (with this repository as the destination)
6155 - unbundle
6157 - unbundle
6156
6158
6157 To avoid permanent data loss, rollback will refuse to rollback a
6159 To avoid permanent data loss, rollback will refuse to rollback a
6158 commit transaction if it isn't checked out. Use --force to
6160 commit transaction if it isn't checked out. Use --force to
6159 override this protection.
6161 override this protection.
6160
6162
6161 This command is not intended for use on public repositories. Once
6163 This command is not intended for use on public repositories. Once
6162 changes are visible for pull by other users, rolling a transaction
6164 changes are visible for pull by other users, rolling a transaction
6163 back locally is ineffective (someone else may already have pulled
6165 back locally is ineffective (someone else may already have pulled
6164 the changes). Furthermore, a race is possible with readers of the
6166 the changes). Furthermore, a race is possible with readers of the
6165 repository; for example an in-progress pull from the repository
6167 repository; for example an in-progress pull from the repository
6166 may fail if a rollback is performed.
6168 may fail if a rollback is performed.
6167
6169
6168 Returns 0 on success, 1 if no rollback data is available.
6170 Returns 0 on success, 1 if no rollback data is available.
6169 """
6171 """
6170 return repo.rollback(dryrun=opts.get('dry_run'),
6172 return repo.rollback(dryrun=opts.get('dry_run'),
6171 force=opts.get('force'))
6173 force=opts.get('force'))
6172
6174
6173 @command('root', [])
6175 @command('root', [])
6174 def root(ui, repo):
6176 def root(ui, repo):
6175 """print the root (top) of the current working directory
6177 """print the root (top) of the current working directory
6176
6178
6177 Print the root directory of the current repository.
6179 Print the root directory of the current repository.
6178
6180
6179 Returns 0 on success.
6181 Returns 0 on success.
6180 """
6182 """
6181 ui.write(repo.root + "\n")
6183 ui.write(repo.root + "\n")
6182
6184
6183 @command('^serve',
6185 @command('^serve',
6184 [('A', 'accesslog', '', _('name of access log file to write to'),
6186 [('A', 'accesslog', '', _('name of access log file to write to'),
6185 _('FILE')),
6187 _('FILE')),
6186 ('d', 'daemon', None, _('run server in background')),
6188 ('d', 'daemon', None, _('run server in background')),
6187 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('FILE')),
6189 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('FILE')),
6188 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
6190 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
6189 # use string type, then we can check if something was passed
6191 # use string type, then we can check if something was passed
6190 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
6192 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
6191 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
6193 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
6192 _('ADDR')),
6194 _('ADDR')),
6193 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
6195 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
6194 _('PREFIX')),
6196 _('PREFIX')),
6195 ('n', 'name', '',
6197 ('n', 'name', '',
6196 _('name to show in web pages (default: working directory)'), _('NAME')),
6198 _('name to show in web pages (default: working directory)'), _('NAME')),
6197 ('', 'web-conf', '',
6199 ('', 'web-conf', '',
6198 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
6200 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
6199 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
6201 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
6200 _('FILE')),
6202 _('FILE')),
6201 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
6203 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
6202 ('', 'stdio', None, _('for remote clients')),
6204 ('', 'stdio', None, _('for remote clients')),
6203 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
6205 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
6204 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
6206 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
6205 ('', 'style', '', _('template style to use'), _('STYLE')),
6207 ('', 'style', '', _('template style to use'), _('STYLE')),
6206 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
6208 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
6207 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
6209 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
6208 _('[OPTION]...'),
6210 _('[OPTION]...'),
6209 optionalrepo=True)
6211 optionalrepo=True)
6210 def serve(ui, repo, **opts):
6212 def serve(ui, repo, **opts):
6211 """start stand-alone webserver
6213 """start stand-alone webserver
6212
6214
6213 Start a local HTTP repository browser and pull server. You can use
6215 Start a local HTTP repository browser and pull server. You can use
6214 this for ad-hoc sharing and browsing of repositories. It is
6216 this for ad-hoc sharing and browsing of repositories. It is
6215 recommended to use a real web server to serve a repository for
6217 recommended to use a real web server to serve a repository for
6216 longer periods of time.
6218 longer periods of time.
6217
6219
6218 Please note that the server does not implement access control.
6220 Please note that the server does not implement access control.
6219 This means that, by default, anybody can read from the server and
6221 This means that, by default, anybody can read from the server and
6220 nobody can write to it by default. Set the ``web.allow_push``
6222 nobody can write to it by default. Set the ``web.allow_push``
6221 option to ``*`` to allow everybody to push to the server. You
6223 option to ``*`` to allow everybody to push to the server. You
6222 should use a real web server if you need to authenticate users.
6224 should use a real web server if you need to authenticate users.
6223
6225
6224 By default, the server logs accesses to stdout and errors to
6226 By default, the server logs accesses to stdout and errors to
6225 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6227 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6226 files.
6228 files.
6227
6229
6228 To have the server choose a free port number to listen on, specify
6230 To have the server choose a free port number to listen on, specify
6229 a port number of 0; in this case, the server will print the port
6231 a port number of 0; in this case, the server will print the port
6230 number it uses.
6232 number it uses.
6231
6233
6232 Returns 0 on success.
6234 Returns 0 on success.
6233 """
6235 """
6234
6236
6235 if opts["stdio"] and opts["cmdserver"]:
6237 if opts["stdio"] and opts["cmdserver"]:
6236 raise error.Abort(_("cannot use --stdio with --cmdserver"))
6238 raise error.Abort(_("cannot use --stdio with --cmdserver"))
6237
6239
6238 if opts["stdio"]:
6240 if opts["stdio"]:
6239 if repo is None:
6241 if repo is None:
6240 raise error.RepoError(_("there is no Mercurial repository here"
6242 raise error.RepoError(_("there is no Mercurial repository here"
6241 " (.hg not found)"))
6243 " (.hg not found)"))
6242 s = sshserver.sshserver(ui, repo)
6244 s = sshserver.sshserver(ui, repo)
6243 s.serve_forever()
6245 s.serve_forever()
6244
6246
6245 if opts["cmdserver"]:
6247 if opts["cmdserver"]:
6246 service = commandserver.createservice(ui, repo, opts)
6248 service = commandserver.createservice(ui, repo, opts)
6247 else:
6249 else:
6248 service = hgweb.createservice(ui, repo, opts)
6250 service = hgweb.createservice(ui, repo, opts)
6249 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
6251 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
6250
6252
6251 @command('^status|st',
6253 @command('^status|st',
6252 [('A', 'all', None, _('show status of all files')),
6254 [('A', 'all', None, _('show status of all files')),
6253 ('m', 'modified', None, _('show only modified files')),
6255 ('m', 'modified', None, _('show only modified files')),
6254 ('a', 'added', None, _('show only added files')),
6256 ('a', 'added', None, _('show only added files')),
6255 ('r', 'removed', None, _('show only removed files')),
6257 ('r', 'removed', None, _('show only removed files')),
6256 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
6258 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
6257 ('c', 'clean', None, _('show only files without changes')),
6259 ('c', 'clean', None, _('show only files without changes')),
6258 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
6260 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
6259 ('i', 'ignored', None, _('show only ignored files')),
6261 ('i', 'ignored', None, _('show only ignored files')),
6260 ('n', 'no-status', None, _('hide status prefix')),
6262 ('n', 'no-status', None, _('hide status prefix')),
6261 ('C', 'copies', None, _('show source of copied files')),
6263 ('C', 'copies', None, _('show source of copied files')),
6262 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
6264 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
6263 ('', 'rev', [], _('show difference from revision'), _('REV')),
6265 ('', 'rev', [], _('show difference from revision'), _('REV')),
6264 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
6266 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
6265 ] + walkopts + subrepoopts + formatteropts,
6267 ] + walkopts + subrepoopts + formatteropts,
6266 _('[OPTION]... [FILE]...'),
6268 _('[OPTION]... [FILE]...'),
6267 inferrepo=True)
6269 inferrepo=True)
6268 def status(ui, repo, *pats, **opts):
6270 def status(ui, repo, *pats, **opts):
6269 """show changed files in the working directory
6271 """show changed files in the working directory
6270
6272
6271 Show status of files in the repository. If names are given, only
6273 Show status of files in the repository. If names are given, only
6272 files that match are shown. Files that are clean or ignored or
6274 files that match are shown. Files that are clean or ignored or
6273 the source of a copy/move operation, are not listed unless
6275 the source of a copy/move operation, are not listed unless
6274 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6276 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6275 Unless options described with "show only ..." are given, the
6277 Unless options described with "show only ..." are given, the
6276 options -mardu are used.
6278 options -mardu are used.
6277
6279
6278 Option -q/--quiet hides untracked (unknown and ignored) files
6280 Option -q/--quiet hides untracked (unknown and ignored) files
6279 unless explicitly requested with -u/--unknown or -i/--ignored.
6281 unless explicitly requested with -u/--unknown or -i/--ignored.
6280
6282
6281 .. note::
6283 .. note::
6282
6284
6283 :hg:`status` may appear to disagree with diff if permissions have
6285 :hg:`status` may appear to disagree with diff if permissions have
6284 changed or a merge has occurred. The standard diff format does
6286 changed or a merge has occurred. The standard diff format does
6285 not report permission changes and diff only reports changes
6287 not report permission changes and diff only reports changes
6286 relative to one merge parent.
6288 relative to one merge parent.
6287
6289
6288 If one revision is given, it is used as the base revision.
6290 If one revision is given, it is used as the base revision.
6289 If two revisions are given, the differences between them are
6291 If two revisions are given, the differences between them are
6290 shown. The --change option can also be used as a shortcut to list
6292 shown. The --change option can also be used as a shortcut to list
6291 the changed files of a revision from its first parent.
6293 the changed files of a revision from its first parent.
6292
6294
6293 The codes used to show the status of files are::
6295 The codes used to show the status of files are::
6294
6296
6295 M = modified
6297 M = modified
6296 A = added
6298 A = added
6297 R = removed
6299 R = removed
6298 C = clean
6300 C = clean
6299 ! = missing (deleted by non-hg command, but still tracked)
6301 ! = missing (deleted by non-hg command, but still tracked)
6300 ? = not tracked
6302 ? = not tracked
6301 I = ignored
6303 I = ignored
6302 = origin of the previous file (with --copies)
6304 = origin of the previous file (with --copies)
6303
6305
6304 .. container:: verbose
6306 .. container:: verbose
6305
6307
6306 Examples:
6308 Examples:
6307
6309
6308 - show changes in the working directory relative to a
6310 - show changes in the working directory relative to a
6309 changeset::
6311 changeset::
6310
6312
6311 hg status --rev 9353
6313 hg status --rev 9353
6312
6314
6313 - show changes in the working directory relative to the
6315 - show changes in the working directory relative to the
6314 current directory (see :hg:`help patterns` for more information)::
6316 current directory (see :hg:`help patterns` for more information)::
6315
6317
6316 hg status re:
6318 hg status re:
6317
6319
6318 - show all changes including copies in an existing changeset::
6320 - show all changes including copies in an existing changeset::
6319
6321
6320 hg status --copies --change 9353
6322 hg status --copies --change 9353
6321
6323
6322 - get a NUL separated list of added files, suitable for xargs::
6324 - get a NUL separated list of added files, suitable for xargs::
6323
6325
6324 hg status -an0
6326 hg status -an0
6325
6327
6326 Returns 0 on success.
6328 Returns 0 on success.
6327 """
6329 """
6328
6330
6329 revs = opts.get('rev')
6331 revs = opts.get('rev')
6330 change = opts.get('change')
6332 change = opts.get('change')
6331
6333
6332 if revs and change:
6334 if revs and change:
6333 msg = _('cannot specify --rev and --change at the same time')
6335 msg = _('cannot specify --rev and --change at the same time')
6334 raise error.Abort(msg)
6336 raise error.Abort(msg)
6335 elif change:
6337 elif change:
6336 node2 = scmutil.revsingle(repo, change, None).node()
6338 node2 = scmutil.revsingle(repo, change, None).node()
6337 node1 = repo[node2].p1().node()
6339 node1 = repo[node2].p1().node()
6338 else:
6340 else:
6339 node1, node2 = scmutil.revpair(repo, revs)
6341 node1, node2 = scmutil.revpair(repo, revs)
6340
6342
6341 if pats:
6343 if pats:
6342 cwd = repo.getcwd()
6344 cwd = repo.getcwd()
6343 else:
6345 else:
6344 cwd = ''
6346 cwd = ''
6345
6347
6346 if opts.get('print0'):
6348 if opts.get('print0'):
6347 end = '\0'
6349 end = '\0'
6348 else:
6350 else:
6349 end = '\n'
6351 end = '\n'
6350 copy = {}
6352 copy = {}
6351 states = 'modified added removed deleted unknown ignored clean'.split()
6353 states = 'modified added removed deleted unknown ignored clean'.split()
6352 show = [k for k in states if opts.get(k)]
6354 show = [k for k in states if opts.get(k)]
6353 if opts.get('all'):
6355 if opts.get('all'):
6354 show += ui.quiet and (states[:4] + ['clean']) or states
6356 show += ui.quiet and (states[:4] + ['clean']) or states
6355 if not show:
6357 if not show:
6356 if ui.quiet:
6358 if ui.quiet:
6357 show = states[:4]
6359 show = states[:4]
6358 else:
6360 else:
6359 show = states[:5]
6361 show = states[:5]
6360
6362
6361 m = scmutil.match(repo[node2], pats, opts)
6363 m = scmutil.match(repo[node2], pats, opts)
6362 stat = repo.status(node1, node2, m,
6364 stat = repo.status(node1, node2, m,
6363 'ignored' in show, 'clean' in show, 'unknown' in show,
6365 'ignored' in show, 'clean' in show, 'unknown' in show,
6364 opts.get('subrepos'))
6366 opts.get('subrepos'))
6365 changestates = zip(states, 'MAR!?IC', stat)
6367 changestates = zip(states, 'MAR!?IC', stat)
6366
6368
6367 if (opts.get('all') or opts.get('copies')
6369 if (opts.get('all') or opts.get('copies')
6368 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6370 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6369 copy = copies.pathcopies(repo[node1], repo[node2], m)
6371 copy = copies.pathcopies(repo[node1], repo[node2], m)
6370
6372
6371 fm = ui.formatter('status', opts)
6373 fm = ui.formatter('status', opts)
6372 fmt = '%s' + end
6374 fmt = '%s' + end
6373 showchar = not opts.get('no_status')
6375 showchar = not opts.get('no_status')
6374
6376
6375 for state, char, files in changestates:
6377 for state, char, files in changestates:
6376 if state in show:
6378 if state in show:
6377 label = 'status.' + state
6379 label = 'status.' + state
6378 for f in files:
6380 for f in files:
6379 fm.startitem()
6381 fm.startitem()
6380 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6382 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6381 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6383 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6382 if f in copy:
6384 if f in copy:
6383 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6385 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6384 label='status.copied')
6386 label='status.copied')
6385 fm.end()
6387 fm.end()
6386
6388
6387 @command('^summary|sum',
6389 @command('^summary|sum',
6388 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6390 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6389 def summary(ui, repo, **opts):
6391 def summary(ui, repo, **opts):
6390 """summarize working directory state
6392 """summarize working directory state
6391
6393
6392 This generates a brief summary of the working directory state,
6394 This generates a brief summary of the working directory state,
6393 including parents, branch, commit status, phase and available updates.
6395 including parents, branch, commit status, phase and available updates.
6394
6396
6395 With the --remote option, this will check the default paths for
6397 With the --remote option, this will check the default paths for
6396 incoming and outgoing changes. This can be time-consuming.
6398 incoming and outgoing changes. This can be time-consuming.
6397
6399
6398 Returns 0 on success.
6400 Returns 0 on success.
6399 """
6401 """
6400
6402
6401 ctx = repo[None]
6403 ctx = repo[None]
6402 parents = ctx.parents()
6404 parents = ctx.parents()
6403 pnode = parents[0].node()
6405 pnode = parents[0].node()
6404 marks = []
6406 marks = []
6405
6407
6406 for p in parents:
6408 for p in parents:
6407 # label with log.changeset (instead of log.parent) since this
6409 # label with log.changeset (instead of log.parent) since this
6408 # shows a working directory parent *changeset*:
6410 # shows a working directory parent *changeset*:
6409 # i18n: column positioning for "hg summary"
6411 # i18n: column positioning for "hg summary"
6410 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6412 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6411 label='log.changeset changeset.%s' % p.phasestr())
6413 label='log.changeset changeset.%s' % p.phasestr())
6412 ui.write(' '.join(p.tags()), label='log.tag')
6414 ui.write(' '.join(p.tags()), label='log.tag')
6413 if p.bookmarks():
6415 if p.bookmarks():
6414 marks.extend(p.bookmarks())
6416 marks.extend(p.bookmarks())
6415 if p.rev() == -1:
6417 if p.rev() == -1:
6416 if not len(repo):
6418 if not len(repo):
6417 ui.write(_(' (empty repository)'))
6419 ui.write(_(' (empty repository)'))
6418 else:
6420 else:
6419 ui.write(_(' (no revision checked out)'))
6421 ui.write(_(' (no revision checked out)'))
6420 ui.write('\n')
6422 ui.write('\n')
6421 if p.description():
6423 if p.description():
6422 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6424 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6423 label='log.summary')
6425 label='log.summary')
6424
6426
6425 branch = ctx.branch()
6427 branch = ctx.branch()
6426 bheads = repo.branchheads(branch)
6428 bheads = repo.branchheads(branch)
6427 # i18n: column positioning for "hg summary"
6429 # i18n: column positioning for "hg summary"
6428 m = _('branch: %s\n') % branch
6430 m = _('branch: %s\n') % branch
6429 if branch != 'default':
6431 if branch != 'default':
6430 ui.write(m, label='log.branch')
6432 ui.write(m, label='log.branch')
6431 else:
6433 else:
6432 ui.status(m, label='log.branch')
6434 ui.status(m, label='log.branch')
6433
6435
6434 if marks:
6436 if marks:
6435 active = repo._activebookmark
6437 active = repo._activebookmark
6436 # i18n: column positioning for "hg summary"
6438 # i18n: column positioning for "hg summary"
6437 ui.write(_('bookmarks:'), label='log.bookmark')
6439 ui.write(_('bookmarks:'), label='log.bookmark')
6438 if active is not None:
6440 if active is not None:
6439 if active in marks:
6441 if active in marks:
6440 ui.write(' *' + active, label=activebookmarklabel)
6442 ui.write(' *' + active, label=activebookmarklabel)
6441 marks.remove(active)
6443 marks.remove(active)
6442 else:
6444 else:
6443 ui.write(' [%s]' % active, label=activebookmarklabel)
6445 ui.write(' [%s]' % active, label=activebookmarklabel)
6444 for m in marks:
6446 for m in marks:
6445 ui.write(' ' + m, label='log.bookmark')
6447 ui.write(' ' + m, label='log.bookmark')
6446 ui.write('\n', label='log.bookmark')
6448 ui.write('\n', label='log.bookmark')
6447
6449
6448 status = repo.status(unknown=True)
6450 status = repo.status(unknown=True)
6449
6451
6450 c = repo.dirstate.copies()
6452 c = repo.dirstate.copies()
6451 copied, renamed = [], []
6453 copied, renamed = [], []
6452 for d, s in c.iteritems():
6454 for d, s in c.iteritems():
6453 if s in status.removed:
6455 if s in status.removed:
6454 status.removed.remove(s)
6456 status.removed.remove(s)
6455 renamed.append(d)
6457 renamed.append(d)
6456 else:
6458 else:
6457 copied.append(d)
6459 copied.append(d)
6458 if d in status.added:
6460 if d in status.added:
6459 status.added.remove(d)
6461 status.added.remove(d)
6460
6462
6461 try:
6463 try:
6462 ms = mergemod.mergestate.read(repo)
6464 ms = mergemod.mergestate.read(repo)
6463 except error.UnsupportedMergeRecords as e:
6465 except error.UnsupportedMergeRecords as e:
6464 s = ' '.join(e.recordtypes)
6466 s = ' '.join(e.recordtypes)
6465 ui.warn(
6467 ui.warn(
6466 _('warning: merge state has unsupported record types: %s\n') % s)
6468 _('warning: merge state has unsupported record types: %s\n') % s)
6467 unresolved = 0
6469 unresolved = 0
6468 else:
6470 else:
6469 unresolved = [f for f in ms if ms[f] == 'u']
6471 unresolved = [f for f in ms if ms[f] == 'u']
6470
6472
6471 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6473 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6472
6474
6473 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6475 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6474 (ui.label(_('%d added'), 'status.added'), status.added),
6476 (ui.label(_('%d added'), 'status.added'), status.added),
6475 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6477 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6476 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6478 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6477 (ui.label(_('%d copied'), 'status.copied'), copied),
6479 (ui.label(_('%d copied'), 'status.copied'), copied),
6478 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6480 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6479 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6481 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6480 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6482 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6481 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6483 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6482 t = []
6484 t = []
6483 for l, s in labels:
6485 for l, s in labels:
6484 if s:
6486 if s:
6485 t.append(l % len(s))
6487 t.append(l % len(s))
6486
6488
6487 t = ', '.join(t)
6489 t = ', '.join(t)
6488 cleanworkdir = False
6490 cleanworkdir = False
6489
6491
6490 if repo.vfs.exists('graftstate'):
6492 if repo.vfs.exists('graftstate'):
6491 t += _(' (graft in progress)')
6493 t += _(' (graft in progress)')
6492 if repo.vfs.exists('updatestate'):
6494 if repo.vfs.exists('updatestate'):
6493 t += _(' (interrupted update)')
6495 t += _(' (interrupted update)')
6494 elif len(parents) > 1:
6496 elif len(parents) > 1:
6495 t += _(' (merge)')
6497 t += _(' (merge)')
6496 elif branch != parents[0].branch():
6498 elif branch != parents[0].branch():
6497 t += _(' (new branch)')
6499 t += _(' (new branch)')
6498 elif (parents[0].closesbranch() and
6500 elif (parents[0].closesbranch() and
6499 pnode in repo.branchheads(branch, closed=True)):
6501 pnode in repo.branchheads(branch, closed=True)):
6500 t += _(' (head closed)')
6502 t += _(' (head closed)')
6501 elif not (status.modified or status.added or status.removed or renamed or
6503 elif not (status.modified or status.added or status.removed or renamed or
6502 copied or subs):
6504 copied or subs):
6503 t += _(' (clean)')
6505 t += _(' (clean)')
6504 cleanworkdir = True
6506 cleanworkdir = True
6505 elif pnode not in bheads:
6507 elif pnode not in bheads:
6506 t += _(' (new branch head)')
6508 t += _(' (new branch head)')
6507
6509
6508 if parents:
6510 if parents:
6509 pendingphase = max(p.phase() for p in parents)
6511 pendingphase = max(p.phase() for p in parents)
6510 else:
6512 else:
6511 pendingphase = phases.public
6513 pendingphase = phases.public
6512
6514
6513 if pendingphase > phases.newcommitphase(ui):
6515 if pendingphase > phases.newcommitphase(ui):
6514 t += ' (%s)' % phases.phasenames[pendingphase]
6516 t += ' (%s)' % phases.phasenames[pendingphase]
6515
6517
6516 if cleanworkdir:
6518 if cleanworkdir:
6517 # i18n: column positioning for "hg summary"
6519 # i18n: column positioning for "hg summary"
6518 ui.status(_('commit: %s\n') % t.strip())
6520 ui.status(_('commit: %s\n') % t.strip())
6519 else:
6521 else:
6520 # i18n: column positioning for "hg summary"
6522 # i18n: column positioning for "hg summary"
6521 ui.write(_('commit: %s\n') % t.strip())
6523 ui.write(_('commit: %s\n') % t.strip())
6522
6524
6523 # all ancestors of branch heads - all ancestors of parent = new csets
6525 # all ancestors of branch heads - all ancestors of parent = new csets
6524 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6526 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6525 bheads))
6527 bheads))
6526
6528
6527 if new == 0:
6529 if new == 0:
6528 # i18n: column positioning for "hg summary"
6530 # i18n: column positioning for "hg summary"
6529 ui.status(_('update: (current)\n'))
6531 ui.status(_('update: (current)\n'))
6530 elif pnode not in bheads:
6532 elif pnode not in bheads:
6531 # i18n: column positioning for "hg summary"
6533 # i18n: column positioning for "hg summary"
6532 ui.write(_('update: %d new changesets (update)\n') % new)
6534 ui.write(_('update: %d new changesets (update)\n') % new)
6533 else:
6535 else:
6534 # i18n: column positioning for "hg summary"
6536 # i18n: column positioning for "hg summary"
6535 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6537 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6536 (new, len(bheads)))
6538 (new, len(bheads)))
6537
6539
6538 t = []
6540 t = []
6539 draft = len(repo.revs('draft()'))
6541 draft = len(repo.revs('draft()'))
6540 if draft:
6542 if draft:
6541 t.append(_('%d draft') % draft)
6543 t.append(_('%d draft') % draft)
6542 secret = len(repo.revs('secret()'))
6544 secret = len(repo.revs('secret()'))
6543 if secret:
6545 if secret:
6544 t.append(_('%d secret') % secret)
6546 t.append(_('%d secret') % secret)
6545
6547
6546 if draft or secret:
6548 if draft or secret:
6547 ui.status(_('phases: %s\n') % ', '.join(t))
6549 ui.status(_('phases: %s\n') % ', '.join(t))
6548
6550
6549 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6551 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6550 for trouble in ("unstable", "divergent", "bumped"):
6552 for trouble in ("unstable", "divergent", "bumped"):
6551 numtrouble = len(repo.revs(trouble + "()"))
6553 numtrouble = len(repo.revs(trouble + "()"))
6552 # We write all the possibilities to ease translation
6554 # We write all the possibilities to ease translation
6553 troublemsg = {
6555 troublemsg = {
6554 "unstable": _("unstable: %d changesets"),
6556 "unstable": _("unstable: %d changesets"),
6555 "divergent": _("divergent: %d changesets"),
6557 "divergent": _("divergent: %d changesets"),
6556 "bumped": _("bumped: %d changesets"),
6558 "bumped": _("bumped: %d changesets"),
6557 }
6559 }
6558 if numtrouble > 0:
6560 if numtrouble > 0:
6559 ui.status(troublemsg[trouble] % numtrouble + "\n")
6561 ui.status(troublemsg[trouble] % numtrouble + "\n")
6560
6562
6561 cmdutil.summaryhooks(ui, repo)
6563 cmdutil.summaryhooks(ui, repo)
6562
6564
6563 if opts.get('remote'):
6565 if opts.get('remote'):
6564 needsincoming, needsoutgoing = True, True
6566 needsincoming, needsoutgoing = True, True
6565 else:
6567 else:
6566 needsincoming, needsoutgoing = False, False
6568 needsincoming, needsoutgoing = False, False
6567 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6569 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6568 if i:
6570 if i:
6569 needsincoming = True
6571 needsincoming = True
6570 if o:
6572 if o:
6571 needsoutgoing = True
6573 needsoutgoing = True
6572 if not needsincoming and not needsoutgoing:
6574 if not needsincoming and not needsoutgoing:
6573 return
6575 return
6574
6576
6575 def getincoming():
6577 def getincoming():
6576 source, branches = hg.parseurl(ui.expandpath('default'))
6578 source, branches = hg.parseurl(ui.expandpath('default'))
6577 sbranch = branches[0]
6579 sbranch = branches[0]
6578 try:
6580 try:
6579 other = hg.peer(repo, {}, source)
6581 other = hg.peer(repo, {}, source)
6580 except error.RepoError:
6582 except error.RepoError:
6581 if opts.get('remote'):
6583 if opts.get('remote'):
6582 raise
6584 raise
6583 return source, sbranch, None, None, None
6585 return source, sbranch, None, None, None
6584 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6586 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6585 if revs:
6587 if revs:
6586 revs = [other.lookup(rev) for rev in revs]
6588 revs = [other.lookup(rev) for rev in revs]
6587 ui.debug('comparing with %s\n' % util.hidepassword(source))
6589 ui.debug('comparing with %s\n' % util.hidepassword(source))
6588 repo.ui.pushbuffer()
6590 repo.ui.pushbuffer()
6589 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6591 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6590 repo.ui.popbuffer()
6592 repo.ui.popbuffer()
6591 return source, sbranch, other, commoninc, commoninc[1]
6593 return source, sbranch, other, commoninc, commoninc[1]
6592
6594
6593 if needsincoming:
6595 if needsincoming:
6594 source, sbranch, sother, commoninc, incoming = getincoming()
6596 source, sbranch, sother, commoninc, incoming = getincoming()
6595 else:
6597 else:
6596 source = sbranch = sother = commoninc = incoming = None
6598 source = sbranch = sother = commoninc = incoming = None
6597
6599
6598 def getoutgoing():
6600 def getoutgoing():
6599 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6601 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6600 dbranch = branches[0]
6602 dbranch = branches[0]
6601 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6603 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6602 if source != dest:
6604 if source != dest:
6603 try:
6605 try:
6604 dother = hg.peer(repo, {}, dest)
6606 dother = hg.peer(repo, {}, dest)
6605 except error.RepoError:
6607 except error.RepoError:
6606 if opts.get('remote'):
6608 if opts.get('remote'):
6607 raise
6609 raise
6608 return dest, dbranch, None, None
6610 return dest, dbranch, None, None
6609 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6611 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6610 elif sother is None:
6612 elif sother is None:
6611 # there is no explicit destination peer, but source one is invalid
6613 # there is no explicit destination peer, but source one is invalid
6612 return dest, dbranch, None, None
6614 return dest, dbranch, None, None
6613 else:
6615 else:
6614 dother = sother
6616 dother = sother
6615 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6617 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6616 common = None
6618 common = None
6617 else:
6619 else:
6618 common = commoninc
6620 common = commoninc
6619 if revs:
6621 if revs:
6620 revs = [repo.lookup(rev) for rev in revs]
6622 revs = [repo.lookup(rev) for rev in revs]
6621 repo.ui.pushbuffer()
6623 repo.ui.pushbuffer()
6622 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6624 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6623 commoninc=common)
6625 commoninc=common)
6624 repo.ui.popbuffer()
6626 repo.ui.popbuffer()
6625 return dest, dbranch, dother, outgoing
6627 return dest, dbranch, dother, outgoing
6626
6628
6627 if needsoutgoing:
6629 if needsoutgoing:
6628 dest, dbranch, dother, outgoing = getoutgoing()
6630 dest, dbranch, dother, outgoing = getoutgoing()
6629 else:
6631 else:
6630 dest = dbranch = dother = outgoing = None
6632 dest = dbranch = dother = outgoing = None
6631
6633
6632 if opts.get('remote'):
6634 if opts.get('remote'):
6633 t = []
6635 t = []
6634 if incoming:
6636 if incoming:
6635 t.append(_('1 or more incoming'))
6637 t.append(_('1 or more incoming'))
6636 o = outgoing.missing
6638 o = outgoing.missing
6637 if o:
6639 if o:
6638 t.append(_('%d outgoing') % len(o))
6640 t.append(_('%d outgoing') % len(o))
6639 other = dother or sother
6641 other = dother or sother
6640 if 'bookmarks' in other.listkeys('namespaces'):
6642 if 'bookmarks' in other.listkeys('namespaces'):
6641 counts = bookmarks.summary(repo, other)
6643 counts = bookmarks.summary(repo, other)
6642 if counts[0] > 0:
6644 if counts[0] > 0:
6643 t.append(_('%d incoming bookmarks') % counts[0])
6645 t.append(_('%d incoming bookmarks') % counts[0])
6644 if counts[1] > 0:
6646 if counts[1] > 0:
6645 t.append(_('%d outgoing bookmarks') % counts[1])
6647 t.append(_('%d outgoing bookmarks') % counts[1])
6646
6648
6647 if t:
6649 if t:
6648 # i18n: column positioning for "hg summary"
6650 # i18n: column positioning for "hg summary"
6649 ui.write(_('remote: %s\n') % (', '.join(t)))
6651 ui.write(_('remote: %s\n') % (', '.join(t)))
6650 else:
6652 else:
6651 # i18n: column positioning for "hg summary"
6653 # i18n: column positioning for "hg summary"
6652 ui.status(_('remote: (synced)\n'))
6654 ui.status(_('remote: (synced)\n'))
6653
6655
6654 cmdutil.summaryremotehooks(ui, repo, opts,
6656 cmdutil.summaryremotehooks(ui, repo, opts,
6655 ((source, sbranch, sother, commoninc),
6657 ((source, sbranch, sother, commoninc),
6656 (dest, dbranch, dother, outgoing)))
6658 (dest, dbranch, dother, outgoing)))
6657
6659
6658 @command('tag',
6660 @command('tag',
6659 [('f', 'force', None, _('force tag')),
6661 [('f', 'force', None, _('force tag')),
6660 ('l', 'local', None, _('make the tag local')),
6662 ('l', 'local', None, _('make the tag local')),
6661 ('r', 'rev', '', _('revision to tag'), _('REV')),
6663 ('r', 'rev', '', _('revision to tag'), _('REV')),
6662 ('', 'remove', None, _('remove a tag')),
6664 ('', 'remove', None, _('remove a tag')),
6663 # -l/--local is already there, commitopts cannot be used
6665 # -l/--local is already there, commitopts cannot be used
6664 ('e', 'edit', None, _('invoke editor on commit messages')),
6666 ('e', 'edit', None, _('invoke editor on commit messages')),
6665 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6667 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6666 ] + commitopts2,
6668 ] + commitopts2,
6667 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6669 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6668 def tag(ui, repo, name1, *names, **opts):
6670 def tag(ui, repo, name1, *names, **opts):
6669 """add one or more tags for the current or given revision
6671 """add one or more tags for the current or given revision
6670
6672
6671 Name a particular revision using <name>.
6673 Name a particular revision using <name>.
6672
6674
6673 Tags are used to name particular revisions of the repository and are
6675 Tags are used to name particular revisions of the repository and are
6674 very useful to compare different revisions, to go back to significant
6676 very useful to compare different revisions, to go back to significant
6675 earlier versions or to mark branch points as releases, etc. Changing
6677 earlier versions or to mark branch points as releases, etc. Changing
6676 an existing tag is normally disallowed; use -f/--force to override.
6678 an existing tag is normally disallowed; use -f/--force to override.
6677
6679
6678 If no revision is given, the parent of the working directory is
6680 If no revision is given, the parent of the working directory is
6679 used.
6681 used.
6680
6682
6681 To facilitate version control, distribution, and merging of tags,
6683 To facilitate version control, distribution, and merging of tags,
6682 they are stored as a file named ".hgtags" which is managed similarly
6684 they are stored as a file named ".hgtags" which is managed similarly
6683 to other project files and can be hand-edited if necessary. This
6685 to other project files and can be hand-edited if necessary. This
6684 also means that tagging creates a new commit. The file
6686 also means that tagging creates a new commit. The file
6685 ".hg/localtags" is used for local tags (not shared among
6687 ".hg/localtags" is used for local tags (not shared among
6686 repositories).
6688 repositories).
6687
6689
6688 Tag commits are usually made at the head of a branch. If the parent
6690 Tag commits are usually made at the head of a branch. If the parent
6689 of the working directory is not a branch head, :hg:`tag` aborts; use
6691 of the working directory is not a branch head, :hg:`tag` aborts; use
6690 -f/--force to force the tag commit to be based on a non-head
6692 -f/--force to force the tag commit to be based on a non-head
6691 changeset.
6693 changeset.
6692
6694
6693 See :hg:`help dates` for a list of formats valid for -d/--date.
6695 See :hg:`help dates` for a list of formats valid for -d/--date.
6694
6696
6695 Since tag names have priority over branch names during revision
6697 Since tag names have priority over branch names during revision
6696 lookup, using an existing branch name as a tag name is discouraged.
6698 lookup, using an existing branch name as a tag name is discouraged.
6697
6699
6698 Returns 0 on success.
6700 Returns 0 on success.
6699 """
6701 """
6700 wlock = lock = None
6702 wlock = lock = None
6701 try:
6703 try:
6702 wlock = repo.wlock()
6704 wlock = repo.wlock()
6703 lock = repo.lock()
6705 lock = repo.lock()
6704 rev_ = "."
6706 rev_ = "."
6705 names = [t.strip() for t in (name1,) + names]
6707 names = [t.strip() for t in (name1,) + names]
6706 if len(names) != len(set(names)):
6708 if len(names) != len(set(names)):
6707 raise error.Abort(_('tag names must be unique'))
6709 raise error.Abort(_('tag names must be unique'))
6708 for n in names:
6710 for n in names:
6709 scmutil.checknewlabel(repo, n, 'tag')
6711 scmutil.checknewlabel(repo, n, 'tag')
6710 if not n:
6712 if not n:
6711 raise error.Abort(_('tag names cannot consist entirely of '
6713 raise error.Abort(_('tag names cannot consist entirely of '
6712 'whitespace'))
6714 'whitespace'))
6713 if opts.get('rev') and opts.get('remove'):
6715 if opts.get('rev') and opts.get('remove'):
6714 raise error.Abort(_("--rev and --remove are incompatible"))
6716 raise error.Abort(_("--rev and --remove are incompatible"))
6715 if opts.get('rev'):
6717 if opts.get('rev'):
6716 rev_ = opts['rev']
6718 rev_ = opts['rev']
6717 message = opts.get('message')
6719 message = opts.get('message')
6718 if opts.get('remove'):
6720 if opts.get('remove'):
6719 if opts.get('local'):
6721 if opts.get('local'):
6720 expectedtype = 'local'
6722 expectedtype = 'local'
6721 else:
6723 else:
6722 expectedtype = 'global'
6724 expectedtype = 'global'
6723
6725
6724 for n in names:
6726 for n in names:
6725 if not repo.tagtype(n):
6727 if not repo.tagtype(n):
6726 raise error.Abort(_("tag '%s' does not exist") % n)
6728 raise error.Abort(_("tag '%s' does not exist") % n)
6727 if repo.tagtype(n) != expectedtype:
6729 if repo.tagtype(n) != expectedtype:
6728 if expectedtype == 'global':
6730 if expectedtype == 'global':
6729 raise error.Abort(_("tag '%s' is not a global tag") % n)
6731 raise error.Abort(_("tag '%s' is not a global tag") % n)
6730 else:
6732 else:
6731 raise error.Abort(_("tag '%s' is not a local tag") % n)
6733 raise error.Abort(_("tag '%s' is not a local tag") % n)
6732 rev_ = 'null'
6734 rev_ = 'null'
6733 if not message:
6735 if not message:
6734 # we don't translate commit messages
6736 # we don't translate commit messages
6735 message = 'Removed tag %s' % ', '.join(names)
6737 message = 'Removed tag %s' % ', '.join(names)
6736 elif not opts.get('force'):
6738 elif not opts.get('force'):
6737 for n in names:
6739 for n in names:
6738 if n in repo.tags():
6740 if n in repo.tags():
6739 raise error.Abort(_("tag '%s' already exists "
6741 raise error.Abort(_("tag '%s' already exists "
6740 "(use -f to force)") % n)
6742 "(use -f to force)") % n)
6741 if not opts.get('local'):
6743 if not opts.get('local'):
6742 p1, p2 = repo.dirstate.parents()
6744 p1, p2 = repo.dirstate.parents()
6743 if p2 != nullid:
6745 if p2 != nullid:
6744 raise error.Abort(_('uncommitted merge'))
6746 raise error.Abort(_('uncommitted merge'))
6745 bheads = repo.branchheads()
6747 bheads = repo.branchheads()
6746 if not opts.get('force') and bheads and p1 not in bheads:
6748 if not opts.get('force') and bheads and p1 not in bheads:
6747 raise error.Abort(_('not at a branch head (use -f to force)'))
6749 raise error.Abort(_('not at a branch head (use -f to force)'))
6748 r = scmutil.revsingle(repo, rev_).node()
6750 r = scmutil.revsingle(repo, rev_).node()
6749
6751
6750 if not message:
6752 if not message:
6751 # we don't translate commit messages
6753 # we don't translate commit messages
6752 message = ('Added tag %s for changeset %s' %
6754 message = ('Added tag %s for changeset %s' %
6753 (', '.join(names), short(r)))
6755 (', '.join(names), short(r)))
6754
6756
6755 date = opts.get('date')
6757 date = opts.get('date')
6756 if date:
6758 if date:
6757 date = util.parsedate(date)
6759 date = util.parsedate(date)
6758
6760
6759 if opts.get('remove'):
6761 if opts.get('remove'):
6760 editform = 'tag.remove'
6762 editform = 'tag.remove'
6761 else:
6763 else:
6762 editform = 'tag.add'
6764 editform = 'tag.add'
6763 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6765 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6764
6766
6765 # don't allow tagging the null rev
6767 # don't allow tagging the null rev
6766 if (not opts.get('remove') and
6768 if (not opts.get('remove') and
6767 scmutil.revsingle(repo, rev_).rev() == nullrev):
6769 scmutil.revsingle(repo, rev_).rev() == nullrev):
6768 raise error.Abort(_("cannot tag null revision"))
6770 raise error.Abort(_("cannot tag null revision"))
6769
6771
6770 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6772 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6771 editor=editor)
6773 editor=editor)
6772 finally:
6774 finally:
6773 release(lock, wlock)
6775 release(lock, wlock)
6774
6776
6775 @command('tags', formatteropts, '')
6777 @command('tags', formatteropts, '')
6776 def tags(ui, repo, **opts):
6778 def tags(ui, repo, **opts):
6777 """list repository tags
6779 """list repository tags
6778
6780
6779 This lists both regular and local tags. When the -v/--verbose
6781 This lists both regular and local tags. When the -v/--verbose
6780 switch is used, a third column "local" is printed for local tags.
6782 switch is used, a third column "local" is printed for local tags.
6781 When the -q/--quiet switch is used, only the tag name is printed.
6783 When the -q/--quiet switch is used, only the tag name is printed.
6782
6784
6783 Returns 0 on success.
6785 Returns 0 on success.
6784 """
6786 """
6785
6787
6786 fm = ui.formatter('tags', opts)
6788 fm = ui.formatter('tags', opts)
6787 hexfunc = fm.hexfunc
6789 hexfunc = fm.hexfunc
6788 tagtype = ""
6790 tagtype = ""
6789
6791
6790 for t, n in reversed(repo.tagslist()):
6792 for t, n in reversed(repo.tagslist()):
6791 hn = hexfunc(n)
6793 hn = hexfunc(n)
6792 label = 'tags.normal'
6794 label = 'tags.normal'
6793 tagtype = ''
6795 tagtype = ''
6794 if repo.tagtype(t) == 'local':
6796 if repo.tagtype(t) == 'local':
6795 label = 'tags.local'
6797 label = 'tags.local'
6796 tagtype = 'local'
6798 tagtype = 'local'
6797
6799
6798 fm.startitem()
6800 fm.startitem()
6799 fm.write('tag', '%s', t, label=label)
6801 fm.write('tag', '%s', t, label=label)
6800 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6802 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6801 fm.condwrite(not ui.quiet, 'rev node', fmt,
6803 fm.condwrite(not ui.quiet, 'rev node', fmt,
6802 repo.changelog.rev(n), hn, label=label)
6804 repo.changelog.rev(n), hn, label=label)
6803 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6805 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6804 tagtype, label=label)
6806 tagtype, label=label)
6805 fm.plain('\n')
6807 fm.plain('\n')
6806 fm.end()
6808 fm.end()
6807
6809
6808 @command('tip',
6810 @command('tip',
6809 [('p', 'patch', None, _('show patch')),
6811 [('p', 'patch', None, _('show patch')),
6810 ('g', 'git', None, _('use git extended diff format')),
6812 ('g', 'git', None, _('use git extended diff format')),
6811 ] + templateopts,
6813 ] + templateopts,
6812 _('[-p] [-g]'))
6814 _('[-p] [-g]'))
6813 def tip(ui, repo, **opts):
6815 def tip(ui, repo, **opts):
6814 """show the tip revision (DEPRECATED)
6816 """show the tip revision (DEPRECATED)
6815
6817
6816 The tip revision (usually just called the tip) is the changeset
6818 The tip revision (usually just called the tip) is the changeset
6817 most recently added to the repository (and therefore the most
6819 most recently added to the repository (and therefore the most
6818 recently changed head).
6820 recently changed head).
6819
6821
6820 If you have just made a commit, that commit will be the tip. If
6822 If you have just made a commit, that commit will be the tip. If
6821 you have just pulled changes from another repository, the tip of
6823 you have just pulled changes from another repository, the tip of
6822 that repository becomes the current tip. The "tip" tag is special
6824 that repository becomes the current tip. The "tip" tag is special
6823 and cannot be renamed or assigned to a different changeset.
6825 and cannot be renamed or assigned to a different changeset.
6824
6826
6825 This command is deprecated, please use :hg:`heads` instead.
6827 This command is deprecated, please use :hg:`heads` instead.
6826
6828
6827 Returns 0 on success.
6829 Returns 0 on success.
6828 """
6830 """
6829 displayer = cmdutil.show_changeset(ui, repo, opts)
6831 displayer = cmdutil.show_changeset(ui, repo, opts)
6830 displayer.show(repo['tip'])
6832 displayer.show(repo['tip'])
6831 displayer.close()
6833 displayer.close()
6832
6834
6833 @command('unbundle',
6835 @command('unbundle',
6834 [('u', 'update', None,
6836 [('u', 'update', None,
6835 _('update to new branch head if changesets were unbundled'))],
6837 _('update to new branch head if changesets were unbundled'))],
6836 _('[-u] FILE...'))
6838 _('[-u] FILE...'))
6837 def unbundle(ui, repo, fname1, *fnames, **opts):
6839 def unbundle(ui, repo, fname1, *fnames, **opts):
6838 """apply one or more changegroup files
6840 """apply one or more changegroup files
6839
6841
6840 Apply one or more compressed changegroup files generated by the
6842 Apply one or more compressed changegroup files generated by the
6841 bundle command.
6843 bundle command.
6842
6844
6843 Returns 0 on success, 1 if an update has unresolved files.
6845 Returns 0 on success, 1 if an update has unresolved files.
6844 """
6846 """
6845 fnames = (fname1,) + fnames
6847 fnames = (fname1,) + fnames
6846
6848
6847 with repo.lock():
6849 with repo.lock():
6848 for fname in fnames:
6850 for fname in fnames:
6849 f = hg.openpath(ui, fname)
6851 f = hg.openpath(ui, fname)
6850 gen = exchange.readbundle(ui, f, fname)
6852 gen = exchange.readbundle(ui, f, fname)
6851 if isinstance(gen, bundle2.unbundle20):
6853 if isinstance(gen, bundle2.unbundle20):
6852 tr = repo.transaction('unbundle')
6854 tr = repo.transaction('unbundle')
6853 try:
6855 try:
6854 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
6856 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
6855 url='bundle:' + fname)
6857 url='bundle:' + fname)
6856 tr.close()
6858 tr.close()
6857 except error.BundleUnknownFeatureError as exc:
6859 except error.BundleUnknownFeatureError as exc:
6858 raise error.Abort(_('%s: unknown bundle feature, %s')
6860 raise error.Abort(_('%s: unknown bundle feature, %s')
6859 % (fname, exc),
6861 % (fname, exc),
6860 hint=_("see https://mercurial-scm.org/"
6862 hint=_("see https://mercurial-scm.org/"
6861 "wiki/BundleFeature for more "
6863 "wiki/BundleFeature for more "
6862 "information"))
6864 "information"))
6863 finally:
6865 finally:
6864 if tr:
6866 if tr:
6865 tr.release()
6867 tr.release()
6866 changes = [r.get('return', 0)
6868 changes = [r.get('return', 0)
6867 for r in op.records['changegroup']]
6869 for r in op.records['changegroup']]
6868 modheads = changegroup.combineresults(changes)
6870 modheads = changegroup.combineresults(changes)
6869 elif isinstance(gen, streamclone.streamcloneapplier):
6871 elif isinstance(gen, streamclone.streamcloneapplier):
6870 raise error.Abort(
6872 raise error.Abort(
6871 _('packed bundles cannot be applied with '
6873 _('packed bundles cannot be applied with '
6872 '"hg unbundle"'),
6874 '"hg unbundle"'),
6873 hint=_('use "hg debugapplystreamclonebundle"'))
6875 hint=_('use "hg debugapplystreamclonebundle"'))
6874 else:
6876 else:
6875 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
6877 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
6876
6878
6877 return postincoming(ui, repo, modheads, opts.get('update'), None)
6879 return postincoming(ui, repo, modheads, opts.get('update'), None)
6878
6880
6879 @command('^update|up|checkout|co',
6881 @command('^update|up|checkout|co',
6880 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6882 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6881 ('c', 'check', None,
6883 ('c', 'check', None,
6882 _('update across branches if no uncommitted changes')),
6884 _('update across branches if no uncommitted changes')),
6883 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6885 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6884 ('r', 'rev', '', _('revision'), _('REV'))
6886 ('r', 'rev', '', _('revision'), _('REV'))
6885 ] + mergetoolopts,
6887 ] + mergetoolopts,
6886 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6888 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6887 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6889 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6888 tool=None):
6890 tool=None):
6889 """update working directory (or switch revisions)
6891 """update working directory (or switch revisions)
6890
6892
6891 Update the repository's working directory to the specified
6893 Update the repository's working directory to the specified
6892 changeset. If no changeset is specified, update to the tip of the
6894 changeset. If no changeset is specified, update to the tip of the
6893 current named branch and move the active bookmark (see :hg:`help
6895 current named branch and move the active bookmark (see :hg:`help
6894 bookmarks`).
6896 bookmarks`).
6895
6897
6896 Update sets the working directory's parent revision to the specified
6898 Update sets the working directory's parent revision to the specified
6897 changeset (see :hg:`help parents`).
6899 changeset (see :hg:`help parents`).
6898
6900
6899 If the changeset is not a descendant or ancestor of the working
6901 If the changeset is not a descendant or ancestor of the working
6900 directory's parent, the update is aborted. With the -c/--check
6902 directory's parent, the update is aborted. With the -c/--check
6901 option, the working directory is checked for uncommitted changes; if
6903 option, the working directory is checked for uncommitted changes; if
6902 none are found, the working directory is updated to the specified
6904 none are found, the working directory is updated to the specified
6903 changeset.
6905 changeset.
6904
6906
6905 .. container:: verbose
6907 .. container:: verbose
6906
6908
6907 The following rules apply when the working directory contains
6909 The following rules apply when the working directory contains
6908 uncommitted changes:
6910 uncommitted changes:
6909
6911
6910 1. If neither -c/--check nor -C/--clean is specified, and if
6912 1. If neither -c/--check nor -C/--clean is specified, and if
6911 the requested changeset is an ancestor or descendant of
6913 the requested changeset is an ancestor or descendant of
6912 the working directory's parent, the uncommitted changes
6914 the working directory's parent, the uncommitted changes
6913 are merged into the requested changeset and the merged
6915 are merged into the requested changeset and the merged
6914 result is left uncommitted. If the requested changeset is
6916 result is left uncommitted. If the requested changeset is
6915 not an ancestor or descendant (that is, it is on another
6917 not an ancestor or descendant (that is, it is on another
6916 branch), the update is aborted and the uncommitted changes
6918 branch), the update is aborted and the uncommitted changes
6917 are preserved.
6919 are preserved.
6918
6920
6919 2. With the -c/--check option, the update is aborted and the
6921 2. With the -c/--check option, the update is aborted and the
6920 uncommitted changes are preserved.
6922 uncommitted changes are preserved.
6921
6923
6922 3. With the -C/--clean option, uncommitted changes are discarded and
6924 3. With the -C/--clean option, uncommitted changes are discarded and
6923 the working directory is updated to the requested changeset.
6925 the working directory is updated to the requested changeset.
6924
6926
6925 To cancel an uncommitted merge (and lose your changes), use
6927 To cancel an uncommitted merge (and lose your changes), use
6926 :hg:`update --clean .`.
6928 :hg:`update --clean .`.
6927
6929
6928 Use null as the changeset to remove the working directory (like
6930 Use null as the changeset to remove the working directory (like
6929 :hg:`clone -U`).
6931 :hg:`clone -U`).
6930
6932
6931 If you want to revert just one file to an older revision, use
6933 If you want to revert just one file to an older revision, use
6932 :hg:`revert [-r REV] NAME`.
6934 :hg:`revert [-r REV] NAME`.
6933
6935
6934 See :hg:`help dates` for a list of formats valid for -d/--date.
6936 See :hg:`help dates` for a list of formats valid for -d/--date.
6935
6937
6936 Returns 0 on success, 1 if there are unresolved files.
6938 Returns 0 on success, 1 if there are unresolved files.
6937 """
6939 """
6938 movemarkfrom = None
6940 movemarkfrom = None
6939 if rev and node:
6941 if rev and node:
6940 raise error.Abort(_("please specify just one revision"))
6942 raise error.Abort(_("please specify just one revision"))
6941
6943
6942 if rev is None or rev == '':
6944 if rev is None or rev == '':
6943 rev = node
6945 rev = node
6944
6946
6945 with repo.wlock():
6947 with repo.wlock():
6946 cmdutil.clearunfinished(repo)
6948 cmdutil.clearunfinished(repo)
6947
6949
6948 if date:
6950 if date:
6949 if rev is not None:
6951 if rev is not None:
6950 raise error.Abort(_("you can't specify a revision and a date"))
6952 raise error.Abort(_("you can't specify a revision and a date"))
6951 rev = cmdutil.finddate(ui, repo, date)
6953 rev = cmdutil.finddate(ui, repo, date)
6952
6954
6953 # if we defined a bookmark, we have to remember the original name
6955 # if we defined a bookmark, we have to remember the original name
6954 brev = rev
6956 brev = rev
6955 rev = scmutil.revsingle(repo, rev, rev).rev()
6957 rev = scmutil.revsingle(repo, rev, rev).rev()
6956
6958
6957 if check and clean:
6959 if check and clean:
6958 raise error.Abort(_("cannot specify both -c/--check and -C/--clean")
6960 raise error.Abort(_("cannot specify both -c/--check and -C/--clean")
6959 )
6961 )
6960
6962
6961 if check:
6963 if check:
6962 cmdutil.bailifchanged(repo, merge=False)
6964 cmdutil.bailifchanged(repo, merge=False)
6963 if rev is None:
6965 if rev is None:
6964 updata = destutil.destupdate(repo, clean=clean, check=check)
6966 updata = destutil.destupdate(repo, clean=clean, check=check)
6965 rev, movemarkfrom, brev = updata
6967 rev, movemarkfrom, brev = updata
6966
6968
6967 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
6969 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
6968
6970
6969 if clean:
6971 if clean:
6970 ret = hg.clean(repo, rev)
6972 ret = hg.clean(repo, rev)
6971 else:
6973 else:
6972 ret = hg.update(repo, rev)
6974 ret = hg.update(repo, rev)
6973
6975
6974 if not ret and movemarkfrom:
6976 if not ret and movemarkfrom:
6975 if movemarkfrom == repo['.'].node():
6977 if movemarkfrom == repo['.'].node():
6976 pass # no-op update
6978 pass # no-op update
6977 elif bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
6979 elif bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
6978 ui.status(_("updating bookmark %s\n") % repo._activebookmark)
6980 ui.status(_("updating bookmark %s\n") % repo._activebookmark)
6979 else:
6981 else:
6980 # this can happen with a non-linear update
6982 # this can happen with a non-linear update
6981 ui.status(_("(leaving bookmark %s)\n") %
6983 ui.status(_("(leaving bookmark %s)\n") %
6982 repo._activebookmark)
6984 repo._activebookmark)
6983 bookmarks.deactivate(repo)
6985 bookmarks.deactivate(repo)
6984 elif brev in repo._bookmarks:
6986 elif brev in repo._bookmarks:
6985 bookmarks.activate(repo, brev)
6987 bookmarks.activate(repo, brev)
6986 ui.status(_("(activating bookmark %s)\n") % brev)
6988 ui.status(_("(activating bookmark %s)\n") % brev)
6987 elif brev:
6989 elif brev:
6988 if repo._activebookmark:
6990 if repo._activebookmark:
6989 ui.status(_("(leaving bookmark %s)\n") %
6991 ui.status(_("(leaving bookmark %s)\n") %
6990 repo._activebookmark)
6992 repo._activebookmark)
6991 bookmarks.deactivate(repo)
6993 bookmarks.deactivate(repo)
6992
6994
6993 return ret
6995 return ret
6994
6996
6995 @command('verify', [])
6997 @command('verify', [])
6996 def verify(ui, repo):
6998 def verify(ui, repo):
6997 """verify the integrity of the repository
6999 """verify the integrity of the repository
6998
7000
6999 Verify the integrity of the current repository.
7001 Verify the integrity of the current repository.
7000
7002
7001 This will perform an extensive check of the repository's
7003 This will perform an extensive check of the repository's
7002 integrity, validating the hashes and checksums of each entry in
7004 integrity, validating the hashes and checksums of each entry in
7003 the changelog, manifest, and tracked files, as well as the
7005 the changelog, manifest, and tracked files, as well as the
7004 integrity of their crosslinks and indices.
7006 integrity of their crosslinks and indices.
7005
7007
7006 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7008 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7007 for more information about recovery from corruption of the
7009 for more information about recovery from corruption of the
7008 repository.
7010 repository.
7009
7011
7010 Returns 0 on success, 1 if errors are encountered.
7012 Returns 0 on success, 1 if errors are encountered.
7011 """
7013 """
7012 return hg.verify(repo)
7014 return hg.verify(repo)
7013
7015
7014 @command('version', [], norepo=True)
7016 @command('version', [], norepo=True)
7015 def version_(ui):
7017 def version_(ui):
7016 """output version and copyright information"""
7018 """output version and copyright information"""
7017 ui.write(_("Mercurial Distributed SCM (version %s)\n")
7019 ui.write(_("Mercurial Distributed SCM (version %s)\n")
7018 % util.version())
7020 % util.version())
7019 ui.status(_(
7021 ui.status(_(
7020 "(see https://mercurial-scm.org for more information)\n"
7022 "(see https://mercurial-scm.org for more information)\n"
7021 "\nCopyright (C) 2005-2016 Matt Mackall and others\n"
7023 "\nCopyright (C) 2005-2016 Matt Mackall and others\n"
7022 "This is free software; see the source for copying conditions. "
7024 "This is free software; see the source for copying conditions. "
7023 "There is NO\nwarranty; "
7025 "There is NO\nwarranty; "
7024 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7026 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7025 ))
7027 ))
7026
7028
7027 ui.note(_("\nEnabled extensions:\n\n"))
7029 ui.note(_("\nEnabled extensions:\n\n"))
7028 if ui.verbose:
7030 if ui.verbose:
7029 # format names and versions into columns
7031 # format names and versions into columns
7030 names = []
7032 names = []
7031 vers = []
7033 vers = []
7032 for name, module in extensions.extensions():
7034 for name, module in extensions.extensions():
7033 names.append(name)
7035 names.append(name)
7034 vers.append(extensions.moduleversion(module))
7036 vers.append(extensions.moduleversion(module))
7035 if names:
7037 if names:
7036 maxnamelen = max(len(n) for n in names)
7038 maxnamelen = max(len(n) for n in names)
7037 for i, name in enumerate(names):
7039 for i, name in enumerate(names):
7038 ui.write(" %-*s %s\n" % (maxnamelen, name, vers[i]))
7040 ui.write(" %-*s %s\n" % (maxnamelen, name, vers[i]))
@@ -1,783 +1,841 b''
1 $ hg init
1 $ hg init
2
2
3 no bookmarks
3 no bookmarks
4
4
5 $ hg bookmarks
5 $ hg bookmarks
6 no bookmarks set
6 no bookmarks set
7
7
8 $ hg bookmarks -Tjson
8 $ hg bookmarks -Tjson
9 [
9 [
10 ]
10 ]
11
11
12 bookmark rev -1
12 bookmark rev -1
13
13
14 $ hg bookmark X
14 $ hg bookmark X
15
15
16 list bookmarks
16 list bookmarks
17
17
18 $ hg bookmarks
18 $ hg bookmarks
19 * X -1:000000000000
19 * X -1:000000000000
20
20
21 list bookmarks with color
21 list bookmarks with color
22
22
23 $ hg --config extensions.color= --config color.mode=ansi \
23 $ hg --config extensions.color= --config color.mode=ansi \
24 > bookmarks --color=always
24 > bookmarks --color=always
25 \x1b[0;32m * \x1b[0m\x1b[0;32mX\x1b[0m\x1b[0;32m -1:000000000000\x1b[0m (esc)
25 \x1b[0;32m * \x1b[0m\x1b[0;32mX\x1b[0m\x1b[0;32m -1:000000000000\x1b[0m (esc)
26
26
27 $ echo a > a
27 $ echo a > a
28 $ hg add a
28 $ hg add a
29 $ hg commit -m 0
29 $ hg commit -m 0
30
30
31 bookmark X moved to rev 0
31 bookmark X moved to rev 0
32
32
33 $ hg bookmarks
33 $ hg bookmarks
34 * X 0:f7b1eb17ad24
34 * X 0:f7b1eb17ad24
35
35
36 look up bookmark
36 look up bookmark
37
37
38 $ hg log -r X
38 $ hg log -r X
39 changeset: 0:f7b1eb17ad24
39 changeset: 0:f7b1eb17ad24
40 bookmark: X
40 bookmark: X
41 tag: tip
41 tag: tip
42 user: test
42 user: test
43 date: Thu Jan 01 00:00:00 1970 +0000
43 date: Thu Jan 01 00:00:00 1970 +0000
44 summary: 0
44 summary: 0
45
45
46
46
47 second bookmark for rev 0, command should work even with ui.strict on
47 second bookmark for rev 0, command should work even with ui.strict on
48
48
49 $ hg --config ui.strict=1 bookmark X2
49 $ hg --config ui.strict=1 bookmark X2
50
50
51 bookmark rev -1 again
51 bookmark rev -1 again
52
52
53 $ hg bookmark -r null Y
53 $ hg bookmark -r null Y
54
54
55 list bookmarks
55 list bookmarks
56
56
57 $ hg bookmarks
57 $ hg bookmarks
58 X 0:f7b1eb17ad24
58 X 0:f7b1eb17ad24
59 * X2 0:f7b1eb17ad24
59 * X2 0:f7b1eb17ad24
60 Y -1:000000000000
60 Y -1:000000000000
61
61
62 $ echo b > b
62 $ echo b > b
63 $ hg add b
63 $ hg add b
64 $ hg commit -m 1
64 $ hg commit -m 1
65
65
66 $ hg bookmarks -Tjson
66 $ hg bookmarks -Tjson
67 [
67 [
68 {
68 {
69 "active": false,
69 "active": false,
70 "bookmark": "X",
70 "bookmark": "X",
71 "node": "f7b1eb17ad24730a1651fccd46c43826d1bbc2ac",
71 "node": "f7b1eb17ad24730a1651fccd46c43826d1bbc2ac",
72 "rev": 0
72 "rev": 0
73 },
73 },
74 {
74 {
75 "active": true,
75 "active": true,
76 "bookmark": "X2",
76 "bookmark": "X2",
77 "node": "925d80f479bb026b0fb3deb27503780b13f74123",
77 "node": "925d80f479bb026b0fb3deb27503780b13f74123",
78 "rev": 1
78 "rev": 1
79 },
79 },
80 {
80 {
81 "active": false,
81 "active": false,
82 "bookmark": "Y",
82 "bookmark": "Y",
83 "node": "0000000000000000000000000000000000000000",
83 "node": "0000000000000000000000000000000000000000",
84 "rev": -1
84 "rev": -1
85 }
85 }
86 ]
86 ]
87
87
88 bookmarks revset
88 bookmarks revset
89
89
90 $ hg log -r 'bookmark()'
90 $ hg log -r 'bookmark()'
91 changeset: 0:f7b1eb17ad24
91 changeset: 0:f7b1eb17ad24
92 bookmark: X
92 bookmark: X
93 user: test
93 user: test
94 date: Thu Jan 01 00:00:00 1970 +0000
94 date: Thu Jan 01 00:00:00 1970 +0000
95 summary: 0
95 summary: 0
96
96
97 changeset: 1:925d80f479bb
97 changeset: 1:925d80f479bb
98 bookmark: X2
98 bookmark: X2
99 tag: tip
99 tag: tip
100 user: test
100 user: test
101 date: Thu Jan 01 00:00:00 1970 +0000
101 date: Thu Jan 01 00:00:00 1970 +0000
102 summary: 1
102 summary: 1
103
103
104 $ hg log -r 'bookmark(Y)'
104 $ hg log -r 'bookmark(Y)'
105 $ hg log -r 'bookmark(X2)'
105 $ hg log -r 'bookmark(X2)'
106 changeset: 1:925d80f479bb
106 changeset: 1:925d80f479bb
107 bookmark: X2
107 bookmark: X2
108 tag: tip
108 tag: tip
109 user: test
109 user: test
110 date: Thu Jan 01 00:00:00 1970 +0000
110 date: Thu Jan 01 00:00:00 1970 +0000
111 summary: 1
111 summary: 1
112
112
113 $ hg log -r 'bookmark("re:X")'
113 $ hg log -r 'bookmark("re:X")'
114 changeset: 0:f7b1eb17ad24
114 changeset: 0:f7b1eb17ad24
115 bookmark: X
115 bookmark: X
116 user: test
116 user: test
117 date: Thu Jan 01 00:00:00 1970 +0000
117 date: Thu Jan 01 00:00:00 1970 +0000
118 summary: 0
118 summary: 0
119
119
120 changeset: 1:925d80f479bb
120 changeset: 1:925d80f479bb
121 bookmark: X2
121 bookmark: X2
122 tag: tip
122 tag: tip
123 user: test
123 user: test
124 date: Thu Jan 01 00:00:00 1970 +0000
124 date: Thu Jan 01 00:00:00 1970 +0000
125 summary: 1
125 summary: 1
126
126
127 $ hg log -r 'bookmark("literal:X")'
127 $ hg log -r 'bookmark("literal:X")'
128 changeset: 0:f7b1eb17ad24
128 changeset: 0:f7b1eb17ad24
129 bookmark: X
129 bookmark: X
130 user: test
130 user: test
131 date: Thu Jan 01 00:00:00 1970 +0000
131 date: Thu Jan 01 00:00:00 1970 +0000
132 summary: 0
132 summary: 0
133
133
134
134
135 $ hg log -r 'bookmark(unknown)'
135 $ hg log -r 'bookmark(unknown)'
136 abort: bookmark 'unknown' does not exist!
136 abort: bookmark 'unknown' does not exist!
137 [255]
137 [255]
138 $ hg log -r 'bookmark("literal:unknown")'
138 $ hg log -r 'bookmark("literal:unknown")'
139 abort: bookmark 'unknown' does not exist!
139 abort: bookmark 'unknown' does not exist!
140 [255]
140 [255]
141 $ hg log -r 'bookmark("re:unknown")'
141 $ hg log -r 'bookmark("re:unknown")'
142 abort: no bookmarks exist that match 'unknown'!
142 abort: no bookmarks exist that match 'unknown'!
143 [255]
143 [255]
144 $ hg log -r 'present(bookmark("literal:unknown"))'
144 $ hg log -r 'present(bookmark("literal:unknown"))'
145 $ hg log -r 'present(bookmark("re:unknown"))'
145 $ hg log -r 'present(bookmark("re:unknown"))'
146
146
147 $ hg help revsets | grep 'bookmark('
147 $ hg help revsets | grep 'bookmark('
148 "bookmark([name])"
148 "bookmark([name])"
149
149
150 bookmarks X and X2 moved to rev 1, Y at rev -1
150 bookmarks X and X2 moved to rev 1, Y at rev -1
151
151
152 $ hg bookmarks
152 $ hg bookmarks
153 X 0:f7b1eb17ad24
153 X 0:f7b1eb17ad24
154 * X2 1:925d80f479bb
154 * X2 1:925d80f479bb
155 Y -1:000000000000
155 Y -1:000000000000
156
156
157 bookmark rev 0 again
157 bookmark rev 0 again
158
158
159 $ hg bookmark -r 0 Z
159 $ hg bookmark -r 0 Z
160
160
161 $ hg update X
161 $ hg update X
162 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
162 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
163 (activating bookmark X)
163 (activating bookmark X)
164 $ echo c > c
164 $ echo c > c
165 $ hg add c
165 $ hg add c
166 $ hg commit -m 2
166 $ hg commit -m 2
167 created new head
167 created new head
168
168
169 bookmarks X moved to rev 2, Y at rev -1, Z at rev 0
169 bookmarks X moved to rev 2, Y at rev -1, Z at rev 0
170
170
171 $ hg bookmarks
171 $ hg bookmarks
172 * X 2:db815d6d32e6
172 * X 2:db815d6d32e6
173 X2 1:925d80f479bb
173 X2 1:925d80f479bb
174 Y -1:000000000000
174 Y -1:000000000000
175 Z 0:f7b1eb17ad24
175 Z 0:f7b1eb17ad24
176
176
177 rename nonexistent bookmark
177 rename nonexistent bookmark
178
178
179 $ hg bookmark -m A B
179 $ hg bookmark -m A B
180 abort: bookmark 'A' does not exist
180 abort: bookmark 'A' does not exist
181 [255]
181 [255]
182
182
183 rename to existent bookmark
183 rename to existent bookmark
184
184
185 $ hg bookmark -m X Y
185 $ hg bookmark -m X Y
186 abort: bookmark 'Y' already exists (use -f to force)
186 abort: bookmark 'Y' already exists (use -f to force)
187 [255]
187 [255]
188
188
189 force rename to existent bookmark
189 force rename to existent bookmark
190
190
191 $ hg bookmark -f -m X Y
191 $ hg bookmark -f -m X Y
192
192
193 list bookmarks
193 list bookmarks
194
194
195 $ hg bookmark
195 $ hg bookmark
196 X2 1:925d80f479bb
196 X2 1:925d80f479bb
197 * Y 2:db815d6d32e6
197 * Y 2:db815d6d32e6
198 Z 0:f7b1eb17ad24
198 Z 0:f7b1eb17ad24
199
199
200 bookmarks from a revset
200 bookmarks from a revset
201 $ hg bookmark -r '.^1' REVSET
201 $ hg bookmark -r '.^1' REVSET
202 $ hg bookmark -r ':tip' TIP
202 $ hg bookmark -r ':tip' TIP
203 $ hg up -q TIP
203 $ hg up -q TIP
204 $ hg bookmarks
204 $ hg bookmarks
205 REVSET 0:f7b1eb17ad24
205 REVSET 0:f7b1eb17ad24
206 * TIP 2:db815d6d32e6
206 * TIP 2:db815d6d32e6
207 X2 1:925d80f479bb
207 X2 1:925d80f479bb
208 Y 2:db815d6d32e6
208 Y 2:db815d6d32e6
209 Z 0:f7b1eb17ad24
209 Z 0:f7b1eb17ad24
210
210
211 $ hg bookmark -d REVSET
211 $ hg bookmark -d REVSET
212 $ hg bookmark -d TIP
212 $ hg bookmark -d TIP
213
213
214 rename without new name or multiple names
214 rename without new name or multiple names
215
215
216 $ hg bookmark -m Y
216 $ hg bookmark -m Y
217 abort: new bookmark name required
217 abort: new bookmark name required
218 [255]
218 [255]
219 $ hg bookmark -m Y Y2 Y3
219 $ hg bookmark -m Y Y2 Y3
220 abort: only one new bookmark name allowed
220 abort: only one new bookmark name allowed
221 [255]
221 [255]
222
222
223 delete without name
223 delete without name
224
224
225 $ hg bookmark -d
225 $ hg bookmark -d
226 abort: bookmark name required
226 abort: bookmark name required
227 [255]
227 [255]
228
228
229 delete nonexistent bookmark
229 delete nonexistent bookmark
230
230
231 $ hg bookmark -d A
231 $ hg bookmark -d A
232 abort: bookmark 'A' does not exist
232 abort: bookmark 'A' does not exist
233 [255]
233 [255]
234
234
235 bookmark name with spaces should be stripped
235 bookmark name with spaces should be stripped
236
236
237 $ hg bookmark ' x y '
237 $ hg bookmark ' x y '
238
238
239 list bookmarks
239 list bookmarks
240
240
241 $ hg bookmarks
241 $ hg bookmarks
242 X2 1:925d80f479bb
242 X2 1:925d80f479bb
243 Y 2:db815d6d32e6
243 Y 2:db815d6d32e6
244 Z 0:f7b1eb17ad24
244 Z 0:f7b1eb17ad24
245 * x y 2:db815d6d32e6
245 * x y 2:db815d6d32e6
246
246
247 look up stripped bookmark name
247 look up stripped bookmark name
248
248
249 $ hg log -r '"x y"'
249 $ hg log -r '"x y"'
250 changeset: 2:db815d6d32e6
250 changeset: 2:db815d6d32e6
251 bookmark: Y
251 bookmark: Y
252 bookmark: x y
252 bookmark: x y
253 tag: tip
253 tag: tip
254 parent: 0:f7b1eb17ad24
254 parent: 0:f7b1eb17ad24
255 user: test
255 user: test
256 date: Thu Jan 01 00:00:00 1970 +0000
256 date: Thu Jan 01 00:00:00 1970 +0000
257 summary: 2
257 summary: 2
258
258
259
259
260 reject bookmark name with newline
260 reject bookmark name with newline
261
261
262 $ hg bookmark '
262 $ hg bookmark '
263 > '
263 > '
264 abort: bookmark names cannot consist entirely of whitespace
264 abort: bookmark names cannot consist entirely of whitespace
265 [255]
265 [255]
266
266
267 $ hg bookmark -m Z '
267 $ hg bookmark -m Z '
268 > '
268 > '
269 abort: bookmark names cannot consist entirely of whitespace
269 abort: bookmark names cannot consist entirely of whitespace
270 [255]
270 [255]
271
271
272 bookmark with reserved name
272 bookmark with reserved name
273
273
274 $ hg bookmark tip
274 $ hg bookmark tip
275 abort: the name 'tip' is reserved
275 abort: the name 'tip' is reserved
276 [255]
276 [255]
277
277
278 $ hg bookmark .
278 $ hg bookmark .
279 abort: the name '.' is reserved
279 abort: the name '.' is reserved
280 [255]
280 [255]
281
281
282 $ hg bookmark null
282 $ hg bookmark null
283 abort: the name 'null' is reserved
283 abort: the name 'null' is reserved
284 [255]
284 [255]
285
285
286
286
287 bookmark with existing name
287 bookmark with existing name
288
288
289 $ hg bookmark X2
289 $ hg bookmark X2
290 abort: bookmark 'X2' already exists (use -f to force)
290 abort: bookmark 'X2' already exists (use -f to force)
291 [255]
291 [255]
292
292
293 $ hg bookmark -m Y Z
293 $ hg bookmark -m Y Z
294 abort: bookmark 'Z' already exists (use -f to force)
294 abort: bookmark 'Z' already exists (use -f to force)
295 [255]
295 [255]
296
296
297 bookmark with name of branch
297 bookmark with name of branch
298
298
299 $ hg bookmark default
299 $ hg bookmark default
300 abort: a bookmark cannot have the name of an existing branch
300 abort: a bookmark cannot have the name of an existing branch
301 [255]
301 [255]
302
302
303 $ hg bookmark -m Y default
303 $ hg bookmark -m Y default
304 abort: a bookmark cannot have the name of an existing branch
304 abort: a bookmark cannot have the name of an existing branch
305 [255]
305 [255]
306
306
307 bookmark with integer name
307 bookmark with integer name
308
308
309 $ hg bookmark 10
309 $ hg bookmark 10
310 abort: cannot use an integer as a name
310 abort: cannot use an integer as a name
311 [255]
311 [255]
312
312
313 incompatible options
313 incompatible options
314
314
315 $ hg bookmark -m Y -d Z
315 $ hg bookmark -m Y -d Z
316 abort: --delete and --rename are incompatible
316 abort: --delete and --rename are incompatible
317 [255]
317 [255]
318
318
319 $ hg bookmark -r 1 -d Z
319 $ hg bookmark -r 1 -d Z
320 abort: --rev is incompatible with --delete
320 abort: --rev is incompatible with --delete
321 [255]
321 [255]
322
322
323 $ hg bookmark -r 1 -m Z Y
323 $ hg bookmark -r 1 -m Z Y
324 abort: --rev is incompatible with --rename
324 abort: --rev is incompatible with --rename
325 [255]
325 [255]
326
326
327 force bookmark with existing name
327 force bookmark with existing name
328
328
329 $ hg bookmark -f X2
329 $ hg bookmark -f X2
330
330
331 force bookmark back to where it was, should deactivate it
331 force bookmark back to where it was, should deactivate it
332
332
333 $ hg bookmark -fr1 X2
333 $ hg bookmark -fr1 X2
334 $ hg bookmarks
334 $ hg bookmarks
335 X2 1:925d80f479bb
335 X2 1:925d80f479bb
336 Y 2:db815d6d32e6
336 Y 2:db815d6d32e6
337 Z 0:f7b1eb17ad24
337 Z 0:f7b1eb17ad24
338 x y 2:db815d6d32e6
338 x y 2:db815d6d32e6
339
339
340 forward bookmark to descendant without --force
340 forward bookmark to descendant without --force
341
341
342 $ hg bookmark Z
342 $ hg bookmark Z
343 moving bookmark 'Z' forward from f7b1eb17ad24
343 moving bookmark 'Z' forward from f7b1eb17ad24
344
344
345 list bookmarks
345 list bookmarks
346
346
347 $ hg bookmark
347 $ hg bookmark
348 X2 1:925d80f479bb
348 X2 1:925d80f479bb
349 Y 2:db815d6d32e6
349 Y 2:db815d6d32e6
350 * Z 2:db815d6d32e6
350 * Z 2:db815d6d32e6
351 x y 2:db815d6d32e6
351 x y 2:db815d6d32e6
352
352
353 revision but no bookmark name
353 revision but no bookmark name
354
354
355 $ hg bookmark -r .
355 $ hg bookmark -r .
356 abort: bookmark name required
356 abort: bookmark name required
357 [255]
357 [255]
358
358
359 bookmark name with whitespace only
359 bookmark name with whitespace only
360
360
361 $ hg bookmark ' '
361 $ hg bookmark ' '
362 abort: bookmark names cannot consist entirely of whitespace
362 abort: bookmark names cannot consist entirely of whitespace
363 [255]
363 [255]
364
364
365 $ hg bookmark -m Y ' '
365 $ hg bookmark -m Y ' '
366 abort: bookmark names cannot consist entirely of whitespace
366 abort: bookmark names cannot consist entirely of whitespace
367 [255]
367 [255]
368
368
369 invalid bookmark
369 invalid bookmark
370
370
371 $ hg bookmark 'foo:bar'
371 $ hg bookmark 'foo:bar'
372 abort: ':' cannot be used in a name
372 abort: ':' cannot be used in a name
373 [255]
373 [255]
374
374
375 $ hg bookmark 'foo
375 $ hg bookmark 'foo
376 > bar'
376 > bar'
377 abort: '\n' cannot be used in a name
377 abort: '\n' cannot be used in a name
378 [255]
378 [255]
379
379
380 the bookmark extension should be ignored now that it is part of core
380 the bookmark extension should be ignored now that it is part of core
381
381
382 $ echo "[extensions]" >> $HGRCPATH
382 $ echo "[extensions]" >> $HGRCPATH
383 $ echo "bookmarks=" >> $HGRCPATH
383 $ echo "bookmarks=" >> $HGRCPATH
384 $ hg bookmarks
384 $ hg bookmarks
385 X2 1:925d80f479bb
385 X2 1:925d80f479bb
386 Y 2:db815d6d32e6
386 Y 2:db815d6d32e6
387 * Z 2:db815d6d32e6
387 * Z 2:db815d6d32e6
388 x y 2:db815d6d32e6
388 x y 2:db815d6d32e6
389
389
390 test summary
390 test summary
391
391
392 $ hg summary
392 $ hg summary
393 parent: 2:db815d6d32e6 tip
393 parent: 2:db815d6d32e6 tip
394 2
394 2
395 branch: default
395 branch: default
396 bookmarks: *Z Y x y
396 bookmarks: *Z Y x y
397 commit: (clean)
397 commit: (clean)
398 update: 1 new changesets, 2 branch heads (merge)
398 update: 1 new changesets, 2 branch heads (merge)
399 phases: 3 draft
399 phases: 3 draft
400
400
401 test id
401 test id
402
402
403 $ hg id
403 $ hg id
404 db815d6d32e6 tip Y/Z/x y
404 db815d6d32e6 tip Y/Z/x y
405
405
406 test rollback
406 test rollback
407
407
408 $ echo foo > f1
408 $ echo foo > f1
409 $ hg bookmark tmp-rollback
409 $ hg bookmark tmp-rollback
410 $ hg ci -Amr
410 $ hg ci -Amr
411 adding f1
411 adding f1
412 $ hg bookmarks
412 $ hg bookmarks
413 X2 1:925d80f479bb
413 X2 1:925d80f479bb
414 Y 2:db815d6d32e6
414 Y 2:db815d6d32e6
415 Z 2:db815d6d32e6
415 Z 2:db815d6d32e6
416 * tmp-rollback 3:2bf5cfec5864
416 * tmp-rollback 3:2bf5cfec5864
417 x y 2:db815d6d32e6
417 x y 2:db815d6d32e6
418 $ hg rollback
418 $ hg rollback
419 repository tip rolled back to revision 2 (undo commit)
419 repository tip rolled back to revision 2 (undo commit)
420 working directory now based on revision 2
420 working directory now based on revision 2
421 $ hg bookmarks
421 $ hg bookmarks
422 X2 1:925d80f479bb
422 X2 1:925d80f479bb
423 Y 2:db815d6d32e6
423 Y 2:db815d6d32e6
424 Z 2:db815d6d32e6
424 Z 2:db815d6d32e6
425 * tmp-rollback 2:db815d6d32e6
425 * tmp-rollback 2:db815d6d32e6
426 x y 2:db815d6d32e6
426 x y 2:db815d6d32e6
427 $ hg bookmark -f Z -r 1
427 $ hg bookmark -f Z -r 1
428 $ hg rollback
428 $ hg rollback
429 repository tip rolled back to revision 2 (undo bookmark)
429 repository tip rolled back to revision 2 (undo bookmark)
430 $ hg bookmarks
430 $ hg bookmarks
431 X2 1:925d80f479bb
431 X2 1:925d80f479bb
432 Y 2:db815d6d32e6
432 Y 2:db815d6d32e6
433 Z 2:db815d6d32e6
433 Z 2:db815d6d32e6
434 * tmp-rollback 2:db815d6d32e6
434 * tmp-rollback 2:db815d6d32e6
435 x y 2:db815d6d32e6
435 x y 2:db815d6d32e6
436 $ hg bookmark -d tmp-rollback
436 $ hg bookmark -d tmp-rollback
437
437
438 activate bookmark on working dir parent without --force
438 activate bookmark on working dir parent without --force
439
439
440 $ hg bookmark --inactive Z
440 $ hg bookmark --inactive Z
441 $ hg bookmark Z
441 $ hg bookmark Z
442
442
443 test clone
443 test clone
444
444
445 $ hg bookmark -r 2 -i @
445 $ hg bookmark -r 2 -i @
446 $ hg bookmark -r 2 -i a@
446 $ hg bookmark -r 2 -i a@
447 $ hg bookmarks
447 $ hg bookmarks
448 @ 2:db815d6d32e6
448 @ 2:db815d6d32e6
449 X2 1:925d80f479bb
449 X2 1:925d80f479bb
450 Y 2:db815d6d32e6
450 Y 2:db815d6d32e6
451 * Z 2:db815d6d32e6
451 * Z 2:db815d6d32e6
452 a@ 2:db815d6d32e6
452 a@ 2:db815d6d32e6
453 x y 2:db815d6d32e6
453 x y 2:db815d6d32e6
454 $ hg clone . cloned-bookmarks
454 $ hg clone . cloned-bookmarks
455 updating to bookmark @
455 updating to bookmark @
456 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
456 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
457 $ hg -R cloned-bookmarks bookmarks
457 $ hg -R cloned-bookmarks bookmarks
458 * @ 2:db815d6d32e6
458 * @ 2:db815d6d32e6
459 X2 1:925d80f479bb
459 X2 1:925d80f479bb
460 Y 2:db815d6d32e6
460 Y 2:db815d6d32e6
461 Z 2:db815d6d32e6
461 Z 2:db815d6d32e6
462 a@ 2:db815d6d32e6
462 a@ 2:db815d6d32e6
463 x y 2:db815d6d32e6
463 x y 2:db815d6d32e6
464
464
465 test clone with pull protocol
465 test clone with pull protocol
466
466
467 $ hg clone --pull . cloned-bookmarks-pull
467 $ hg clone --pull . cloned-bookmarks-pull
468 requesting all changes
468 requesting all changes
469 adding changesets
469 adding changesets
470 adding manifests
470 adding manifests
471 adding file changes
471 adding file changes
472 added 3 changesets with 3 changes to 3 files (+1 heads)
472 added 3 changesets with 3 changes to 3 files (+1 heads)
473 updating to bookmark @
473 updating to bookmark @
474 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
474 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
475 $ hg -R cloned-bookmarks-pull bookmarks
475 $ hg -R cloned-bookmarks-pull bookmarks
476 * @ 2:db815d6d32e6
476 * @ 2:db815d6d32e6
477 X2 1:925d80f479bb
477 X2 1:925d80f479bb
478 Y 2:db815d6d32e6
478 Y 2:db815d6d32e6
479 Z 2:db815d6d32e6
479 Z 2:db815d6d32e6
480 a@ 2:db815d6d32e6
480 a@ 2:db815d6d32e6
481 x y 2:db815d6d32e6
481 x y 2:db815d6d32e6
482
482
483 delete multiple bookmarks at once
483 delete multiple bookmarks at once
484
484
485 $ hg bookmark -d @ a@
485 $ hg bookmark -d @ a@
486
486
487 test clone with a bookmark named "default" (issue3677)
487 test clone with a bookmark named "default" (issue3677)
488
488
489 $ hg bookmark -r 1 -f -i default
489 $ hg bookmark -r 1 -f -i default
490 $ hg clone . cloned-bookmark-default
490 $ hg clone . cloned-bookmark-default
491 updating to branch default
491 updating to branch default
492 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
492 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
493 $ hg -R cloned-bookmark-default bookmarks
493 $ hg -R cloned-bookmark-default bookmarks
494 X2 1:925d80f479bb
494 X2 1:925d80f479bb
495 Y 2:db815d6d32e6
495 Y 2:db815d6d32e6
496 Z 2:db815d6d32e6
496 Z 2:db815d6d32e6
497 default 1:925d80f479bb
497 default 1:925d80f479bb
498 x y 2:db815d6d32e6
498 x y 2:db815d6d32e6
499 $ hg -R cloned-bookmark-default parents -q
499 $ hg -R cloned-bookmark-default parents -q
500 2:db815d6d32e6
500 2:db815d6d32e6
501 $ hg bookmark -d default
501 $ hg bookmark -d default
502
502
503 test clone with a specific revision
503 test clone with a specific revision
504
504
505 $ hg clone -r 925d80 . cloned-bookmarks-rev
505 $ hg clone -r 925d80 . cloned-bookmarks-rev
506 adding changesets
506 adding changesets
507 adding manifests
507 adding manifests
508 adding file changes
508 adding file changes
509 added 2 changesets with 2 changes to 2 files
509 added 2 changesets with 2 changes to 2 files
510 updating to branch default
510 updating to branch default
511 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
511 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
512 $ hg -R cloned-bookmarks-rev bookmarks
512 $ hg -R cloned-bookmarks-rev bookmarks
513 X2 1:925d80f479bb
513 X2 1:925d80f479bb
514
514
515 test clone with update to a bookmark
515 test clone with update to a bookmark
516
516
517 $ hg clone -u Z . ../cloned-bookmarks-update
517 $ hg clone -u Z . ../cloned-bookmarks-update
518 updating to branch default
518 updating to branch default
519 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
519 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
520 $ hg -R ../cloned-bookmarks-update bookmarks
520 $ hg -R ../cloned-bookmarks-update bookmarks
521 X2 1:925d80f479bb
521 X2 1:925d80f479bb
522 Y 2:db815d6d32e6
522 Y 2:db815d6d32e6
523 * Z 2:db815d6d32e6
523 * Z 2:db815d6d32e6
524 x y 2:db815d6d32e6
524 x y 2:db815d6d32e6
525
525
526 create bundle with two heads
526 create bundle with two heads
527
527
528 $ hg clone . tobundle
528 $ hg clone . tobundle
529 updating to branch default
529 updating to branch default
530 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
530 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
531 $ echo x > tobundle/x
531 $ echo x > tobundle/x
532 $ hg -R tobundle add tobundle/x
532 $ hg -R tobundle add tobundle/x
533 $ hg -R tobundle commit -m'x'
533 $ hg -R tobundle commit -m'x'
534 $ hg -R tobundle update -r -2
534 $ hg -R tobundle update -r -2
535 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
535 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
536 $ echo y > tobundle/y
536 $ echo y > tobundle/y
537 $ hg -R tobundle branch test
537 $ hg -R tobundle branch test
538 marked working directory as branch test
538 marked working directory as branch test
539 (branches are permanent and global, did you want a bookmark?)
539 (branches are permanent and global, did you want a bookmark?)
540 $ hg -R tobundle add tobundle/y
540 $ hg -R tobundle add tobundle/y
541 $ hg -R tobundle commit -m'y'
541 $ hg -R tobundle commit -m'y'
542 $ hg -R tobundle bundle tobundle.hg
542 $ hg -R tobundle bundle tobundle.hg
543 searching for changes
543 searching for changes
544 2 changesets found
544 2 changesets found
545 $ hg unbundle tobundle.hg
545 $ hg unbundle tobundle.hg
546 adding changesets
546 adding changesets
547 adding manifests
547 adding manifests
548 adding file changes
548 adding file changes
549 added 2 changesets with 2 changes to 2 files (+1 heads)
549 added 2 changesets with 2 changes to 2 files (+1 heads)
550 (run 'hg heads' to see heads, 'hg merge' to merge)
550 (run 'hg heads' to see heads, 'hg merge' to merge)
551
551
552 update to active bookmark if it's not the parent
552 update to active bookmark if it's not the parent
553
553
554 $ hg summary
554 $ hg summary
555 parent: 2:db815d6d32e6
555 parent: 2:db815d6d32e6
556 2
556 2
557 branch: default
557 branch: default
558 bookmarks: *Z Y x y
558 bookmarks: *Z Y x y
559 commit: 1 added, 1 unknown (new branch head)
559 commit: 1 added, 1 unknown (new branch head)
560 update: 2 new changesets (update)
560 update: 2 new changesets (update)
561 phases: 5 draft
561 phases: 5 draft
562 $ hg update
562 $ hg update
563 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
563 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
564 updating bookmark Z
564 updating bookmark Z
565 $ hg bookmarks
565 $ hg bookmarks
566 X2 1:925d80f479bb
566 X2 1:925d80f479bb
567 Y 2:db815d6d32e6
567 Y 2:db815d6d32e6
568 * Z 3:125c9a1d6df6
568 * Z 3:125c9a1d6df6
569 x y 2:db815d6d32e6
569 x y 2:db815d6d32e6
570
570
571 pull --update works the same as pull && update
571 pull --update works the same as pull && update
572
572
573 $ hg bookmark -r3 Y
573 $ hg bookmark -r3 Y
574 moving bookmark 'Y' forward from db815d6d32e6
574 moving bookmark 'Y' forward from db815d6d32e6
575 $ cp -r ../cloned-bookmarks-update ../cloned-bookmarks-manual-update
575 $ cp -r ../cloned-bookmarks-update ../cloned-bookmarks-manual-update
576
576
577 (manual version)
577 (manual version)
578
578
579 $ hg -R ../cloned-bookmarks-manual-update update Y
579 $ hg -R ../cloned-bookmarks-manual-update update Y
580 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
580 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
581 (activating bookmark Y)
581 (activating bookmark Y)
582 $ hg -R ../cloned-bookmarks-manual-update pull .
582 $ hg -R ../cloned-bookmarks-manual-update pull .
583 pulling from .
583 pulling from .
584 searching for changes
584 searching for changes
585 adding changesets
585 adding changesets
586 adding manifests
586 adding manifests
587 adding file changes
587 adding file changes
588 added 2 changesets with 2 changes to 2 files (+1 heads)
588 added 2 changesets with 2 changes to 2 files (+1 heads)
589 updating bookmark Y
589 updating bookmark Y
590 updating bookmark Z
590 updating bookmark Z
591 (run 'hg heads' to see heads, 'hg merge' to merge)
591 (run 'hg heads' to see heads, 'hg merge' to merge)
592
592
593 (# tests strange but with --date crashing when bookmark have to move)
593 (# tests strange but with --date crashing when bookmark have to move)
594
594
595 $ hg -R ../cloned-bookmarks-manual-update update -d 1986
595 $ hg -R ../cloned-bookmarks-manual-update update -d 1986
596 abort: revision matching date not found
596 abort: revision matching date not found
597 [255]
597 [255]
598 $ hg -R ../cloned-bookmarks-manual-update update
598 $ hg -R ../cloned-bookmarks-manual-update update
599 updating to active bookmark Y
599 updating to active bookmark Y
600 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
600 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
601 (activating bookmark Y)
601 (activating bookmark Y)
602
602
603 (all in one version)
603 (all in one version)
604
604
605 $ hg -R ../cloned-bookmarks-update update Y
605 $ hg -R ../cloned-bookmarks-update update Y
606 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
606 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
607 (activating bookmark Y)
607 (activating bookmark Y)
608 $ hg -R ../cloned-bookmarks-update pull --update .
608 $ hg -R ../cloned-bookmarks-update pull --update .
609 pulling from .
609 pulling from .
610 searching for changes
610 searching for changes
611 adding changesets
611 adding changesets
612 adding manifests
612 adding manifests
613 adding file changes
613 adding file changes
614 added 2 changesets with 2 changes to 2 files (+1 heads)
614 added 2 changesets with 2 changes to 2 files (+1 heads)
615 updating bookmark Y
615 updating bookmark Y
616 updating bookmark Z
616 updating bookmark Z
617 updating to active bookmark Y
617 updating to active bookmark Y
618 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
618 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
619
619
620 test wrongly formated bookmark
620 test wrongly formated bookmark
621
621
622 $ echo '' >> .hg/bookmarks
622 $ echo '' >> .hg/bookmarks
623 $ hg bookmarks
623 $ hg bookmarks
624 X2 1:925d80f479bb
624 X2 1:925d80f479bb
625 Y 3:125c9a1d6df6
625 Y 3:125c9a1d6df6
626 * Z 3:125c9a1d6df6
626 * Z 3:125c9a1d6df6
627 x y 2:db815d6d32e6
627 x y 2:db815d6d32e6
628 $ echo "Ican'thasformatedlines" >> .hg/bookmarks
628 $ echo "Ican'thasformatedlines" >> .hg/bookmarks
629 $ hg bookmarks
629 $ hg bookmarks
630 malformed line in .hg/bookmarks: "Ican'thasformatedlines"
630 malformed line in .hg/bookmarks: "Ican'thasformatedlines"
631 X2 1:925d80f479bb
631 X2 1:925d80f479bb
632 Y 3:125c9a1d6df6
632 Y 3:125c9a1d6df6
633 * Z 3:125c9a1d6df6
633 * Z 3:125c9a1d6df6
634 x y 2:db815d6d32e6
634 x y 2:db815d6d32e6
635
635
636 test missing revisions
636 test missing revisions
637
637
638 $ echo "925d80f479bc z" > .hg/bookmarks
638 $ echo "925d80f479bc z" > .hg/bookmarks
639 $ hg book
639 $ hg book
640 no bookmarks set
640 no bookmarks set
641
641
642 test stripping a non-checked-out but bookmarked revision
642 test stripping a non-checked-out but bookmarked revision
643
643
644 $ hg log --graph
644 $ hg log --graph
645 o changeset: 4:9ba5f110a0b3
645 o changeset: 4:9ba5f110a0b3
646 | branch: test
646 | branch: test
647 | tag: tip
647 | tag: tip
648 | parent: 2:db815d6d32e6
648 | parent: 2:db815d6d32e6
649 | user: test
649 | user: test
650 | date: Thu Jan 01 00:00:00 1970 +0000
650 | date: Thu Jan 01 00:00:00 1970 +0000
651 | summary: y
651 | summary: y
652 |
652 |
653 | @ changeset: 3:125c9a1d6df6
653 | @ changeset: 3:125c9a1d6df6
654 |/ user: test
654 |/ user: test
655 | date: Thu Jan 01 00:00:00 1970 +0000
655 | date: Thu Jan 01 00:00:00 1970 +0000
656 | summary: x
656 | summary: x
657 |
657 |
658 o changeset: 2:db815d6d32e6
658 o changeset: 2:db815d6d32e6
659 | parent: 0:f7b1eb17ad24
659 | parent: 0:f7b1eb17ad24
660 | user: test
660 | user: test
661 | date: Thu Jan 01 00:00:00 1970 +0000
661 | date: Thu Jan 01 00:00:00 1970 +0000
662 | summary: 2
662 | summary: 2
663 |
663 |
664 | o changeset: 1:925d80f479bb
664 | o changeset: 1:925d80f479bb
665 |/ user: test
665 |/ user: test
666 | date: Thu Jan 01 00:00:00 1970 +0000
666 | date: Thu Jan 01 00:00:00 1970 +0000
667 | summary: 1
667 | summary: 1
668 |
668 |
669 o changeset: 0:f7b1eb17ad24
669 o changeset: 0:f7b1eb17ad24
670 user: test
670 user: test
671 date: Thu Jan 01 00:00:00 1970 +0000
671 date: Thu Jan 01 00:00:00 1970 +0000
672 summary: 0
672 summary: 0
673
673
674 $ hg book should-end-on-two
674 $ hg book should-end-on-two
675 $ hg co --clean 4
675 $ hg co --clean 4
676 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
676 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
677 (leaving bookmark should-end-on-two)
677 (leaving bookmark should-end-on-two)
678 $ hg book four
678 $ hg book four
679 $ hg --config extensions.mq= strip 3
679 $ hg --config extensions.mq= strip 3
680 saved backup bundle to * (glob)
680 saved backup bundle to * (glob)
681 should-end-on-two should end up pointing to revision 2, as that's the
681 should-end-on-two should end up pointing to revision 2, as that's the
682 tipmost surviving ancestor of the stripped revision.
682 tipmost surviving ancestor of the stripped revision.
683 $ hg log --graph
683 $ hg log --graph
684 @ changeset: 3:9ba5f110a0b3
684 @ changeset: 3:9ba5f110a0b3
685 | branch: test
685 | branch: test
686 | bookmark: four
686 | bookmark: four
687 | tag: tip
687 | tag: tip
688 | user: test
688 | user: test
689 | date: Thu Jan 01 00:00:00 1970 +0000
689 | date: Thu Jan 01 00:00:00 1970 +0000
690 | summary: y
690 | summary: y
691 |
691 |
692 o changeset: 2:db815d6d32e6
692 o changeset: 2:db815d6d32e6
693 | bookmark: should-end-on-two
693 | bookmark: should-end-on-two
694 | parent: 0:f7b1eb17ad24
694 | parent: 0:f7b1eb17ad24
695 | user: test
695 | user: test
696 | date: Thu Jan 01 00:00:00 1970 +0000
696 | date: Thu Jan 01 00:00:00 1970 +0000
697 | summary: 2
697 | summary: 2
698 |
698 |
699 | o changeset: 1:925d80f479bb
699 | o changeset: 1:925d80f479bb
700 |/ user: test
700 |/ user: test
701 | date: Thu Jan 01 00:00:00 1970 +0000
701 | date: Thu Jan 01 00:00:00 1970 +0000
702 | summary: 1
702 | summary: 1
703 |
703 |
704 o changeset: 0:f7b1eb17ad24
704 o changeset: 0:f7b1eb17ad24
705 user: test
705 user: test
706 date: Thu Jan 01 00:00:00 1970 +0000
706 date: Thu Jan 01 00:00:00 1970 +0000
707 summary: 0
707 summary: 0
708
708
709 test non-linear update not clearing active bookmark
709 test non-linear update not clearing active bookmark
710
710
711 $ hg up 1
711 $ hg up 1
712 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
712 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
713 (leaving bookmark four)
713 (leaving bookmark four)
714 $ hg book drop
714 $ hg book drop
715 $ hg up -C
715 $ hg up -C
716 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
716 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
717 (leaving bookmark drop)
717 (leaving bookmark drop)
718 $ hg sum
718 $ hg sum
719 parent: 2:db815d6d32e6
719 parent: 2:db815d6d32e6
720 2
720 2
721 branch: default
721 branch: default
722 bookmarks: should-end-on-two
722 bookmarks: should-end-on-two
723 commit: 2 unknown (clean)
723 commit: 2 unknown (clean)
724 update: 1 new changesets, 2 branch heads (merge)
724 update: 1 new changesets, 2 branch heads (merge)
725 phases: 4 draft
725 phases: 4 draft
726 $ hg book
726 $ hg book
727 drop 1:925d80f479bb
727 drop 1:925d80f479bb
728 four 3:9ba5f110a0b3
728 four 3:9ba5f110a0b3
729 should-end-on-two 2:db815d6d32e6
729 should-end-on-two 2:db815d6d32e6
730 $ hg book -d drop
730 $ hg book -d drop
731 $ hg up four
731 $ hg up four
732 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
732 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
733 (activating bookmark four)
733 (activating bookmark four)
734
734
735 no-op update doesn't deactive bookmarks
735 no-op update doesn't deactive bookmarks
736
736
737 $ hg up
737 $ hg up
738 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
738 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
739 $ hg sum
739 $ hg sum
740 parent: 3:9ba5f110a0b3 tip
740 parent: 3:9ba5f110a0b3 tip
741 y
741 y
742 branch: test
742 branch: test
743 bookmarks: *four
743 bookmarks: *four
744 commit: 2 unknown (clean)
744 commit: 2 unknown (clean)
745 update: (current)
745 update: (current)
746 phases: 4 draft
746 phases: 4 draft
747
747
748 test clearing divergent bookmarks of linear ancestors
748 test clearing divergent bookmarks of linear ancestors
749
749
750 $ hg bookmark Z -r 0
750 $ hg bookmark Z -r 0
751 $ hg bookmark Z@1 -r 1
751 $ hg bookmark Z@1 -r 1
752 $ hg bookmark Z@2 -r 2
752 $ hg bookmark Z@2 -r 2
753 $ hg bookmark Z@3 -r 3
753 $ hg bookmark Z@3 -r 3
754 $ hg book
754 $ hg book
755 Z 0:f7b1eb17ad24
755 Z 0:f7b1eb17ad24
756 Z@1 1:925d80f479bb
756 Z@1 1:925d80f479bb
757 Z@2 2:db815d6d32e6
757 Z@2 2:db815d6d32e6
758 Z@3 3:9ba5f110a0b3
758 Z@3 3:9ba5f110a0b3
759 * four 3:9ba5f110a0b3
759 * four 3:9ba5f110a0b3
760 should-end-on-two 2:db815d6d32e6
760 should-end-on-two 2:db815d6d32e6
761 $ hg bookmark Z
761 $ hg bookmark Z
762 moving bookmark 'Z' forward from f7b1eb17ad24
762 moving bookmark 'Z' forward from f7b1eb17ad24
763 $ hg book
763 $ hg book
764 * Z 3:9ba5f110a0b3
764 * Z 3:9ba5f110a0b3
765 Z@1 1:925d80f479bb
765 Z@1 1:925d80f479bb
766 four 3:9ba5f110a0b3
766 four 3:9ba5f110a0b3
767 should-end-on-two 2:db815d6d32e6
767 should-end-on-two 2:db815d6d32e6
768
768
769 test clearing only a single divergent bookmark across branches
769 test clearing only a single divergent bookmark across branches
770
770
771 $ hg book foo -r 1
771 $ hg book foo -r 1
772 $ hg book foo@1 -r 0
772 $ hg book foo@1 -r 0
773 $ hg book foo@2 -r 2
773 $ hg book foo@2 -r 2
774 $ hg book foo@3 -r 3
774 $ hg book foo@3 -r 3
775 $ hg book foo -r foo@3
775 $ hg book foo -r foo@3
776 $ hg book
776 $ hg book
777 * Z 3:9ba5f110a0b3
777 * Z 3:9ba5f110a0b3
778 Z@1 1:925d80f479bb
778 Z@1 1:925d80f479bb
779 foo 3:9ba5f110a0b3
779 foo 3:9ba5f110a0b3
780 foo@1 0:f7b1eb17ad24
780 foo@1 0:f7b1eb17ad24
781 foo@2 2:db815d6d32e6
781 foo@2 2:db815d6d32e6
782 four 3:9ba5f110a0b3
782 four 3:9ba5f110a0b3
783 should-end-on-two 2:db815d6d32e6
783 should-end-on-two 2:db815d6d32e6
784
785 pull --update works the same as pull && update (case #2)
786
787 It is assumed that "hg pull" itself doesn't update current active
788 bookmark ('Y' in tests below).
789
790 $ hg pull -q ../cloned-bookmarks-update
791 divergent bookmark Z stored as Z@2
792
793 (pulling revision on another named branch with --update updates
794 neither the working directory nor current active bookmark: "no-op"
795 case)
796
797 $ echo yy >> y
798 $ hg commit -m yy
799
800 $ hg -R ../cloned-bookmarks-update bookmarks | grep ' Y '
801 * Y 3:125c9a1d6df6
802 $ hg -R ../cloned-bookmarks-update pull . --update
803 pulling from .
804 searching for changes
805 adding changesets
806 adding manifests
807 adding file changes
808 added 1 changesets with 1 changes to 1 files
809 divergent bookmark Z stored as Z@default
810 adding remote bookmark foo
811 adding remote bookmark four
812 adding remote bookmark should-end-on-two
813 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
814 $ hg -R ../cloned-bookmarks-update parents -T "{rev}:{node|short}\n"
815 3:125c9a1d6df6
816 $ hg -R ../cloned-bookmarks-update bookmarks | grep ' Y '
817 * Y 3:125c9a1d6df6
818
819 (pulling revision on current named/topological branch with --update
820 updates the working directory and current active bookmark)
821
822 $ hg update -C -q 125c9a1d6df6
823 $ echo xx >> x
824 $ hg commit -m xx
825
826 $ hg -R ../cloned-bookmarks-update bookmarks | grep ' Y '
827 * Y 3:125c9a1d6df6
828 $ hg -R ../cloned-bookmarks-update pull . --update
829 pulling from .
830 searching for changes
831 adding changesets
832 adding manifests
833 adding file changes
834 added 1 changesets with 1 changes to 1 files
835 divergent bookmark Z stored as Z@default
836 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
837 updating bookmark Y
838 $ hg -R ../cloned-bookmarks-update parents -T "{rev}:{node|short}\n"
839 6:81dcce76aa0b
840 $ hg -R ../cloned-bookmarks-update bookmarks | grep ' Y '
841 * Y 6:81dcce76aa0b
General Comments 0
You need to be logged in to leave comments. Login now