##// END OF EJS Templates
merge: save merge part labels for later reuse...
Simon Farnsworth -
r28634:3ceac01b default
parent child Browse files
Show More
@@ -1,7197 +1,7205 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import difflib
10 import difflib
11 import errno
11 import errno
12 import operator
12 import operator
13 import os
13 import os
14 import random
14 import random
15 import re
15 import re
16 import shlex
16 import shlex
17 import socket
17 import socket
18 import sys
18 import sys
19 import tempfile
19 import tempfile
20 import time
20 import time
21
21
22 from .i18n import _
22 from .i18n import _
23 from .node import (
23 from .node import (
24 bin,
24 bin,
25 hex,
25 hex,
26 nullhex,
26 nullhex,
27 nullid,
27 nullid,
28 nullrev,
28 nullrev,
29 short,
29 short,
30 )
30 )
31 from . import (
31 from . import (
32 archival,
32 archival,
33 bookmarks,
33 bookmarks,
34 bundle2,
34 bundle2,
35 changegroup,
35 changegroup,
36 cmdutil,
36 cmdutil,
37 commandserver,
37 commandserver,
38 context,
38 context,
39 copies,
39 copies,
40 dagparser,
40 dagparser,
41 dagutil,
41 dagutil,
42 destutil,
42 destutil,
43 discovery,
43 discovery,
44 encoding,
44 encoding,
45 error,
45 error,
46 exchange,
46 exchange,
47 extensions,
47 extensions,
48 fileset,
48 fileset,
49 graphmod,
49 graphmod,
50 hbisect,
50 hbisect,
51 help,
51 help,
52 hg,
52 hg,
53 hgweb,
53 hgweb,
54 localrepo,
54 localrepo,
55 lock as lockmod,
55 lock as lockmod,
56 merge as mergemod,
56 merge as mergemod,
57 minirst,
57 minirst,
58 obsolete,
58 obsolete,
59 patch,
59 patch,
60 phases,
60 phases,
61 pvec,
61 pvec,
62 repair,
62 repair,
63 revlog,
63 revlog,
64 revset,
64 revset,
65 scmutil,
65 scmutil,
66 setdiscovery,
66 setdiscovery,
67 simplemerge,
67 simplemerge,
68 sshserver,
68 sshserver,
69 streamclone,
69 streamclone,
70 templatekw,
70 templatekw,
71 templater,
71 templater,
72 treediscovery,
72 treediscovery,
73 ui as uimod,
73 ui as uimod,
74 util,
74 util,
75 )
75 )
76
76
77 release = lockmod.release
77 release = lockmod.release
78
78
79 table = {}
79 table = {}
80
80
81 command = cmdutil.command(table)
81 command = cmdutil.command(table)
82
82
83 # label constants
83 # label constants
84 # until 3.5, bookmarks.current was the advertised name, not
84 # until 3.5, bookmarks.current was the advertised name, not
85 # bookmarks.active, so we must use both to avoid breaking old
85 # bookmarks.active, so we must use both to avoid breaking old
86 # custom styles
86 # custom styles
87 activebookmarklabel = 'bookmarks.active bookmarks.current'
87 activebookmarklabel = 'bookmarks.active bookmarks.current'
88
88
89 # common command options
89 # common command options
90
90
91 globalopts = [
91 globalopts = [
92 ('R', 'repository', '',
92 ('R', 'repository', '',
93 _('repository root directory or name of overlay bundle file'),
93 _('repository root directory or name of overlay bundle file'),
94 _('REPO')),
94 _('REPO')),
95 ('', 'cwd', '',
95 ('', 'cwd', '',
96 _('change working directory'), _('DIR')),
96 _('change working directory'), _('DIR')),
97 ('y', 'noninteractive', None,
97 ('y', 'noninteractive', None,
98 _('do not prompt, automatically pick the first choice for all prompts')),
98 _('do not prompt, automatically pick the first choice for all prompts')),
99 ('q', 'quiet', None, _('suppress output')),
99 ('q', 'quiet', None, _('suppress output')),
100 ('v', 'verbose', None, _('enable additional output')),
100 ('v', 'verbose', None, _('enable additional output')),
101 ('', 'config', [],
101 ('', 'config', [],
102 _('set/override config option (use \'section.name=value\')'),
102 _('set/override config option (use \'section.name=value\')'),
103 _('CONFIG')),
103 _('CONFIG')),
104 ('', 'debug', None, _('enable debugging output')),
104 ('', 'debug', None, _('enable debugging output')),
105 ('', 'debugger', None, _('start debugger')),
105 ('', 'debugger', None, _('start debugger')),
106 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
106 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
107 _('ENCODE')),
107 _('ENCODE')),
108 ('', 'encodingmode', encoding.encodingmode,
108 ('', 'encodingmode', encoding.encodingmode,
109 _('set the charset encoding mode'), _('MODE')),
109 _('set the charset encoding mode'), _('MODE')),
110 ('', 'traceback', None, _('always print a traceback on exception')),
110 ('', 'traceback', None, _('always print a traceback on exception')),
111 ('', 'time', None, _('time how long the command takes')),
111 ('', 'time', None, _('time how long the command takes')),
112 ('', 'profile', None, _('print command execution profile')),
112 ('', 'profile', None, _('print command execution profile')),
113 ('', 'version', None, _('output version information and exit')),
113 ('', 'version', None, _('output version information and exit')),
114 ('h', 'help', None, _('display help and exit')),
114 ('h', 'help', None, _('display help and exit')),
115 ('', 'hidden', False, _('consider hidden changesets')),
115 ('', 'hidden', False, _('consider hidden changesets')),
116 ]
116 ]
117
117
118 dryrunopts = [('n', 'dry-run', None,
118 dryrunopts = [('n', 'dry-run', None,
119 _('do not perform actions, just print output'))]
119 _('do not perform actions, just print output'))]
120
120
121 remoteopts = [
121 remoteopts = [
122 ('e', 'ssh', '',
122 ('e', 'ssh', '',
123 _('specify ssh command to use'), _('CMD')),
123 _('specify ssh command to use'), _('CMD')),
124 ('', 'remotecmd', '',
124 ('', 'remotecmd', '',
125 _('specify hg command to run on the remote side'), _('CMD')),
125 _('specify hg command to run on the remote side'), _('CMD')),
126 ('', 'insecure', None,
126 ('', 'insecure', None,
127 _('do not verify server certificate (ignoring web.cacerts config)')),
127 _('do not verify server certificate (ignoring web.cacerts config)')),
128 ]
128 ]
129
129
130 walkopts = [
130 walkopts = [
131 ('I', 'include', [],
131 ('I', 'include', [],
132 _('include names matching the given patterns'), _('PATTERN')),
132 _('include names matching the given patterns'), _('PATTERN')),
133 ('X', 'exclude', [],
133 ('X', 'exclude', [],
134 _('exclude names matching the given patterns'), _('PATTERN')),
134 _('exclude names matching the given patterns'), _('PATTERN')),
135 ]
135 ]
136
136
137 commitopts = [
137 commitopts = [
138 ('m', 'message', '',
138 ('m', 'message', '',
139 _('use text as commit message'), _('TEXT')),
139 _('use text as commit message'), _('TEXT')),
140 ('l', 'logfile', '',
140 ('l', 'logfile', '',
141 _('read commit message from file'), _('FILE')),
141 _('read commit message from file'), _('FILE')),
142 ]
142 ]
143
143
144 commitopts2 = [
144 commitopts2 = [
145 ('d', 'date', '',
145 ('d', 'date', '',
146 _('record the specified date as commit date'), _('DATE')),
146 _('record the specified date as commit date'), _('DATE')),
147 ('u', 'user', '',
147 ('u', 'user', '',
148 _('record the specified user as committer'), _('USER')),
148 _('record the specified user as committer'), _('USER')),
149 ]
149 ]
150
150
151 # hidden for now
151 # hidden for now
152 formatteropts = [
152 formatteropts = [
153 ('T', 'template', '',
153 ('T', 'template', '',
154 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
154 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
155 ]
155 ]
156
156
157 templateopts = [
157 templateopts = [
158 ('', 'style', '',
158 ('', 'style', '',
159 _('display using template map file (DEPRECATED)'), _('STYLE')),
159 _('display using template map file (DEPRECATED)'), _('STYLE')),
160 ('T', 'template', '',
160 ('T', 'template', '',
161 _('display with template'), _('TEMPLATE')),
161 _('display with template'), _('TEMPLATE')),
162 ]
162 ]
163
163
164 logopts = [
164 logopts = [
165 ('p', 'patch', None, _('show patch')),
165 ('p', 'patch', None, _('show patch')),
166 ('g', 'git', None, _('use git extended diff format')),
166 ('g', 'git', None, _('use git extended diff format')),
167 ('l', 'limit', '',
167 ('l', 'limit', '',
168 _('limit number of changes displayed'), _('NUM')),
168 _('limit number of changes displayed'), _('NUM')),
169 ('M', 'no-merges', None, _('do not show merges')),
169 ('M', 'no-merges', None, _('do not show merges')),
170 ('', 'stat', None, _('output diffstat-style summary of changes')),
170 ('', 'stat', None, _('output diffstat-style summary of changes')),
171 ('G', 'graph', None, _("show the revision DAG")),
171 ('G', 'graph', None, _("show the revision DAG")),
172 ] + templateopts
172 ] + templateopts
173
173
174 diffopts = [
174 diffopts = [
175 ('a', 'text', None, _('treat all files as text')),
175 ('a', 'text', None, _('treat all files as text')),
176 ('g', 'git', None, _('use git extended diff format')),
176 ('g', 'git', None, _('use git extended diff format')),
177 ('', 'nodates', None, _('omit dates from diff headers'))
177 ('', 'nodates', None, _('omit dates from diff headers'))
178 ]
178 ]
179
179
180 diffwsopts = [
180 diffwsopts = [
181 ('w', 'ignore-all-space', None,
181 ('w', 'ignore-all-space', None,
182 _('ignore white space when comparing lines')),
182 _('ignore white space when comparing lines')),
183 ('b', 'ignore-space-change', None,
183 ('b', 'ignore-space-change', None,
184 _('ignore changes in the amount of white space')),
184 _('ignore changes in the amount of white space')),
185 ('B', 'ignore-blank-lines', None,
185 ('B', 'ignore-blank-lines', None,
186 _('ignore changes whose lines are all blank')),
186 _('ignore changes whose lines are all blank')),
187 ]
187 ]
188
188
189 diffopts2 = [
189 diffopts2 = [
190 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
190 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
191 ('p', 'show-function', None, _('show which function each change is in')),
191 ('p', 'show-function', None, _('show which function each change is in')),
192 ('', 'reverse', None, _('produce a diff that undoes the changes')),
192 ('', 'reverse', None, _('produce a diff that undoes the changes')),
193 ] + diffwsopts + [
193 ] + diffwsopts + [
194 ('U', 'unified', '',
194 ('U', 'unified', '',
195 _('number of lines of context to show'), _('NUM')),
195 _('number of lines of context to show'), _('NUM')),
196 ('', 'stat', None, _('output diffstat-style summary of changes')),
196 ('', 'stat', None, _('output diffstat-style summary of changes')),
197 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
197 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
198 ]
198 ]
199
199
200 mergetoolopts = [
200 mergetoolopts = [
201 ('t', 'tool', '', _('specify merge tool')),
201 ('t', 'tool', '', _('specify merge tool')),
202 ]
202 ]
203
203
204 similarityopts = [
204 similarityopts = [
205 ('s', 'similarity', '',
205 ('s', 'similarity', '',
206 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
206 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
207 ]
207 ]
208
208
209 subrepoopts = [
209 subrepoopts = [
210 ('S', 'subrepos', None,
210 ('S', 'subrepos', None,
211 _('recurse into subrepositories'))
211 _('recurse into subrepositories'))
212 ]
212 ]
213
213
214 debugrevlogopts = [
214 debugrevlogopts = [
215 ('c', 'changelog', False, _('open changelog')),
215 ('c', 'changelog', False, _('open changelog')),
216 ('m', 'manifest', False, _('open manifest')),
216 ('m', 'manifest', False, _('open manifest')),
217 ('', 'dir', False, _('open directory manifest')),
217 ('', 'dir', False, _('open directory manifest')),
218 ]
218 ]
219
219
220 # Commands start here, listed alphabetically
220 # Commands start here, listed alphabetically
221
221
222 @command('^add',
222 @command('^add',
223 walkopts + subrepoopts + dryrunopts,
223 walkopts + subrepoopts + dryrunopts,
224 _('[OPTION]... [FILE]...'),
224 _('[OPTION]... [FILE]...'),
225 inferrepo=True)
225 inferrepo=True)
226 def add(ui, repo, *pats, **opts):
226 def add(ui, repo, *pats, **opts):
227 """add the specified files on the next commit
227 """add the specified files on the next commit
228
228
229 Schedule files to be version controlled and added to the
229 Schedule files to be version controlled and added to the
230 repository.
230 repository.
231
231
232 The files will be added to the repository at the next commit. To
232 The files will be added to the repository at the next commit. To
233 undo an add before that, see :hg:`forget`.
233 undo an add before that, see :hg:`forget`.
234
234
235 If no names are given, add all files to the repository (except
235 If no names are given, add all files to the repository (except
236 files matching ``.hgignore``).
236 files matching ``.hgignore``).
237
237
238 .. container:: verbose
238 .. container:: verbose
239
239
240 Examples:
240 Examples:
241
241
242 - New (unknown) files are added
242 - New (unknown) files are added
243 automatically by :hg:`add`::
243 automatically by :hg:`add`::
244
244
245 $ ls
245 $ ls
246 foo.c
246 foo.c
247 $ hg status
247 $ hg status
248 ? foo.c
248 ? foo.c
249 $ hg add
249 $ hg add
250 adding foo.c
250 adding foo.c
251 $ hg status
251 $ hg status
252 A foo.c
252 A foo.c
253
253
254 - Specific files to be added can be specified::
254 - Specific files to be added can be specified::
255
255
256 $ ls
256 $ ls
257 bar.c foo.c
257 bar.c foo.c
258 $ hg status
258 $ hg status
259 ? bar.c
259 ? bar.c
260 ? foo.c
260 ? foo.c
261 $ hg add bar.c
261 $ hg add bar.c
262 $ hg status
262 $ hg status
263 A bar.c
263 A bar.c
264 ? foo.c
264 ? foo.c
265
265
266 Returns 0 if all files are successfully added.
266 Returns 0 if all files are successfully added.
267 """
267 """
268
268
269 m = scmutil.match(repo[None], pats, opts)
269 m = scmutil.match(repo[None], pats, opts)
270 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
270 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
271 return rejected and 1 or 0
271 return rejected and 1 or 0
272
272
273 @command('addremove',
273 @command('addremove',
274 similarityopts + subrepoopts + walkopts + dryrunopts,
274 similarityopts + subrepoopts + walkopts + dryrunopts,
275 _('[OPTION]... [FILE]...'),
275 _('[OPTION]... [FILE]...'),
276 inferrepo=True)
276 inferrepo=True)
277 def addremove(ui, repo, *pats, **opts):
277 def addremove(ui, repo, *pats, **opts):
278 """add all new files, delete all missing files
278 """add all new files, delete all missing files
279
279
280 Add all new files and remove all missing files from the
280 Add all new files and remove all missing files from the
281 repository.
281 repository.
282
282
283 Unless names are given, new files are ignored if they match any of
283 Unless names are given, new files are ignored if they match any of
284 the patterns in ``.hgignore``. As with add, these changes take
284 the patterns in ``.hgignore``. As with add, these changes take
285 effect at the next commit.
285 effect at the next commit.
286
286
287 Use the -s/--similarity option to detect renamed files. This
287 Use the -s/--similarity option to detect renamed files. This
288 option takes a percentage between 0 (disabled) and 100 (files must
288 option takes a percentage between 0 (disabled) and 100 (files must
289 be identical) as its parameter. With a parameter greater than 0,
289 be identical) as its parameter. With a parameter greater than 0,
290 this compares every removed file with every added file and records
290 this compares every removed file with every added file and records
291 those similar enough as renames. Detecting renamed files this way
291 those similar enough as renames. Detecting renamed files this way
292 can be expensive. After using this option, :hg:`status -C` can be
292 can be expensive. After using this option, :hg:`status -C` can be
293 used to check which files were identified as moved or renamed. If
293 used to check which files were identified as moved or renamed. If
294 not specified, -s/--similarity defaults to 100 and only renames of
294 not specified, -s/--similarity defaults to 100 and only renames of
295 identical files are detected.
295 identical files are detected.
296
296
297 .. container:: verbose
297 .. container:: verbose
298
298
299 Examples:
299 Examples:
300
300
301 - A number of files (bar.c and foo.c) are new,
301 - A number of files (bar.c and foo.c) are new,
302 while foobar.c has been removed (without using :hg:`remove`)
302 while foobar.c has been removed (without using :hg:`remove`)
303 from the repository::
303 from the repository::
304
304
305 $ ls
305 $ ls
306 bar.c foo.c
306 bar.c foo.c
307 $ hg status
307 $ hg status
308 ! foobar.c
308 ! foobar.c
309 ? bar.c
309 ? bar.c
310 ? foo.c
310 ? foo.c
311 $ hg addremove
311 $ hg addremove
312 adding bar.c
312 adding bar.c
313 adding foo.c
313 adding foo.c
314 removing foobar.c
314 removing foobar.c
315 $ hg status
315 $ hg status
316 A bar.c
316 A bar.c
317 A foo.c
317 A foo.c
318 R foobar.c
318 R foobar.c
319
319
320 - A file foobar.c was moved to foo.c without using :hg:`rename`.
320 - A file foobar.c was moved to foo.c without using :hg:`rename`.
321 Afterwards, it was edited slightly::
321 Afterwards, it was edited slightly::
322
322
323 $ ls
323 $ ls
324 foo.c
324 foo.c
325 $ hg status
325 $ hg status
326 ! foobar.c
326 ! foobar.c
327 ? foo.c
327 ? foo.c
328 $ hg addremove --similarity 90
328 $ hg addremove --similarity 90
329 removing foobar.c
329 removing foobar.c
330 adding foo.c
330 adding foo.c
331 recording removal of foobar.c as rename to foo.c (94% similar)
331 recording removal of foobar.c as rename to foo.c (94% similar)
332 $ hg status -C
332 $ hg status -C
333 A foo.c
333 A foo.c
334 foobar.c
334 foobar.c
335 R foobar.c
335 R foobar.c
336
336
337 Returns 0 if all files are successfully added.
337 Returns 0 if all files are successfully added.
338 """
338 """
339 try:
339 try:
340 sim = float(opts.get('similarity') or 100)
340 sim = float(opts.get('similarity') or 100)
341 except ValueError:
341 except ValueError:
342 raise error.Abort(_('similarity must be a number'))
342 raise error.Abort(_('similarity must be a number'))
343 if sim < 0 or sim > 100:
343 if sim < 0 or sim > 100:
344 raise error.Abort(_('similarity must be between 0 and 100'))
344 raise error.Abort(_('similarity must be between 0 and 100'))
345 matcher = scmutil.match(repo[None], pats, opts)
345 matcher = scmutil.match(repo[None], pats, opts)
346 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
346 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
347
347
348 @command('^annotate|blame',
348 @command('^annotate|blame',
349 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
349 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
350 ('', 'follow', None,
350 ('', 'follow', None,
351 _('follow copies/renames and list the filename (DEPRECATED)')),
351 _('follow copies/renames and list the filename (DEPRECATED)')),
352 ('', 'no-follow', None, _("don't follow copies and renames")),
352 ('', 'no-follow', None, _("don't follow copies and renames")),
353 ('a', 'text', None, _('treat all files as text')),
353 ('a', 'text', None, _('treat all files as text')),
354 ('u', 'user', None, _('list the author (long with -v)')),
354 ('u', 'user', None, _('list the author (long with -v)')),
355 ('f', 'file', None, _('list the filename')),
355 ('f', 'file', None, _('list the filename')),
356 ('d', 'date', None, _('list the date (short with -q)')),
356 ('d', 'date', None, _('list the date (short with -q)')),
357 ('n', 'number', None, _('list the revision number (default)')),
357 ('n', 'number', None, _('list the revision number (default)')),
358 ('c', 'changeset', None, _('list the changeset')),
358 ('c', 'changeset', None, _('list the changeset')),
359 ('l', 'line-number', None, _('show line number at the first appearance'))
359 ('l', 'line-number', None, _('show line number at the first appearance'))
360 ] + diffwsopts + walkopts + formatteropts,
360 ] + diffwsopts + walkopts + formatteropts,
361 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
361 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
362 inferrepo=True)
362 inferrepo=True)
363 def annotate(ui, repo, *pats, **opts):
363 def annotate(ui, repo, *pats, **opts):
364 """show changeset information by line for each file
364 """show changeset information by line for each file
365
365
366 List changes in files, showing the revision id responsible for
366 List changes in files, showing the revision id responsible for
367 each line.
367 each line.
368
368
369 This command is useful for discovering when a change was made and
369 This command is useful for discovering when a change was made and
370 by whom.
370 by whom.
371
371
372 If you include --file, --user, or --date, the revision number is
372 If you include --file, --user, or --date, the revision number is
373 suppressed unless you also include --number.
373 suppressed unless you also include --number.
374
374
375 Without the -a/--text option, annotate will avoid processing files
375 Without the -a/--text option, annotate will avoid processing files
376 it detects as binary. With -a, annotate will annotate the file
376 it detects as binary. With -a, annotate will annotate the file
377 anyway, although the results will probably be neither useful
377 anyway, although the results will probably be neither useful
378 nor desirable.
378 nor desirable.
379
379
380 Returns 0 on success.
380 Returns 0 on success.
381 """
381 """
382 if not pats:
382 if not pats:
383 raise error.Abort(_('at least one filename or pattern is required'))
383 raise error.Abort(_('at least one filename or pattern is required'))
384
384
385 if opts.get('follow'):
385 if opts.get('follow'):
386 # --follow is deprecated and now just an alias for -f/--file
386 # --follow is deprecated and now just an alias for -f/--file
387 # to mimic the behavior of Mercurial before version 1.5
387 # to mimic the behavior of Mercurial before version 1.5
388 opts['file'] = True
388 opts['file'] = True
389
389
390 ctx = scmutil.revsingle(repo, opts.get('rev'))
390 ctx = scmutil.revsingle(repo, opts.get('rev'))
391
391
392 fm = ui.formatter('annotate', opts)
392 fm = ui.formatter('annotate', opts)
393 if ui.quiet:
393 if ui.quiet:
394 datefunc = util.shortdate
394 datefunc = util.shortdate
395 else:
395 else:
396 datefunc = util.datestr
396 datefunc = util.datestr
397 if ctx.rev() is None:
397 if ctx.rev() is None:
398 def hexfn(node):
398 def hexfn(node):
399 if node is None:
399 if node is None:
400 return None
400 return None
401 else:
401 else:
402 return fm.hexfunc(node)
402 return fm.hexfunc(node)
403 if opts.get('changeset'):
403 if opts.get('changeset'):
404 # omit "+" suffix which is appended to node hex
404 # omit "+" suffix which is appended to node hex
405 def formatrev(rev):
405 def formatrev(rev):
406 if rev is None:
406 if rev is None:
407 return '%d' % ctx.p1().rev()
407 return '%d' % ctx.p1().rev()
408 else:
408 else:
409 return '%d' % rev
409 return '%d' % rev
410 else:
410 else:
411 def formatrev(rev):
411 def formatrev(rev):
412 if rev is None:
412 if rev is None:
413 return '%d+' % ctx.p1().rev()
413 return '%d+' % ctx.p1().rev()
414 else:
414 else:
415 return '%d ' % rev
415 return '%d ' % rev
416 def formathex(hex):
416 def formathex(hex):
417 if hex is None:
417 if hex is None:
418 return '%s+' % fm.hexfunc(ctx.p1().node())
418 return '%s+' % fm.hexfunc(ctx.p1().node())
419 else:
419 else:
420 return '%s ' % hex
420 return '%s ' % hex
421 else:
421 else:
422 hexfn = fm.hexfunc
422 hexfn = fm.hexfunc
423 formatrev = formathex = str
423 formatrev = formathex = str
424
424
425 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
425 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
426 ('number', ' ', lambda x: x[0].rev(), formatrev),
426 ('number', ' ', lambda x: x[0].rev(), formatrev),
427 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
427 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
428 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
428 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
429 ('file', ' ', lambda x: x[0].path(), str),
429 ('file', ' ', lambda x: x[0].path(), str),
430 ('line_number', ':', lambda x: x[1], str),
430 ('line_number', ':', lambda x: x[1], str),
431 ]
431 ]
432 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
432 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
433
433
434 if (not opts.get('user') and not opts.get('changeset')
434 if (not opts.get('user') and not opts.get('changeset')
435 and not opts.get('date') and not opts.get('file')):
435 and not opts.get('date') and not opts.get('file')):
436 opts['number'] = True
436 opts['number'] = True
437
437
438 linenumber = opts.get('line_number') is not None
438 linenumber = opts.get('line_number') is not None
439 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
439 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
440 raise error.Abort(_('at least one of -n/-c is required for -l'))
440 raise error.Abort(_('at least one of -n/-c is required for -l'))
441
441
442 if fm:
442 if fm:
443 def makefunc(get, fmt):
443 def makefunc(get, fmt):
444 return get
444 return get
445 else:
445 else:
446 def makefunc(get, fmt):
446 def makefunc(get, fmt):
447 return lambda x: fmt(get(x))
447 return lambda x: fmt(get(x))
448 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
448 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
449 if opts.get(op)]
449 if opts.get(op)]
450 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
450 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
451 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
451 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
452 if opts.get(op))
452 if opts.get(op))
453
453
454 def bad(x, y):
454 def bad(x, y):
455 raise error.Abort("%s: %s" % (x, y))
455 raise error.Abort("%s: %s" % (x, y))
456
456
457 m = scmutil.match(ctx, pats, opts, badfn=bad)
457 m = scmutil.match(ctx, pats, opts, badfn=bad)
458
458
459 follow = not opts.get('no_follow')
459 follow = not opts.get('no_follow')
460 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
460 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
461 whitespace=True)
461 whitespace=True)
462 for abs in ctx.walk(m):
462 for abs in ctx.walk(m):
463 fctx = ctx[abs]
463 fctx = ctx[abs]
464 if not opts.get('text') and util.binary(fctx.data()):
464 if not opts.get('text') and util.binary(fctx.data()):
465 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
465 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
466 continue
466 continue
467
467
468 lines = fctx.annotate(follow=follow, linenumber=linenumber,
468 lines = fctx.annotate(follow=follow, linenumber=linenumber,
469 diffopts=diffopts)
469 diffopts=diffopts)
470 formats = []
470 formats = []
471 pieces = []
471 pieces = []
472
472
473 for f, sep in funcmap:
473 for f, sep in funcmap:
474 l = [f(n) for n, dummy in lines]
474 l = [f(n) for n, dummy in lines]
475 if l:
475 if l:
476 if fm:
476 if fm:
477 formats.append(['%s' for x in l])
477 formats.append(['%s' for x in l])
478 else:
478 else:
479 sizes = [encoding.colwidth(x) for x in l]
479 sizes = [encoding.colwidth(x) for x in l]
480 ml = max(sizes)
480 ml = max(sizes)
481 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
481 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
482 pieces.append(l)
482 pieces.append(l)
483
483
484 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
484 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
485 fm.startitem()
485 fm.startitem()
486 fm.write(fields, "".join(f), *p)
486 fm.write(fields, "".join(f), *p)
487 fm.write('line', ": %s", l[1])
487 fm.write('line', ": %s", l[1])
488
488
489 if lines and not lines[-1][1].endswith('\n'):
489 if lines and not lines[-1][1].endswith('\n'):
490 fm.plain('\n')
490 fm.plain('\n')
491
491
492 fm.end()
492 fm.end()
493
493
494 @command('archive',
494 @command('archive',
495 [('', 'no-decode', None, _('do not pass files through decoders')),
495 [('', 'no-decode', None, _('do not pass files through decoders')),
496 ('p', 'prefix', '', _('directory prefix for files in archive'),
496 ('p', 'prefix', '', _('directory prefix for files in archive'),
497 _('PREFIX')),
497 _('PREFIX')),
498 ('r', 'rev', '', _('revision to distribute'), _('REV')),
498 ('r', 'rev', '', _('revision to distribute'), _('REV')),
499 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
499 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
500 ] + subrepoopts + walkopts,
500 ] + subrepoopts + walkopts,
501 _('[OPTION]... DEST'))
501 _('[OPTION]... DEST'))
502 def archive(ui, repo, dest, **opts):
502 def archive(ui, repo, dest, **opts):
503 '''create an unversioned archive of a repository revision
503 '''create an unversioned archive of a repository revision
504
504
505 By default, the revision used is the parent of the working
505 By default, the revision used is the parent of the working
506 directory; use -r/--rev to specify a different revision.
506 directory; use -r/--rev to specify a different revision.
507
507
508 The archive type is automatically detected based on file
508 The archive type is automatically detected based on file
509 extension (to override, use -t/--type).
509 extension (to override, use -t/--type).
510
510
511 .. container:: verbose
511 .. container:: verbose
512
512
513 Examples:
513 Examples:
514
514
515 - create a zip file containing the 1.0 release::
515 - create a zip file containing the 1.0 release::
516
516
517 hg archive -r 1.0 project-1.0.zip
517 hg archive -r 1.0 project-1.0.zip
518
518
519 - create a tarball excluding .hg files::
519 - create a tarball excluding .hg files::
520
520
521 hg archive project.tar.gz -X ".hg*"
521 hg archive project.tar.gz -X ".hg*"
522
522
523 Valid types are:
523 Valid types are:
524
524
525 :``files``: a directory full of files (default)
525 :``files``: a directory full of files (default)
526 :``tar``: tar archive, uncompressed
526 :``tar``: tar archive, uncompressed
527 :``tbz2``: tar archive, compressed using bzip2
527 :``tbz2``: tar archive, compressed using bzip2
528 :``tgz``: tar archive, compressed using gzip
528 :``tgz``: tar archive, compressed using gzip
529 :``uzip``: zip archive, uncompressed
529 :``uzip``: zip archive, uncompressed
530 :``zip``: zip archive, compressed using deflate
530 :``zip``: zip archive, compressed using deflate
531
531
532 The exact name of the destination archive or directory is given
532 The exact name of the destination archive or directory is given
533 using a format string; see :hg:`help export` for details.
533 using a format string; see :hg:`help export` for details.
534
534
535 Each member added to an archive file has a directory prefix
535 Each member added to an archive file has a directory prefix
536 prepended. Use -p/--prefix to specify a format string for the
536 prepended. Use -p/--prefix to specify a format string for the
537 prefix. The default is the basename of the archive, with suffixes
537 prefix. The default is the basename of the archive, with suffixes
538 removed.
538 removed.
539
539
540 Returns 0 on success.
540 Returns 0 on success.
541 '''
541 '''
542
542
543 ctx = scmutil.revsingle(repo, opts.get('rev'))
543 ctx = scmutil.revsingle(repo, opts.get('rev'))
544 if not ctx:
544 if not ctx:
545 raise error.Abort(_('no working directory: please specify a revision'))
545 raise error.Abort(_('no working directory: please specify a revision'))
546 node = ctx.node()
546 node = ctx.node()
547 dest = cmdutil.makefilename(repo, dest, node)
547 dest = cmdutil.makefilename(repo, dest, node)
548 if os.path.realpath(dest) == repo.root:
548 if os.path.realpath(dest) == repo.root:
549 raise error.Abort(_('repository root cannot be destination'))
549 raise error.Abort(_('repository root cannot be destination'))
550
550
551 kind = opts.get('type') or archival.guesskind(dest) or 'files'
551 kind = opts.get('type') or archival.guesskind(dest) or 'files'
552 prefix = opts.get('prefix')
552 prefix = opts.get('prefix')
553
553
554 if dest == '-':
554 if dest == '-':
555 if kind == 'files':
555 if kind == 'files':
556 raise error.Abort(_('cannot archive plain files to stdout'))
556 raise error.Abort(_('cannot archive plain files to stdout'))
557 dest = cmdutil.makefileobj(repo, dest)
557 dest = cmdutil.makefileobj(repo, dest)
558 if not prefix:
558 if not prefix:
559 prefix = os.path.basename(repo.root) + '-%h'
559 prefix = os.path.basename(repo.root) + '-%h'
560
560
561 prefix = cmdutil.makefilename(repo, prefix, node)
561 prefix = cmdutil.makefilename(repo, prefix, node)
562 matchfn = scmutil.match(ctx, [], opts)
562 matchfn = scmutil.match(ctx, [], opts)
563 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
563 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
564 matchfn, prefix, subrepos=opts.get('subrepos'))
564 matchfn, prefix, subrepos=opts.get('subrepos'))
565
565
566 @command('backout',
566 @command('backout',
567 [('', 'merge', None, _('merge with old dirstate parent after backout')),
567 [('', 'merge', None, _('merge with old dirstate parent after backout')),
568 ('', 'commit', None,
568 ('', 'commit', None,
569 _('commit if no conflicts were encountered (DEPRECATED)')),
569 _('commit if no conflicts were encountered (DEPRECATED)')),
570 ('', 'no-commit', None, _('do not commit')),
570 ('', 'no-commit', None, _('do not commit')),
571 ('', 'parent', '',
571 ('', 'parent', '',
572 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
572 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
573 ('r', 'rev', '', _('revision to backout'), _('REV')),
573 ('r', 'rev', '', _('revision to backout'), _('REV')),
574 ('e', 'edit', False, _('invoke editor on commit messages')),
574 ('e', 'edit', False, _('invoke editor on commit messages')),
575 ] + mergetoolopts + walkopts + commitopts + commitopts2,
575 ] + mergetoolopts + walkopts + commitopts + commitopts2,
576 _('[OPTION]... [-r] REV'))
576 _('[OPTION]... [-r] REV'))
577 def backout(ui, repo, node=None, rev=None, **opts):
577 def backout(ui, repo, node=None, rev=None, **opts):
578 '''reverse effect of earlier changeset
578 '''reverse effect of earlier changeset
579
579
580 Prepare a new changeset with the effect of REV undone in the
580 Prepare a new changeset with the effect of REV undone in the
581 current working directory. If no conflicts were encountered,
581 current working directory. If no conflicts were encountered,
582 it will be committed immediately.
582 it will be committed immediately.
583
583
584 If REV is the parent of the working directory, then this new changeset
584 If REV is the parent of the working directory, then this new changeset
585 is committed automatically (unless --no-commit is specified).
585 is committed automatically (unless --no-commit is specified).
586
586
587 .. note::
587 .. note::
588
588
589 :hg:`backout` cannot be used to fix either an unwanted or
589 :hg:`backout` cannot be used to fix either an unwanted or
590 incorrect merge.
590 incorrect merge.
591
591
592 .. container:: verbose
592 .. container:: verbose
593
593
594 Examples:
594 Examples:
595
595
596 - Reverse the effect of the parent of the working directory.
596 - Reverse the effect of the parent of the working directory.
597 This backout will be committed immediately::
597 This backout will be committed immediately::
598
598
599 hg backout -r .
599 hg backout -r .
600
600
601 - Reverse the effect of previous bad revision 23::
601 - Reverse the effect of previous bad revision 23::
602
602
603 hg backout -r 23
603 hg backout -r 23
604
604
605 - Reverse the effect of previous bad revision 23 and
605 - Reverse the effect of previous bad revision 23 and
606 leave changes uncommitted::
606 leave changes uncommitted::
607
607
608 hg backout -r 23 --no-commit
608 hg backout -r 23 --no-commit
609 hg commit -m "Backout revision 23"
609 hg commit -m "Backout revision 23"
610
610
611 By default, the pending changeset will have one parent,
611 By default, the pending changeset will have one parent,
612 maintaining a linear history. With --merge, the pending
612 maintaining a linear history. With --merge, the pending
613 changeset will instead have two parents: the old parent of the
613 changeset will instead have two parents: the old parent of the
614 working directory and a new child of REV that simply undoes REV.
614 working directory and a new child of REV that simply undoes REV.
615
615
616 Before version 1.7, the behavior without --merge was equivalent
616 Before version 1.7, the behavior without --merge was equivalent
617 to specifying --merge followed by :hg:`update --clean .` to
617 to specifying --merge followed by :hg:`update --clean .` to
618 cancel the merge and leave the child of REV as a head to be
618 cancel the merge and leave the child of REV as a head to be
619 merged separately.
619 merged separately.
620
620
621 See :hg:`help dates` for a list of formats valid for -d/--date.
621 See :hg:`help dates` for a list of formats valid for -d/--date.
622
622
623 See :hg:`help revert` for a way to restore files to the state
623 See :hg:`help revert` for a way to restore files to the state
624 of another revision.
624 of another revision.
625
625
626 Returns 0 on success, 1 if nothing to backout or there are unresolved
626 Returns 0 on success, 1 if nothing to backout or there are unresolved
627 files.
627 files.
628 '''
628 '''
629 wlock = lock = None
629 wlock = lock = None
630 try:
630 try:
631 wlock = repo.wlock()
631 wlock = repo.wlock()
632 lock = repo.lock()
632 lock = repo.lock()
633 return _dobackout(ui, repo, node, rev, **opts)
633 return _dobackout(ui, repo, node, rev, **opts)
634 finally:
634 finally:
635 release(lock, wlock)
635 release(lock, wlock)
636
636
637 def _dobackout(ui, repo, node=None, rev=None, **opts):
637 def _dobackout(ui, repo, node=None, rev=None, **opts):
638 if opts.get('commit') and opts.get('no_commit'):
638 if opts.get('commit') and opts.get('no_commit'):
639 raise error.Abort(_("cannot use --commit with --no-commit"))
639 raise error.Abort(_("cannot use --commit with --no-commit"))
640 if opts.get('merge') and opts.get('no_commit'):
640 if opts.get('merge') and opts.get('no_commit'):
641 raise error.Abort(_("cannot use --merge with --no-commit"))
641 raise error.Abort(_("cannot use --merge with --no-commit"))
642
642
643 if rev and node:
643 if rev and node:
644 raise error.Abort(_("please specify just one revision"))
644 raise error.Abort(_("please specify just one revision"))
645
645
646 if not rev:
646 if not rev:
647 rev = node
647 rev = node
648
648
649 if not rev:
649 if not rev:
650 raise error.Abort(_("please specify a revision to backout"))
650 raise error.Abort(_("please specify a revision to backout"))
651
651
652 date = opts.get('date')
652 date = opts.get('date')
653 if date:
653 if date:
654 opts['date'] = util.parsedate(date)
654 opts['date'] = util.parsedate(date)
655
655
656 cmdutil.checkunfinished(repo)
656 cmdutil.checkunfinished(repo)
657 cmdutil.bailifchanged(repo)
657 cmdutil.bailifchanged(repo)
658 node = scmutil.revsingle(repo, rev).node()
658 node = scmutil.revsingle(repo, rev).node()
659
659
660 op1, op2 = repo.dirstate.parents()
660 op1, op2 = repo.dirstate.parents()
661 if not repo.changelog.isancestor(node, op1):
661 if not repo.changelog.isancestor(node, op1):
662 raise error.Abort(_('cannot backout change that is not an ancestor'))
662 raise error.Abort(_('cannot backout change that is not an ancestor'))
663
663
664 p1, p2 = repo.changelog.parents(node)
664 p1, p2 = repo.changelog.parents(node)
665 if p1 == nullid:
665 if p1 == nullid:
666 raise error.Abort(_('cannot backout a change with no parents'))
666 raise error.Abort(_('cannot backout a change with no parents'))
667 if p2 != nullid:
667 if p2 != nullid:
668 if not opts.get('parent'):
668 if not opts.get('parent'):
669 raise error.Abort(_('cannot backout a merge changeset'))
669 raise error.Abort(_('cannot backout a merge changeset'))
670 p = repo.lookup(opts['parent'])
670 p = repo.lookup(opts['parent'])
671 if p not in (p1, p2):
671 if p not in (p1, p2):
672 raise error.Abort(_('%s is not a parent of %s') %
672 raise error.Abort(_('%s is not a parent of %s') %
673 (short(p), short(node)))
673 (short(p), short(node)))
674 parent = p
674 parent = p
675 else:
675 else:
676 if opts.get('parent'):
676 if opts.get('parent'):
677 raise error.Abort(_('cannot use --parent on non-merge changeset'))
677 raise error.Abort(_('cannot use --parent on non-merge changeset'))
678 parent = p1
678 parent = p1
679
679
680 # the backout should appear on the same branch
680 # the backout should appear on the same branch
681 branch = repo.dirstate.branch()
681 branch = repo.dirstate.branch()
682 bheads = repo.branchheads(branch)
682 bheads = repo.branchheads(branch)
683 rctx = scmutil.revsingle(repo, hex(parent))
683 rctx = scmutil.revsingle(repo, hex(parent))
684 if not opts.get('merge') and op1 != node:
684 if not opts.get('merge') and op1 != node:
685 dsguard = cmdutil.dirstateguard(repo, 'backout')
685 dsguard = cmdutil.dirstateguard(repo, 'backout')
686 try:
686 try:
687 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
687 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
688 'backout')
688 'backout')
689 stats = mergemod.update(repo, parent, True, True, node, False)
689 stats = mergemod.update(repo, parent, True, True, node, False)
690 repo.setparents(op1, op2)
690 repo.setparents(op1, op2)
691 dsguard.close()
691 dsguard.close()
692 hg._showstats(repo, stats)
692 hg._showstats(repo, stats)
693 if stats[3]:
693 if stats[3]:
694 repo.ui.status(_("use 'hg resolve' to retry unresolved "
694 repo.ui.status(_("use 'hg resolve' to retry unresolved "
695 "file merges\n"))
695 "file merges\n"))
696 return 1
696 return 1
697 finally:
697 finally:
698 ui.setconfig('ui', 'forcemerge', '', '')
698 ui.setconfig('ui', 'forcemerge', '', '')
699 lockmod.release(dsguard)
699 lockmod.release(dsguard)
700 else:
700 else:
701 hg.clean(repo, node, show_stats=False)
701 hg.clean(repo, node, show_stats=False)
702 repo.dirstate.setbranch(branch)
702 repo.dirstate.setbranch(branch)
703 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
703 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
704
704
705 if opts.get('no_commit'):
705 if opts.get('no_commit'):
706 msg = _("changeset %s backed out, "
706 msg = _("changeset %s backed out, "
707 "don't forget to commit.\n")
707 "don't forget to commit.\n")
708 ui.status(msg % short(node))
708 ui.status(msg % short(node))
709 return 0
709 return 0
710
710
711 def commitfunc(ui, repo, message, match, opts):
711 def commitfunc(ui, repo, message, match, opts):
712 editform = 'backout'
712 editform = 'backout'
713 e = cmdutil.getcommiteditor(editform=editform, **opts)
713 e = cmdutil.getcommiteditor(editform=editform, **opts)
714 if not message:
714 if not message:
715 # we don't translate commit messages
715 # we don't translate commit messages
716 message = "Backed out changeset %s" % short(node)
716 message = "Backed out changeset %s" % short(node)
717 e = cmdutil.getcommiteditor(edit=True, editform=editform)
717 e = cmdutil.getcommiteditor(edit=True, editform=editform)
718 return repo.commit(message, opts.get('user'), opts.get('date'),
718 return repo.commit(message, opts.get('user'), opts.get('date'),
719 match, editor=e)
719 match, editor=e)
720 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
720 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
721 if not newnode:
721 if not newnode:
722 ui.status(_("nothing changed\n"))
722 ui.status(_("nothing changed\n"))
723 return 1
723 return 1
724 cmdutil.commitstatus(repo, newnode, branch, bheads)
724 cmdutil.commitstatus(repo, newnode, branch, bheads)
725
725
726 def nice(node):
726 def nice(node):
727 return '%d:%s' % (repo.changelog.rev(node), short(node))
727 return '%d:%s' % (repo.changelog.rev(node), short(node))
728 ui.status(_('changeset %s backs out changeset %s\n') %
728 ui.status(_('changeset %s backs out changeset %s\n') %
729 (nice(repo.changelog.tip()), nice(node)))
729 (nice(repo.changelog.tip()), nice(node)))
730 if opts.get('merge') and op1 != node:
730 if opts.get('merge') and op1 != node:
731 hg.clean(repo, op1, show_stats=False)
731 hg.clean(repo, op1, show_stats=False)
732 ui.status(_('merging with changeset %s\n')
732 ui.status(_('merging with changeset %s\n')
733 % nice(repo.changelog.tip()))
733 % nice(repo.changelog.tip()))
734 try:
734 try:
735 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
735 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
736 'backout')
736 'backout')
737 return hg.merge(repo, hex(repo.changelog.tip()))
737 return hg.merge(repo, hex(repo.changelog.tip()))
738 finally:
738 finally:
739 ui.setconfig('ui', 'forcemerge', '', '')
739 ui.setconfig('ui', 'forcemerge', '', '')
740 return 0
740 return 0
741
741
742 @command('bisect',
742 @command('bisect',
743 [('r', 'reset', False, _('reset bisect state')),
743 [('r', 'reset', False, _('reset bisect state')),
744 ('g', 'good', False, _('mark changeset good')),
744 ('g', 'good', False, _('mark changeset good')),
745 ('b', 'bad', False, _('mark changeset bad')),
745 ('b', 'bad', False, _('mark changeset bad')),
746 ('s', 'skip', False, _('skip testing changeset')),
746 ('s', 'skip', False, _('skip testing changeset')),
747 ('e', 'extend', False, _('extend the bisect range')),
747 ('e', 'extend', False, _('extend the bisect range')),
748 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
748 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
749 ('U', 'noupdate', False, _('do not update to target'))],
749 ('U', 'noupdate', False, _('do not update to target'))],
750 _("[-gbsr] [-U] [-c CMD] [REV]"))
750 _("[-gbsr] [-U] [-c CMD] [REV]"))
751 def bisect(ui, repo, rev=None, extra=None, command=None,
751 def bisect(ui, repo, rev=None, extra=None, command=None,
752 reset=None, good=None, bad=None, skip=None, extend=None,
752 reset=None, good=None, bad=None, skip=None, extend=None,
753 noupdate=None):
753 noupdate=None):
754 """subdivision search of changesets
754 """subdivision search of changesets
755
755
756 This command helps to find changesets which introduce problems. To
756 This command helps to find changesets which introduce problems. To
757 use, mark the earliest changeset you know exhibits the problem as
757 use, mark the earliest changeset you know exhibits the problem as
758 bad, then mark the latest changeset which is free from the problem
758 bad, then mark the latest changeset which is free from the problem
759 as good. Bisect will update your working directory to a revision
759 as good. Bisect will update your working directory to a revision
760 for testing (unless the -U/--noupdate option is specified). Once
760 for testing (unless the -U/--noupdate option is specified). Once
761 you have performed tests, mark the working directory as good or
761 you have performed tests, mark the working directory as good or
762 bad, and bisect will either update to another candidate changeset
762 bad, and bisect will either update to another candidate changeset
763 or announce that it has found the bad revision.
763 or announce that it has found the bad revision.
764
764
765 As a shortcut, you can also use the revision argument to mark a
765 As a shortcut, you can also use the revision argument to mark a
766 revision as good or bad without checking it out first.
766 revision as good or bad without checking it out first.
767
767
768 If you supply a command, it will be used for automatic bisection.
768 If you supply a command, it will be used for automatic bisection.
769 The environment variable HG_NODE will contain the ID of the
769 The environment variable HG_NODE will contain the ID of the
770 changeset being tested. The exit status of the command will be
770 changeset being tested. The exit status of the command will be
771 used to mark revisions as good or bad: status 0 means good, 125
771 used to mark revisions as good or bad: status 0 means good, 125
772 means to skip the revision, 127 (command not found) will abort the
772 means to skip the revision, 127 (command not found) will abort the
773 bisection, and any other non-zero exit status means the revision
773 bisection, and any other non-zero exit status means the revision
774 is bad.
774 is bad.
775
775
776 .. container:: verbose
776 .. container:: verbose
777
777
778 Some examples:
778 Some examples:
779
779
780 - start a bisection with known bad revision 34, and good revision 12::
780 - start a bisection with known bad revision 34, and good revision 12::
781
781
782 hg bisect --bad 34
782 hg bisect --bad 34
783 hg bisect --good 12
783 hg bisect --good 12
784
784
785 - advance the current bisection by marking current revision as good or
785 - advance the current bisection by marking current revision as good or
786 bad::
786 bad::
787
787
788 hg bisect --good
788 hg bisect --good
789 hg bisect --bad
789 hg bisect --bad
790
790
791 - mark the current revision, or a known revision, to be skipped (e.g. if
791 - mark the current revision, or a known revision, to be skipped (e.g. if
792 that revision is not usable because of another issue)::
792 that revision is not usable because of another issue)::
793
793
794 hg bisect --skip
794 hg bisect --skip
795 hg bisect --skip 23
795 hg bisect --skip 23
796
796
797 - skip all revisions that do not touch directories ``foo`` or ``bar``::
797 - skip all revisions that do not touch directories ``foo`` or ``bar``::
798
798
799 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
799 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
800
800
801 - forget the current bisection::
801 - forget the current bisection::
802
802
803 hg bisect --reset
803 hg bisect --reset
804
804
805 - use 'make && make tests' to automatically find the first broken
805 - use 'make && make tests' to automatically find the first broken
806 revision::
806 revision::
807
807
808 hg bisect --reset
808 hg bisect --reset
809 hg bisect --bad 34
809 hg bisect --bad 34
810 hg bisect --good 12
810 hg bisect --good 12
811 hg bisect --command "make && make tests"
811 hg bisect --command "make && make tests"
812
812
813 - see all changesets whose states are already known in the current
813 - see all changesets whose states are already known in the current
814 bisection::
814 bisection::
815
815
816 hg log -r "bisect(pruned)"
816 hg log -r "bisect(pruned)"
817
817
818 - see the changeset currently being bisected (especially useful
818 - see the changeset currently being bisected (especially useful
819 if running with -U/--noupdate)::
819 if running with -U/--noupdate)::
820
820
821 hg log -r "bisect(current)"
821 hg log -r "bisect(current)"
822
822
823 - see all changesets that took part in the current bisection::
823 - see all changesets that took part in the current bisection::
824
824
825 hg log -r "bisect(range)"
825 hg log -r "bisect(range)"
826
826
827 - you can even get a nice graph::
827 - you can even get a nice graph::
828
828
829 hg log --graph -r "bisect(range)"
829 hg log --graph -r "bisect(range)"
830
830
831 See :hg:`help revsets` for more about the `bisect()` keyword.
831 See :hg:`help revsets` for more about the `bisect()` keyword.
832
832
833 Returns 0 on success.
833 Returns 0 on success.
834 """
834 """
835 def extendbisectrange(nodes, good):
835 def extendbisectrange(nodes, good):
836 # bisect is incomplete when it ends on a merge node and
836 # bisect is incomplete when it ends on a merge node and
837 # one of the parent was not checked.
837 # one of the parent was not checked.
838 parents = repo[nodes[0]].parents()
838 parents = repo[nodes[0]].parents()
839 if len(parents) > 1:
839 if len(parents) > 1:
840 if good:
840 if good:
841 side = state['bad']
841 side = state['bad']
842 else:
842 else:
843 side = state['good']
843 side = state['good']
844 num = len(set(i.node() for i in parents) & set(side))
844 num = len(set(i.node() for i in parents) & set(side))
845 if num == 1:
845 if num == 1:
846 return parents[0].ancestor(parents[1])
846 return parents[0].ancestor(parents[1])
847 return None
847 return None
848
848
849 def print_result(nodes, good):
849 def print_result(nodes, good):
850 displayer = cmdutil.show_changeset(ui, repo, {})
850 displayer = cmdutil.show_changeset(ui, repo, {})
851 if len(nodes) == 1:
851 if len(nodes) == 1:
852 # narrowed it down to a single revision
852 # narrowed it down to a single revision
853 if good:
853 if good:
854 ui.write(_("The first good revision is:\n"))
854 ui.write(_("The first good revision is:\n"))
855 else:
855 else:
856 ui.write(_("The first bad revision is:\n"))
856 ui.write(_("The first bad revision is:\n"))
857 displayer.show(repo[nodes[0]])
857 displayer.show(repo[nodes[0]])
858 extendnode = extendbisectrange(nodes, good)
858 extendnode = extendbisectrange(nodes, good)
859 if extendnode is not None:
859 if extendnode is not None:
860 ui.write(_('Not all ancestors of this changeset have been'
860 ui.write(_('Not all ancestors of this changeset have been'
861 ' checked.\nUse bisect --extend to continue the '
861 ' checked.\nUse bisect --extend to continue the '
862 'bisection from\nthe common ancestor, %s.\n')
862 'bisection from\nthe common ancestor, %s.\n')
863 % extendnode)
863 % extendnode)
864 else:
864 else:
865 # multiple possible revisions
865 # multiple possible revisions
866 if good:
866 if good:
867 ui.write(_("Due to skipped revisions, the first "
867 ui.write(_("Due to skipped revisions, the first "
868 "good revision could be any of:\n"))
868 "good revision could be any of:\n"))
869 else:
869 else:
870 ui.write(_("Due to skipped revisions, the first "
870 ui.write(_("Due to skipped revisions, the first "
871 "bad revision could be any of:\n"))
871 "bad revision could be any of:\n"))
872 for n in nodes:
872 for n in nodes:
873 displayer.show(repo[n])
873 displayer.show(repo[n])
874 displayer.close()
874 displayer.close()
875
875
876 def check_state(state, interactive=True):
876 def check_state(state, interactive=True):
877 if not state['good'] or not state['bad']:
877 if not state['good'] or not state['bad']:
878 if (good or bad or skip or reset) and interactive:
878 if (good or bad or skip or reset) and interactive:
879 return
879 return
880 if not state['good']:
880 if not state['good']:
881 raise error.Abort(_('cannot bisect (no known good revisions)'))
881 raise error.Abort(_('cannot bisect (no known good revisions)'))
882 else:
882 else:
883 raise error.Abort(_('cannot bisect (no known bad revisions)'))
883 raise error.Abort(_('cannot bisect (no known bad revisions)'))
884 return True
884 return True
885
885
886 # backward compatibility
886 # backward compatibility
887 if rev in "good bad reset init".split():
887 if rev in "good bad reset init".split():
888 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
888 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
889 cmd, rev, extra = rev, extra, None
889 cmd, rev, extra = rev, extra, None
890 if cmd == "good":
890 if cmd == "good":
891 good = True
891 good = True
892 elif cmd == "bad":
892 elif cmd == "bad":
893 bad = True
893 bad = True
894 else:
894 else:
895 reset = True
895 reset = True
896 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
896 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
897 raise error.Abort(_('incompatible arguments'))
897 raise error.Abort(_('incompatible arguments'))
898
898
899 cmdutil.checkunfinished(repo)
899 cmdutil.checkunfinished(repo)
900
900
901 if reset:
901 if reset:
902 p = repo.join("bisect.state")
902 p = repo.join("bisect.state")
903 if os.path.exists(p):
903 if os.path.exists(p):
904 os.unlink(p)
904 os.unlink(p)
905 return
905 return
906
906
907 state = hbisect.load_state(repo)
907 state = hbisect.load_state(repo)
908
908
909 if command:
909 if command:
910 changesets = 1
910 changesets = 1
911 if noupdate:
911 if noupdate:
912 try:
912 try:
913 node = state['current'][0]
913 node = state['current'][0]
914 except LookupError:
914 except LookupError:
915 raise error.Abort(_('current bisect revision is unknown - '
915 raise error.Abort(_('current bisect revision is unknown - '
916 'start a new bisect to fix'))
916 'start a new bisect to fix'))
917 else:
917 else:
918 node, p2 = repo.dirstate.parents()
918 node, p2 = repo.dirstate.parents()
919 if p2 != nullid:
919 if p2 != nullid:
920 raise error.Abort(_('current bisect revision is a merge'))
920 raise error.Abort(_('current bisect revision is a merge'))
921 try:
921 try:
922 while changesets:
922 while changesets:
923 # update state
923 # update state
924 state['current'] = [node]
924 state['current'] = [node]
925 hbisect.save_state(repo, state)
925 hbisect.save_state(repo, state)
926 status = ui.system(command, environ={'HG_NODE': hex(node)})
926 status = ui.system(command, environ={'HG_NODE': hex(node)})
927 if status == 125:
927 if status == 125:
928 transition = "skip"
928 transition = "skip"
929 elif status == 0:
929 elif status == 0:
930 transition = "good"
930 transition = "good"
931 # status < 0 means process was killed
931 # status < 0 means process was killed
932 elif status == 127:
932 elif status == 127:
933 raise error.Abort(_("failed to execute %s") % command)
933 raise error.Abort(_("failed to execute %s") % command)
934 elif status < 0:
934 elif status < 0:
935 raise error.Abort(_("%s killed") % command)
935 raise error.Abort(_("%s killed") % command)
936 else:
936 else:
937 transition = "bad"
937 transition = "bad"
938 ctx = scmutil.revsingle(repo, rev, node)
938 ctx = scmutil.revsingle(repo, rev, node)
939 rev = None # clear for future iterations
939 rev = None # clear for future iterations
940 state[transition].append(ctx.node())
940 state[transition].append(ctx.node())
941 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
941 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
942 check_state(state, interactive=False)
942 check_state(state, interactive=False)
943 # bisect
943 # bisect
944 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
944 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
945 # update to next check
945 # update to next check
946 node = nodes[0]
946 node = nodes[0]
947 if not noupdate:
947 if not noupdate:
948 cmdutil.bailifchanged(repo)
948 cmdutil.bailifchanged(repo)
949 hg.clean(repo, node, show_stats=False)
949 hg.clean(repo, node, show_stats=False)
950 finally:
950 finally:
951 state['current'] = [node]
951 state['current'] = [node]
952 hbisect.save_state(repo, state)
952 hbisect.save_state(repo, state)
953 print_result(nodes, bgood)
953 print_result(nodes, bgood)
954 return
954 return
955
955
956 # update state
956 # update state
957
957
958 if rev:
958 if rev:
959 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
959 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
960 else:
960 else:
961 nodes = [repo.lookup('.')]
961 nodes = [repo.lookup('.')]
962
962
963 if good or bad or skip:
963 if good or bad or skip:
964 if good:
964 if good:
965 state['good'] += nodes
965 state['good'] += nodes
966 elif bad:
966 elif bad:
967 state['bad'] += nodes
967 state['bad'] += nodes
968 elif skip:
968 elif skip:
969 state['skip'] += nodes
969 state['skip'] += nodes
970 hbisect.save_state(repo, state)
970 hbisect.save_state(repo, state)
971
971
972 if not check_state(state):
972 if not check_state(state):
973 return
973 return
974
974
975 # actually bisect
975 # actually bisect
976 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
976 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
977 if extend:
977 if extend:
978 if not changesets:
978 if not changesets:
979 extendnode = extendbisectrange(nodes, good)
979 extendnode = extendbisectrange(nodes, good)
980 if extendnode is not None:
980 if extendnode is not None:
981 ui.write(_("Extending search to changeset %d:%s\n")
981 ui.write(_("Extending search to changeset %d:%s\n")
982 % (extendnode.rev(), extendnode))
982 % (extendnode.rev(), extendnode))
983 state['current'] = [extendnode.node()]
983 state['current'] = [extendnode.node()]
984 hbisect.save_state(repo, state)
984 hbisect.save_state(repo, state)
985 if noupdate:
985 if noupdate:
986 return
986 return
987 cmdutil.bailifchanged(repo)
987 cmdutil.bailifchanged(repo)
988 return hg.clean(repo, extendnode.node())
988 return hg.clean(repo, extendnode.node())
989 raise error.Abort(_("nothing to extend"))
989 raise error.Abort(_("nothing to extend"))
990
990
991 if changesets == 0:
991 if changesets == 0:
992 print_result(nodes, good)
992 print_result(nodes, good)
993 else:
993 else:
994 assert len(nodes) == 1 # only a single node can be tested next
994 assert len(nodes) == 1 # only a single node can be tested next
995 node = nodes[0]
995 node = nodes[0]
996 # compute the approximate number of remaining tests
996 # compute the approximate number of remaining tests
997 tests, size = 0, 2
997 tests, size = 0, 2
998 while size <= changesets:
998 while size <= changesets:
999 tests, size = tests + 1, size * 2
999 tests, size = tests + 1, size * 2
1000 rev = repo.changelog.rev(node)
1000 rev = repo.changelog.rev(node)
1001 ui.write(_("Testing changeset %d:%s "
1001 ui.write(_("Testing changeset %d:%s "
1002 "(%d changesets remaining, ~%d tests)\n")
1002 "(%d changesets remaining, ~%d tests)\n")
1003 % (rev, short(node), changesets, tests))
1003 % (rev, short(node), changesets, tests))
1004 state['current'] = [node]
1004 state['current'] = [node]
1005 hbisect.save_state(repo, state)
1005 hbisect.save_state(repo, state)
1006 if not noupdate:
1006 if not noupdate:
1007 cmdutil.bailifchanged(repo)
1007 cmdutil.bailifchanged(repo)
1008 return hg.clean(repo, node)
1008 return hg.clean(repo, node)
1009
1009
1010 @command('bookmarks|bookmark',
1010 @command('bookmarks|bookmark',
1011 [('f', 'force', False, _('force')),
1011 [('f', 'force', False, _('force')),
1012 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
1012 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
1013 ('d', 'delete', False, _('delete a given bookmark')),
1013 ('d', 'delete', False, _('delete a given bookmark')),
1014 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
1014 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
1015 ('i', 'inactive', False, _('mark a bookmark inactive')),
1015 ('i', 'inactive', False, _('mark a bookmark inactive')),
1016 ] + formatteropts,
1016 ] + formatteropts,
1017 _('hg bookmarks [OPTIONS]... [NAME]...'))
1017 _('hg bookmarks [OPTIONS]... [NAME]...'))
1018 def bookmark(ui, repo, *names, **opts):
1018 def bookmark(ui, repo, *names, **opts):
1019 '''create a new bookmark or list existing bookmarks
1019 '''create a new bookmark or list existing bookmarks
1020
1020
1021 Bookmarks are labels on changesets to help track lines of development.
1021 Bookmarks are labels on changesets to help track lines of development.
1022 Bookmarks are unversioned and can be moved, renamed and deleted.
1022 Bookmarks are unversioned and can be moved, renamed and deleted.
1023 Deleting or moving a bookmark has no effect on the associated changesets.
1023 Deleting or moving a bookmark has no effect on the associated changesets.
1024
1024
1025 Creating or updating to a bookmark causes it to be marked as 'active'.
1025 Creating or updating to a bookmark causes it to be marked as 'active'.
1026 The active bookmark is indicated with a '*'.
1026 The active bookmark is indicated with a '*'.
1027 When a commit is made, the active bookmark will advance to the new commit.
1027 When a commit is made, the active bookmark will advance to the new commit.
1028 A plain :hg:`update` will also advance an active bookmark, if possible.
1028 A plain :hg:`update` will also advance an active bookmark, if possible.
1029 Updating away from a bookmark will cause it to be deactivated.
1029 Updating away from a bookmark will cause it to be deactivated.
1030
1030
1031 Bookmarks can be pushed and pulled between repositories (see
1031 Bookmarks can be pushed and pulled between repositories (see
1032 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1032 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1033 diverged, a new 'divergent bookmark' of the form 'name@path' will
1033 diverged, a new 'divergent bookmark' of the form 'name@path' will
1034 be created. Using :hg:`merge` will resolve the divergence.
1034 be created. Using :hg:`merge` will resolve the divergence.
1035
1035
1036 A bookmark named '@' has the special property that :hg:`clone` will
1036 A bookmark named '@' has the special property that :hg:`clone` will
1037 check it out by default if it exists.
1037 check it out by default if it exists.
1038
1038
1039 .. container:: verbose
1039 .. container:: verbose
1040
1040
1041 Examples:
1041 Examples:
1042
1042
1043 - create an active bookmark for a new line of development::
1043 - create an active bookmark for a new line of development::
1044
1044
1045 hg book new-feature
1045 hg book new-feature
1046
1046
1047 - create an inactive bookmark as a place marker::
1047 - create an inactive bookmark as a place marker::
1048
1048
1049 hg book -i reviewed
1049 hg book -i reviewed
1050
1050
1051 - create an inactive bookmark on another changeset::
1051 - create an inactive bookmark on another changeset::
1052
1052
1053 hg book -r .^ tested
1053 hg book -r .^ tested
1054
1054
1055 - rename bookmark turkey to dinner::
1055 - rename bookmark turkey to dinner::
1056
1056
1057 hg book -m turkey dinner
1057 hg book -m turkey dinner
1058
1058
1059 - move the '@' bookmark from another branch::
1059 - move the '@' bookmark from another branch::
1060
1060
1061 hg book -f @
1061 hg book -f @
1062 '''
1062 '''
1063 force = opts.get('force')
1063 force = opts.get('force')
1064 rev = opts.get('rev')
1064 rev = opts.get('rev')
1065 delete = opts.get('delete')
1065 delete = opts.get('delete')
1066 rename = opts.get('rename')
1066 rename = opts.get('rename')
1067 inactive = opts.get('inactive')
1067 inactive = opts.get('inactive')
1068
1068
1069 def checkformat(mark):
1069 def checkformat(mark):
1070 mark = mark.strip()
1070 mark = mark.strip()
1071 if not mark:
1071 if not mark:
1072 raise error.Abort(_("bookmark names cannot consist entirely of "
1072 raise error.Abort(_("bookmark names cannot consist entirely of "
1073 "whitespace"))
1073 "whitespace"))
1074 scmutil.checknewlabel(repo, mark, 'bookmark')
1074 scmutil.checknewlabel(repo, mark, 'bookmark')
1075 return mark
1075 return mark
1076
1076
1077 def checkconflict(repo, mark, cur, force=False, target=None):
1077 def checkconflict(repo, mark, cur, force=False, target=None):
1078 if mark in marks and not force:
1078 if mark in marks and not force:
1079 if target:
1079 if target:
1080 if marks[mark] == target and target == cur:
1080 if marks[mark] == target and target == cur:
1081 # re-activating a bookmark
1081 # re-activating a bookmark
1082 return
1082 return
1083 anc = repo.changelog.ancestors([repo[target].rev()])
1083 anc = repo.changelog.ancestors([repo[target].rev()])
1084 bmctx = repo[marks[mark]]
1084 bmctx = repo[marks[mark]]
1085 divs = [repo[b].node() for b in marks
1085 divs = [repo[b].node() for b in marks
1086 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1086 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1087
1087
1088 # allow resolving a single divergent bookmark even if moving
1088 # allow resolving a single divergent bookmark even if moving
1089 # the bookmark across branches when a revision is specified
1089 # the bookmark across branches when a revision is specified
1090 # that contains a divergent bookmark
1090 # that contains a divergent bookmark
1091 if bmctx.rev() not in anc and target in divs:
1091 if bmctx.rev() not in anc and target in divs:
1092 bookmarks.deletedivergent(repo, [target], mark)
1092 bookmarks.deletedivergent(repo, [target], mark)
1093 return
1093 return
1094
1094
1095 deletefrom = [b for b in divs
1095 deletefrom = [b for b in divs
1096 if repo[b].rev() in anc or b == target]
1096 if repo[b].rev() in anc or b == target]
1097 bookmarks.deletedivergent(repo, deletefrom, mark)
1097 bookmarks.deletedivergent(repo, deletefrom, mark)
1098 if bookmarks.validdest(repo, bmctx, repo[target]):
1098 if bookmarks.validdest(repo, bmctx, repo[target]):
1099 ui.status(_("moving bookmark '%s' forward from %s\n") %
1099 ui.status(_("moving bookmark '%s' forward from %s\n") %
1100 (mark, short(bmctx.node())))
1100 (mark, short(bmctx.node())))
1101 return
1101 return
1102 raise error.Abort(_("bookmark '%s' already exists "
1102 raise error.Abort(_("bookmark '%s' already exists "
1103 "(use -f to force)") % mark)
1103 "(use -f to force)") % mark)
1104 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1104 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1105 and not force):
1105 and not force):
1106 raise error.Abort(
1106 raise error.Abort(
1107 _("a bookmark cannot have the name of an existing branch"))
1107 _("a bookmark cannot have the name of an existing branch"))
1108
1108
1109 if delete and rename:
1109 if delete and rename:
1110 raise error.Abort(_("--delete and --rename are incompatible"))
1110 raise error.Abort(_("--delete and --rename are incompatible"))
1111 if delete and rev:
1111 if delete and rev:
1112 raise error.Abort(_("--rev is incompatible with --delete"))
1112 raise error.Abort(_("--rev is incompatible with --delete"))
1113 if rename and rev:
1113 if rename and rev:
1114 raise error.Abort(_("--rev is incompatible with --rename"))
1114 raise error.Abort(_("--rev is incompatible with --rename"))
1115 if not names and (delete or rev):
1115 if not names and (delete or rev):
1116 raise error.Abort(_("bookmark name required"))
1116 raise error.Abort(_("bookmark name required"))
1117
1117
1118 if delete or rename or names or inactive:
1118 if delete or rename or names or inactive:
1119 wlock = lock = tr = None
1119 wlock = lock = tr = None
1120 try:
1120 try:
1121 wlock = repo.wlock()
1121 wlock = repo.wlock()
1122 lock = repo.lock()
1122 lock = repo.lock()
1123 cur = repo.changectx('.').node()
1123 cur = repo.changectx('.').node()
1124 marks = repo._bookmarks
1124 marks = repo._bookmarks
1125 if delete:
1125 if delete:
1126 tr = repo.transaction('bookmark')
1126 tr = repo.transaction('bookmark')
1127 for mark in names:
1127 for mark in names:
1128 if mark not in marks:
1128 if mark not in marks:
1129 raise error.Abort(_("bookmark '%s' does not exist") %
1129 raise error.Abort(_("bookmark '%s' does not exist") %
1130 mark)
1130 mark)
1131 if mark == repo._activebookmark:
1131 if mark == repo._activebookmark:
1132 bookmarks.deactivate(repo)
1132 bookmarks.deactivate(repo)
1133 del marks[mark]
1133 del marks[mark]
1134
1134
1135 elif rename:
1135 elif rename:
1136 tr = repo.transaction('bookmark')
1136 tr = repo.transaction('bookmark')
1137 if not names:
1137 if not names:
1138 raise error.Abort(_("new bookmark name required"))
1138 raise error.Abort(_("new bookmark name required"))
1139 elif len(names) > 1:
1139 elif len(names) > 1:
1140 raise error.Abort(_("only one new bookmark name allowed"))
1140 raise error.Abort(_("only one new bookmark name allowed"))
1141 mark = checkformat(names[0])
1141 mark = checkformat(names[0])
1142 if rename not in marks:
1142 if rename not in marks:
1143 raise error.Abort(_("bookmark '%s' does not exist")
1143 raise error.Abort(_("bookmark '%s' does not exist")
1144 % rename)
1144 % rename)
1145 checkconflict(repo, mark, cur, force)
1145 checkconflict(repo, mark, cur, force)
1146 marks[mark] = marks[rename]
1146 marks[mark] = marks[rename]
1147 if repo._activebookmark == rename and not inactive:
1147 if repo._activebookmark == rename and not inactive:
1148 bookmarks.activate(repo, mark)
1148 bookmarks.activate(repo, mark)
1149 del marks[rename]
1149 del marks[rename]
1150 elif names:
1150 elif names:
1151 tr = repo.transaction('bookmark')
1151 tr = repo.transaction('bookmark')
1152 newact = None
1152 newact = None
1153 for mark in names:
1153 for mark in names:
1154 mark = checkformat(mark)
1154 mark = checkformat(mark)
1155 if newact is None:
1155 if newact is None:
1156 newact = mark
1156 newact = mark
1157 if inactive and mark == repo._activebookmark:
1157 if inactive and mark == repo._activebookmark:
1158 bookmarks.deactivate(repo)
1158 bookmarks.deactivate(repo)
1159 return
1159 return
1160 tgt = cur
1160 tgt = cur
1161 if rev:
1161 if rev:
1162 tgt = scmutil.revsingle(repo, rev).node()
1162 tgt = scmutil.revsingle(repo, rev).node()
1163 checkconflict(repo, mark, cur, force, tgt)
1163 checkconflict(repo, mark, cur, force, tgt)
1164 marks[mark] = tgt
1164 marks[mark] = tgt
1165 if not inactive and cur == marks[newact] and not rev:
1165 if not inactive and cur == marks[newact] and not rev:
1166 bookmarks.activate(repo, newact)
1166 bookmarks.activate(repo, newact)
1167 elif cur != tgt and newact == repo._activebookmark:
1167 elif cur != tgt and newact == repo._activebookmark:
1168 bookmarks.deactivate(repo)
1168 bookmarks.deactivate(repo)
1169 elif inactive:
1169 elif inactive:
1170 if len(marks) == 0:
1170 if len(marks) == 0:
1171 ui.status(_("no bookmarks set\n"))
1171 ui.status(_("no bookmarks set\n"))
1172 elif not repo._activebookmark:
1172 elif not repo._activebookmark:
1173 ui.status(_("no active bookmark\n"))
1173 ui.status(_("no active bookmark\n"))
1174 else:
1174 else:
1175 bookmarks.deactivate(repo)
1175 bookmarks.deactivate(repo)
1176 if tr is not None:
1176 if tr is not None:
1177 marks.recordchange(tr)
1177 marks.recordchange(tr)
1178 tr.close()
1178 tr.close()
1179 finally:
1179 finally:
1180 lockmod.release(tr, lock, wlock)
1180 lockmod.release(tr, lock, wlock)
1181 else: # show bookmarks
1181 else: # show bookmarks
1182 fm = ui.formatter('bookmarks', opts)
1182 fm = ui.formatter('bookmarks', opts)
1183 hexfn = fm.hexfunc
1183 hexfn = fm.hexfunc
1184 marks = repo._bookmarks
1184 marks = repo._bookmarks
1185 if len(marks) == 0 and not fm:
1185 if len(marks) == 0 and not fm:
1186 ui.status(_("no bookmarks set\n"))
1186 ui.status(_("no bookmarks set\n"))
1187 for bmark, n in sorted(marks.iteritems()):
1187 for bmark, n in sorted(marks.iteritems()):
1188 active = repo._activebookmark
1188 active = repo._activebookmark
1189 if bmark == active:
1189 if bmark == active:
1190 prefix, label = '*', activebookmarklabel
1190 prefix, label = '*', activebookmarklabel
1191 else:
1191 else:
1192 prefix, label = ' ', ''
1192 prefix, label = ' ', ''
1193
1193
1194 fm.startitem()
1194 fm.startitem()
1195 if not ui.quiet:
1195 if not ui.quiet:
1196 fm.plain(' %s ' % prefix, label=label)
1196 fm.plain(' %s ' % prefix, label=label)
1197 fm.write('bookmark', '%s', bmark, label=label)
1197 fm.write('bookmark', '%s', bmark, label=label)
1198 pad = " " * (25 - encoding.colwidth(bmark))
1198 pad = " " * (25 - encoding.colwidth(bmark))
1199 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1199 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1200 repo.changelog.rev(n), hexfn(n), label=label)
1200 repo.changelog.rev(n), hexfn(n), label=label)
1201 fm.data(active=(bmark == active))
1201 fm.data(active=(bmark == active))
1202 fm.plain('\n')
1202 fm.plain('\n')
1203 fm.end()
1203 fm.end()
1204
1204
1205 @command('branch',
1205 @command('branch',
1206 [('f', 'force', None,
1206 [('f', 'force', None,
1207 _('set branch name even if it shadows an existing branch')),
1207 _('set branch name even if it shadows an existing branch')),
1208 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1208 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1209 _('[-fC] [NAME]'))
1209 _('[-fC] [NAME]'))
1210 def branch(ui, repo, label=None, **opts):
1210 def branch(ui, repo, label=None, **opts):
1211 """set or show the current branch name
1211 """set or show the current branch name
1212
1212
1213 .. note::
1213 .. note::
1214
1214
1215 Branch names are permanent and global. Use :hg:`bookmark` to create a
1215 Branch names are permanent and global. Use :hg:`bookmark` to create a
1216 light-weight bookmark instead. See :hg:`help glossary` for more
1216 light-weight bookmark instead. See :hg:`help glossary` for more
1217 information about named branches and bookmarks.
1217 information about named branches and bookmarks.
1218
1218
1219 With no argument, show the current branch name. With one argument,
1219 With no argument, show the current branch name. With one argument,
1220 set the working directory branch name (the branch will not exist
1220 set the working directory branch name (the branch will not exist
1221 in the repository until the next commit). Standard practice
1221 in the repository until the next commit). Standard practice
1222 recommends that primary development take place on the 'default'
1222 recommends that primary development take place on the 'default'
1223 branch.
1223 branch.
1224
1224
1225 Unless -f/--force is specified, branch will not let you set a
1225 Unless -f/--force is specified, branch will not let you set a
1226 branch name that already exists.
1226 branch name that already exists.
1227
1227
1228 Use -C/--clean to reset the working directory branch to that of
1228 Use -C/--clean to reset the working directory branch to that of
1229 the parent of the working directory, negating a previous branch
1229 the parent of the working directory, negating a previous branch
1230 change.
1230 change.
1231
1231
1232 Use the command :hg:`update` to switch to an existing branch. Use
1232 Use the command :hg:`update` to switch to an existing branch. Use
1233 :hg:`commit --close-branch` to mark this branch head as closed.
1233 :hg:`commit --close-branch` to mark this branch head as closed.
1234 When all heads of a branch are closed, the branch will be
1234 When all heads of a branch are closed, the branch will be
1235 considered closed.
1235 considered closed.
1236
1236
1237 Returns 0 on success.
1237 Returns 0 on success.
1238 """
1238 """
1239 if label:
1239 if label:
1240 label = label.strip()
1240 label = label.strip()
1241
1241
1242 if not opts.get('clean') and not label:
1242 if not opts.get('clean') and not label:
1243 ui.write("%s\n" % repo.dirstate.branch())
1243 ui.write("%s\n" % repo.dirstate.branch())
1244 return
1244 return
1245
1245
1246 with repo.wlock():
1246 with repo.wlock():
1247 if opts.get('clean'):
1247 if opts.get('clean'):
1248 label = repo[None].p1().branch()
1248 label = repo[None].p1().branch()
1249 repo.dirstate.setbranch(label)
1249 repo.dirstate.setbranch(label)
1250 ui.status(_('reset working directory to branch %s\n') % label)
1250 ui.status(_('reset working directory to branch %s\n') % label)
1251 elif label:
1251 elif label:
1252 if not opts.get('force') and label in repo.branchmap():
1252 if not opts.get('force') and label in repo.branchmap():
1253 if label not in [p.branch() for p in repo[None].parents()]:
1253 if label not in [p.branch() for p in repo[None].parents()]:
1254 raise error.Abort(_('a branch of the same name already'
1254 raise error.Abort(_('a branch of the same name already'
1255 ' exists'),
1255 ' exists'),
1256 # i18n: "it" refers to an existing branch
1256 # i18n: "it" refers to an existing branch
1257 hint=_("use 'hg update' to switch to it"))
1257 hint=_("use 'hg update' to switch to it"))
1258 scmutil.checknewlabel(repo, label, 'branch')
1258 scmutil.checknewlabel(repo, label, 'branch')
1259 repo.dirstate.setbranch(label)
1259 repo.dirstate.setbranch(label)
1260 ui.status(_('marked working directory as branch %s\n') % label)
1260 ui.status(_('marked working directory as branch %s\n') % label)
1261
1261
1262 # find any open named branches aside from default
1262 # find any open named branches aside from default
1263 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1263 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1264 if n != "default" and not c]
1264 if n != "default" and not c]
1265 if not others:
1265 if not others:
1266 ui.status(_('(branches are permanent and global, '
1266 ui.status(_('(branches are permanent and global, '
1267 'did you want a bookmark?)\n'))
1267 'did you want a bookmark?)\n'))
1268
1268
1269 @command('branches',
1269 @command('branches',
1270 [('a', 'active', False,
1270 [('a', 'active', False,
1271 _('show only branches that have unmerged heads (DEPRECATED)')),
1271 _('show only branches that have unmerged heads (DEPRECATED)')),
1272 ('c', 'closed', False, _('show normal and closed branches')),
1272 ('c', 'closed', False, _('show normal and closed branches')),
1273 ] + formatteropts,
1273 ] + formatteropts,
1274 _('[-c]'))
1274 _('[-c]'))
1275 def branches(ui, repo, active=False, closed=False, **opts):
1275 def branches(ui, repo, active=False, closed=False, **opts):
1276 """list repository named branches
1276 """list repository named branches
1277
1277
1278 List the repository's named branches, indicating which ones are
1278 List the repository's named branches, indicating which ones are
1279 inactive. If -c/--closed is specified, also list branches which have
1279 inactive. If -c/--closed is specified, also list branches which have
1280 been marked closed (see :hg:`commit --close-branch`).
1280 been marked closed (see :hg:`commit --close-branch`).
1281
1281
1282 Use the command :hg:`update` to switch to an existing branch.
1282 Use the command :hg:`update` to switch to an existing branch.
1283
1283
1284 Returns 0.
1284 Returns 0.
1285 """
1285 """
1286
1286
1287 fm = ui.formatter('branches', opts)
1287 fm = ui.formatter('branches', opts)
1288 hexfunc = fm.hexfunc
1288 hexfunc = fm.hexfunc
1289
1289
1290 allheads = set(repo.heads())
1290 allheads = set(repo.heads())
1291 branches = []
1291 branches = []
1292 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1292 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1293 isactive = not isclosed and bool(set(heads) & allheads)
1293 isactive = not isclosed and bool(set(heads) & allheads)
1294 branches.append((tag, repo[tip], isactive, not isclosed))
1294 branches.append((tag, repo[tip], isactive, not isclosed))
1295 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1295 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1296 reverse=True)
1296 reverse=True)
1297
1297
1298 for tag, ctx, isactive, isopen in branches:
1298 for tag, ctx, isactive, isopen in branches:
1299 if active and not isactive:
1299 if active and not isactive:
1300 continue
1300 continue
1301 if isactive:
1301 if isactive:
1302 label = 'branches.active'
1302 label = 'branches.active'
1303 notice = ''
1303 notice = ''
1304 elif not isopen:
1304 elif not isopen:
1305 if not closed:
1305 if not closed:
1306 continue
1306 continue
1307 label = 'branches.closed'
1307 label = 'branches.closed'
1308 notice = _(' (closed)')
1308 notice = _(' (closed)')
1309 else:
1309 else:
1310 label = 'branches.inactive'
1310 label = 'branches.inactive'
1311 notice = _(' (inactive)')
1311 notice = _(' (inactive)')
1312 current = (tag == repo.dirstate.branch())
1312 current = (tag == repo.dirstate.branch())
1313 if current:
1313 if current:
1314 label = 'branches.current'
1314 label = 'branches.current'
1315
1315
1316 fm.startitem()
1316 fm.startitem()
1317 fm.write('branch', '%s', tag, label=label)
1317 fm.write('branch', '%s', tag, label=label)
1318 rev = ctx.rev()
1318 rev = ctx.rev()
1319 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1319 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1320 fmt = ' ' * padsize + ' %d:%s'
1320 fmt = ' ' * padsize + ' %d:%s'
1321 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1321 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1322 label='log.changeset changeset.%s' % ctx.phasestr())
1322 label='log.changeset changeset.%s' % ctx.phasestr())
1323 fm.data(active=isactive, closed=not isopen, current=current)
1323 fm.data(active=isactive, closed=not isopen, current=current)
1324 if not ui.quiet:
1324 if not ui.quiet:
1325 fm.plain(notice)
1325 fm.plain(notice)
1326 fm.plain('\n')
1326 fm.plain('\n')
1327 fm.end()
1327 fm.end()
1328
1328
1329 @command('bundle',
1329 @command('bundle',
1330 [('f', 'force', None, _('run even when the destination is unrelated')),
1330 [('f', 'force', None, _('run even when the destination is unrelated')),
1331 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1331 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1332 _('REV')),
1332 _('REV')),
1333 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1333 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1334 _('BRANCH')),
1334 _('BRANCH')),
1335 ('', 'base', [],
1335 ('', 'base', [],
1336 _('a base changeset assumed to be available at the destination'),
1336 _('a base changeset assumed to be available at the destination'),
1337 _('REV')),
1337 _('REV')),
1338 ('a', 'all', None, _('bundle all changesets in the repository')),
1338 ('a', 'all', None, _('bundle all changesets in the repository')),
1339 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1339 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1340 ] + remoteopts,
1340 ] + remoteopts,
1341 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1341 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1342 def bundle(ui, repo, fname, dest=None, **opts):
1342 def bundle(ui, repo, fname, dest=None, **opts):
1343 """create a changegroup file
1343 """create a changegroup file
1344
1344
1345 Generate a changegroup file collecting changesets to be added
1345 Generate a changegroup file collecting changesets to be added
1346 to a repository.
1346 to a repository.
1347
1347
1348 To create a bundle containing all changesets, use -a/--all
1348 To create a bundle containing all changesets, use -a/--all
1349 (or --base null). Otherwise, hg assumes the destination will have
1349 (or --base null). Otherwise, hg assumes the destination will have
1350 all the nodes you specify with --base parameters. Otherwise, hg
1350 all the nodes you specify with --base parameters. Otherwise, hg
1351 will assume the repository has all the nodes in destination, or
1351 will assume the repository has all the nodes in destination, or
1352 default-push/default if no destination is specified.
1352 default-push/default if no destination is specified.
1353
1353
1354 You can change bundle format with the -t/--type option. You can
1354 You can change bundle format with the -t/--type option. You can
1355 specify a compression, a bundle version or both using a dash
1355 specify a compression, a bundle version or both using a dash
1356 (comp-version). The available compression methods are: none, bzip2,
1356 (comp-version). The available compression methods are: none, bzip2,
1357 and gzip (by default, bundles are compressed using bzip2). The
1357 and gzip (by default, bundles are compressed using bzip2). The
1358 available formats are: v1, v2 (default to most suitable).
1358 available formats are: v1, v2 (default to most suitable).
1359
1359
1360 The bundle file can then be transferred using conventional means
1360 The bundle file can then be transferred using conventional means
1361 and applied to another repository with the unbundle or pull
1361 and applied to another repository with the unbundle or pull
1362 command. This is useful when direct push and pull are not
1362 command. This is useful when direct push and pull are not
1363 available or when exporting an entire repository is undesirable.
1363 available or when exporting an entire repository is undesirable.
1364
1364
1365 Applying bundles preserves all changeset contents including
1365 Applying bundles preserves all changeset contents including
1366 permissions, copy/rename information, and revision history.
1366 permissions, copy/rename information, and revision history.
1367
1367
1368 Returns 0 on success, 1 if no changes found.
1368 Returns 0 on success, 1 if no changes found.
1369 """
1369 """
1370 revs = None
1370 revs = None
1371 if 'rev' in opts:
1371 if 'rev' in opts:
1372 revstrings = opts['rev']
1372 revstrings = opts['rev']
1373 revs = scmutil.revrange(repo, revstrings)
1373 revs = scmutil.revrange(repo, revstrings)
1374 if revstrings and not revs:
1374 if revstrings and not revs:
1375 raise error.Abort(_('no commits to bundle'))
1375 raise error.Abort(_('no commits to bundle'))
1376
1376
1377 bundletype = opts.get('type', 'bzip2').lower()
1377 bundletype = opts.get('type', 'bzip2').lower()
1378 try:
1378 try:
1379 bcompression, cgversion, params = exchange.parsebundlespec(
1379 bcompression, cgversion, params = exchange.parsebundlespec(
1380 repo, bundletype, strict=False)
1380 repo, bundletype, strict=False)
1381 except error.UnsupportedBundleSpecification as e:
1381 except error.UnsupportedBundleSpecification as e:
1382 raise error.Abort(str(e),
1382 raise error.Abort(str(e),
1383 hint=_('see "hg help bundle" for supported '
1383 hint=_('see "hg help bundle" for supported '
1384 'values for --type'))
1384 'values for --type'))
1385
1385
1386 # Packed bundles are a pseudo bundle format for now.
1386 # Packed bundles are a pseudo bundle format for now.
1387 if cgversion == 's1':
1387 if cgversion == 's1':
1388 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1388 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1389 hint=_('use "hg debugcreatestreamclonebundle"'))
1389 hint=_('use "hg debugcreatestreamclonebundle"'))
1390
1390
1391 if opts.get('all'):
1391 if opts.get('all'):
1392 if dest:
1392 if dest:
1393 raise error.Abort(_("--all is incompatible with specifying "
1393 raise error.Abort(_("--all is incompatible with specifying "
1394 "a destination"))
1394 "a destination"))
1395 if opts.get('base'):
1395 if opts.get('base'):
1396 ui.warn(_("ignoring --base because --all was specified\n"))
1396 ui.warn(_("ignoring --base because --all was specified\n"))
1397 base = ['null']
1397 base = ['null']
1398 else:
1398 else:
1399 base = scmutil.revrange(repo, opts.get('base'))
1399 base = scmutil.revrange(repo, opts.get('base'))
1400 # TODO: get desired bundlecaps from command line.
1400 # TODO: get desired bundlecaps from command line.
1401 bundlecaps = None
1401 bundlecaps = None
1402 if base:
1402 if base:
1403 if dest:
1403 if dest:
1404 raise error.Abort(_("--base is incompatible with specifying "
1404 raise error.Abort(_("--base is incompatible with specifying "
1405 "a destination"))
1405 "a destination"))
1406 common = [repo.lookup(rev) for rev in base]
1406 common = [repo.lookup(rev) for rev in base]
1407 heads = revs and map(repo.lookup, revs) or revs
1407 heads = revs and map(repo.lookup, revs) or revs
1408 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1408 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1409 common=common, bundlecaps=bundlecaps,
1409 common=common, bundlecaps=bundlecaps,
1410 version=cgversion)
1410 version=cgversion)
1411 outgoing = None
1411 outgoing = None
1412 else:
1412 else:
1413 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1413 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1414 dest, branches = hg.parseurl(dest, opts.get('branch'))
1414 dest, branches = hg.parseurl(dest, opts.get('branch'))
1415 other = hg.peer(repo, opts, dest)
1415 other = hg.peer(repo, opts, dest)
1416 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1416 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1417 heads = revs and map(repo.lookup, revs) or revs
1417 heads = revs and map(repo.lookup, revs) or revs
1418 outgoing = discovery.findcommonoutgoing(repo, other,
1418 outgoing = discovery.findcommonoutgoing(repo, other,
1419 onlyheads=heads,
1419 onlyheads=heads,
1420 force=opts.get('force'),
1420 force=opts.get('force'),
1421 portable=True)
1421 portable=True)
1422 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1422 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1423 bundlecaps, version=cgversion)
1423 bundlecaps, version=cgversion)
1424 if not cg:
1424 if not cg:
1425 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1425 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1426 return 1
1426 return 1
1427
1427
1428 if cgversion == '01': #bundle1
1428 if cgversion == '01': #bundle1
1429 if bcompression is None:
1429 if bcompression is None:
1430 bcompression = 'UN'
1430 bcompression = 'UN'
1431 bversion = 'HG10' + bcompression
1431 bversion = 'HG10' + bcompression
1432 bcompression = None
1432 bcompression = None
1433 else:
1433 else:
1434 assert cgversion == '02'
1434 assert cgversion == '02'
1435 bversion = 'HG20'
1435 bversion = 'HG20'
1436
1436
1437
1437
1438 changegroup.writebundle(ui, cg, fname, bversion, compression=bcompression)
1438 changegroup.writebundle(ui, cg, fname, bversion, compression=bcompression)
1439
1439
1440 @command('cat',
1440 @command('cat',
1441 [('o', 'output', '',
1441 [('o', 'output', '',
1442 _('print output to file with formatted name'), _('FORMAT')),
1442 _('print output to file with formatted name'), _('FORMAT')),
1443 ('r', 'rev', '', _('print the given revision'), _('REV')),
1443 ('r', 'rev', '', _('print the given revision'), _('REV')),
1444 ('', 'decode', None, _('apply any matching decode filter')),
1444 ('', 'decode', None, _('apply any matching decode filter')),
1445 ] + walkopts,
1445 ] + walkopts,
1446 _('[OPTION]... FILE...'),
1446 _('[OPTION]... FILE...'),
1447 inferrepo=True)
1447 inferrepo=True)
1448 def cat(ui, repo, file1, *pats, **opts):
1448 def cat(ui, repo, file1, *pats, **opts):
1449 """output the current or given revision of files
1449 """output the current or given revision of files
1450
1450
1451 Print the specified files as they were at the given revision. If
1451 Print the specified files as they were at the given revision. If
1452 no revision is given, the parent of the working directory is used.
1452 no revision is given, the parent of the working directory is used.
1453
1453
1454 Output may be to a file, in which case the name of the file is
1454 Output may be to a file, in which case the name of the file is
1455 given using a format string. The formatting rules as follows:
1455 given using a format string. The formatting rules as follows:
1456
1456
1457 :``%%``: literal "%" character
1457 :``%%``: literal "%" character
1458 :``%s``: basename of file being printed
1458 :``%s``: basename of file being printed
1459 :``%d``: dirname of file being printed, or '.' if in repository root
1459 :``%d``: dirname of file being printed, or '.' if in repository root
1460 :``%p``: root-relative path name of file being printed
1460 :``%p``: root-relative path name of file being printed
1461 :``%H``: changeset hash (40 hexadecimal digits)
1461 :``%H``: changeset hash (40 hexadecimal digits)
1462 :``%R``: changeset revision number
1462 :``%R``: changeset revision number
1463 :``%h``: short-form changeset hash (12 hexadecimal digits)
1463 :``%h``: short-form changeset hash (12 hexadecimal digits)
1464 :``%r``: zero-padded changeset revision number
1464 :``%r``: zero-padded changeset revision number
1465 :``%b``: basename of the exporting repository
1465 :``%b``: basename of the exporting repository
1466
1466
1467 Returns 0 on success.
1467 Returns 0 on success.
1468 """
1468 """
1469 ctx = scmutil.revsingle(repo, opts.get('rev'))
1469 ctx = scmutil.revsingle(repo, opts.get('rev'))
1470 m = scmutil.match(ctx, (file1,) + pats, opts)
1470 m = scmutil.match(ctx, (file1,) + pats, opts)
1471
1471
1472 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1472 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1473
1473
1474 @command('^clone',
1474 @command('^clone',
1475 [('U', 'noupdate', None, _('the clone will include an empty working '
1475 [('U', 'noupdate', None, _('the clone will include an empty working '
1476 'directory (only a repository)')),
1476 'directory (only a repository)')),
1477 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1477 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1478 _('REV')),
1478 _('REV')),
1479 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1479 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1480 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1480 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1481 ('', 'pull', None, _('use pull protocol to copy metadata')),
1481 ('', 'pull', None, _('use pull protocol to copy metadata')),
1482 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1482 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1483 ] + remoteopts,
1483 ] + remoteopts,
1484 _('[OPTION]... SOURCE [DEST]'),
1484 _('[OPTION]... SOURCE [DEST]'),
1485 norepo=True)
1485 norepo=True)
1486 def clone(ui, source, dest=None, **opts):
1486 def clone(ui, source, dest=None, **opts):
1487 """make a copy of an existing repository
1487 """make a copy of an existing repository
1488
1488
1489 Create a copy of an existing repository in a new directory.
1489 Create a copy of an existing repository in a new directory.
1490
1490
1491 If no destination directory name is specified, it defaults to the
1491 If no destination directory name is specified, it defaults to the
1492 basename of the source.
1492 basename of the source.
1493
1493
1494 The location of the source is added to the new repository's
1494 The location of the source is added to the new repository's
1495 ``.hg/hgrc`` file, as the default to be used for future pulls.
1495 ``.hg/hgrc`` file, as the default to be used for future pulls.
1496
1496
1497 Only local paths and ``ssh://`` URLs are supported as
1497 Only local paths and ``ssh://`` URLs are supported as
1498 destinations. For ``ssh://`` destinations, no working directory or
1498 destinations. For ``ssh://`` destinations, no working directory or
1499 ``.hg/hgrc`` will be created on the remote side.
1499 ``.hg/hgrc`` will be created on the remote side.
1500
1500
1501 If the source repository has a bookmark called '@' set, that
1501 If the source repository has a bookmark called '@' set, that
1502 revision will be checked out in the new repository by default.
1502 revision will be checked out in the new repository by default.
1503
1503
1504 To check out a particular version, use -u/--update, or
1504 To check out a particular version, use -u/--update, or
1505 -U/--noupdate to create a clone with no working directory.
1505 -U/--noupdate to create a clone with no working directory.
1506
1506
1507 To pull only a subset of changesets, specify one or more revisions
1507 To pull only a subset of changesets, specify one or more revisions
1508 identifiers with -r/--rev or branches with -b/--branch. The
1508 identifiers with -r/--rev or branches with -b/--branch. The
1509 resulting clone will contain only the specified changesets and
1509 resulting clone will contain only the specified changesets and
1510 their ancestors. These options (or 'clone src#rev dest') imply
1510 their ancestors. These options (or 'clone src#rev dest') imply
1511 --pull, even for local source repositories.
1511 --pull, even for local source repositories.
1512
1512
1513 .. note::
1513 .. note::
1514
1514
1515 Specifying a tag will include the tagged changeset but not the
1515 Specifying a tag will include the tagged changeset but not the
1516 changeset containing the tag.
1516 changeset containing the tag.
1517
1517
1518 .. container:: verbose
1518 .. container:: verbose
1519
1519
1520 For efficiency, hardlinks are used for cloning whenever the
1520 For efficiency, hardlinks are used for cloning whenever the
1521 source and destination are on the same filesystem (note this
1521 source and destination are on the same filesystem (note this
1522 applies only to the repository data, not to the working
1522 applies only to the repository data, not to the working
1523 directory). Some filesystems, such as AFS, implement hardlinking
1523 directory). Some filesystems, such as AFS, implement hardlinking
1524 incorrectly, but do not report errors. In these cases, use the
1524 incorrectly, but do not report errors. In these cases, use the
1525 --pull option to avoid hardlinking.
1525 --pull option to avoid hardlinking.
1526
1526
1527 In some cases, you can clone repositories and the working
1527 In some cases, you can clone repositories and the working
1528 directory using full hardlinks with ::
1528 directory using full hardlinks with ::
1529
1529
1530 $ cp -al REPO REPOCLONE
1530 $ cp -al REPO REPOCLONE
1531
1531
1532 This is the fastest way to clone, but it is not always safe. The
1532 This is the fastest way to clone, but it is not always safe. The
1533 operation is not atomic (making sure REPO is not modified during
1533 operation is not atomic (making sure REPO is not modified during
1534 the operation is up to you) and you have to make sure your
1534 the operation is up to you) and you have to make sure your
1535 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1535 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1536 so). Also, this is not compatible with certain extensions that
1536 so). Also, this is not compatible with certain extensions that
1537 place their metadata under the .hg directory, such as mq.
1537 place their metadata under the .hg directory, such as mq.
1538
1538
1539 Mercurial will update the working directory to the first applicable
1539 Mercurial will update the working directory to the first applicable
1540 revision from this list:
1540 revision from this list:
1541
1541
1542 a) null if -U or the source repository has no changesets
1542 a) null if -U or the source repository has no changesets
1543 b) if -u . and the source repository is local, the first parent of
1543 b) if -u . and the source repository is local, the first parent of
1544 the source repository's working directory
1544 the source repository's working directory
1545 c) the changeset specified with -u (if a branch name, this means the
1545 c) the changeset specified with -u (if a branch name, this means the
1546 latest head of that branch)
1546 latest head of that branch)
1547 d) the changeset specified with -r
1547 d) the changeset specified with -r
1548 e) the tipmost head specified with -b
1548 e) the tipmost head specified with -b
1549 f) the tipmost head specified with the url#branch source syntax
1549 f) the tipmost head specified with the url#branch source syntax
1550 g) the revision marked with the '@' bookmark, if present
1550 g) the revision marked with the '@' bookmark, if present
1551 h) the tipmost head of the default branch
1551 h) the tipmost head of the default branch
1552 i) tip
1552 i) tip
1553
1553
1554 When cloning from servers that support it, Mercurial may fetch
1554 When cloning from servers that support it, Mercurial may fetch
1555 pre-generated data from a server-advertised URL. When this is done,
1555 pre-generated data from a server-advertised URL. When this is done,
1556 hooks operating on incoming changesets and changegroups may fire twice,
1556 hooks operating on incoming changesets and changegroups may fire twice,
1557 once for the bundle fetched from the URL and another for any additional
1557 once for the bundle fetched from the URL and another for any additional
1558 data not fetched from this URL. In addition, if an error occurs, the
1558 data not fetched from this URL. In addition, if an error occurs, the
1559 repository may be rolled back to a partial clone. This behavior may
1559 repository may be rolled back to a partial clone. This behavior may
1560 change in future releases. See :hg:`help -e clonebundles` for more.
1560 change in future releases. See :hg:`help -e clonebundles` for more.
1561
1561
1562 Examples:
1562 Examples:
1563
1563
1564 - clone a remote repository to a new directory named hg/::
1564 - clone a remote repository to a new directory named hg/::
1565
1565
1566 hg clone http://selenic.com/hg
1566 hg clone http://selenic.com/hg
1567
1567
1568 - create a lightweight local clone::
1568 - create a lightweight local clone::
1569
1569
1570 hg clone project/ project-feature/
1570 hg clone project/ project-feature/
1571
1571
1572 - clone from an absolute path on an ssh server (note double-slash)::
1572 - clone from an absolute path on an ssh server (note double-slash)::
1573
1573
1574 hg clone ssh://user@server//home/projects/alpha/
1574 hg clone ssh://user@server//home/projects/alpha/
1575
1575
1576 - do a high-speed clone over a LAN while checking out a
1576 - do a high-speed clone over a LAN while checking out a
1577 specified version::
1577 specified version::
1578
1578
1579 hg clone --uncompressed http://server/repo -u 1.5
1579 hg clone --uncompressed http://server/repo -u 1.5
1580
1580
1581 - create a repository without changesets after a particular revision::
1581 - create a repository without changesets after a particular revision::
1582
1582
1583 hg clone -r 04e544 experimental/ good/
1583 hg clone -r 04e544 experimental/ good/
1584
1584
1585 - clone (and track) a particular named branch::
1585 - clone (and track) a particular named branch::
1586
1586
1587 hg clone http://selenic.com/hg#stable
1587 hg clone http://selenic.com/hg#stable
1588
1588
1589 See :hg:`help urls` for details on specifying URLs.
1589 See :hg:`help urls` for details on specifying URLs.
1590
1590
1591 Returns 0 on success.
1591 Returns 0 on success.
1592 """
1592 """
1593 if opts.get('noupdate') and opts.get('updaterev'):
1593 if opts.get('noupdate') and opts.get('updaterev'):
1594 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1594 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1595
1595
1596 r = hg.clone(ui, opts, source, dest,
1596 r = hg.clone(ui, opts, source, dest,
1597 pull=opts.get('pull'),
1597 pull=opts.get('pull'),
1598 stream=opts.get('uncompressed'),
1598 stream=opts.get('uncompressed'),
1599 rev=opts.get('rev'),
1599 rev=opts.get('rev'),
1600 update=opts.get('updaterev') or not opts.get('noupdate'),
1600 update=opts.get('updaterev') or not opts.get('noupdate'),
1601 branch=opts.get('branch'),
1601 branch=opts.get('branch'),
1602 shareopts=opts.get('shareopts'))
1602 shareopts=opts.get('shareopts'))
1603
1603
1604 return r is None
1604 return r is None
1605
1605
1606 @command('^commit|ci',
1606 @command('^commit|ci',
1607 [('A', 'addremove', None,
1607 [('A', 'addremove', None,
1608 _('mark new/missing files as added/removed before committing')),
1608 _('mark new/missing files as added/removed before committing')),
1609 ('', 'close-branch', None,
1609 ('', 'close-branch', None,
1610 _('mark a branch head as closed')),
1610 _('mark a branch head as closed')),
1611 ('', 'amend', None, _('amend the parent of the working directory')),
1611 ('', 'amend', None, _('amend the parent of the working directory')),
1612 ('s', 'secret', None, _('use the secret phase for committing')),
1612 ('s', 'secret', None, _('use the secret phase for committing')),
1613 ('e', 'edit', None, _('invoke editor on commit messages')),
1613 ('e', 'edit', None, _('invoke editor on commit messages')),
1614 ('i', 'interactive', None, _('use interactive mode')),
1614 ('i', 'interactive', None, _('use interactive mode')),
1615 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1615 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1616 _('[OPTION]... [FILE]...'),
1616 _('[OPTION]... [FILE]...'),
1617 inferrepo=True)
1617 inferrepo=True)
1618 def commit(ui, repo, *pats, **opts):
1618 def commit(ui, repo, *pats, **opts):
1619 """commit the specified files or all outstanding changes
1619 """commit the specified files or all outstanding changes
1620
1620
1621 Commit changes to the given files into the repository. Unlike a
1621 Commit changes to the given files into the repository. Unlike a
1622 centralized SCM, this operation is a local operation. See
1622 centralized SCM, this operation is a local operation. See
1623 :hg:`push` for a way to actively distribute your changes.
1623 :hg:`push` for a way to actively distribute your changes.
1624
1624
1625 If a list of files is omitted, all changes reported by :hg:`status`
1625 If a list of files is omitted, all changes reported by :hg:`status`
1626 will be committed.
1626 will be committed.
1627
1627
1628 If you are committing the result of a merge, do not provide any
1628 If you are committing the result of a merge, do not provide any
1629 filenames or -I/-X filters.
1629 filenames or -I/-X filters.
1630
1630
1631 If no commit message is specified, Mercurial starts your
1631 If no commit message is specified, Mercurial starts your
1632 configured editor where you can enter a message. In case your
1632 configured editor where you can enter a message. In case your
1633 commit fails, you will find a backup of your message in
1633 commit fails, you will find a backup of your message in
1634 ``.hg/last-message.txt``.
1634 ``.hg/last-message.txt``.
1635
1635
1636 The --close-branch flag can be used to mark the current branch
1636 The --close-branch flag can be used to mark the current branch
1637 head closed. When all heads of a branch are closed, the branch
1637 head closed. When all heads of a branch are closed, the branch
1638 will be considered closed and no longer listed.
1638 will be considered closed and no longer listed.
1639
1639
1640 The --amend flag can be used to amend the parent of the
1640 The --amend flag can be used to amend the parent of the
1641 working directory with a new commit that contains the changes
1641 working directory with a new commit that contains the changes
1642 in the parent in addition to those currently reported by :hg:`status`,
1642 in the parent in addition to those currently reported by :hg:`status`,
1643 if there are any. The old commit is stored in a backup bundle in
1643 if there are any. The old commit is stored in a backup bundle in
1644 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1644 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1645 on how to restore it).
1645 on how to restore it).
1646
1646
1647 Message, user and date are taken from the amended commit unless
1647 Message, user and date are taken from the amended commit unless
1648 specified. When a message isn't specified on the command line,
1648 specified. When a message isn't specified on the command line,
1649 the editor will open with the message of the amended commit.
1649 the editor will open with the message of the amended commit.
1650
1650
1651 It is not possible to amend public changesets (see :hg:`help phases`)
1651 It is not possible to amend public changesets (see :hg:`help phases`)
1652 or changesets that have children.
1652 or changesets that have children.
1653
1653
1654 See :hg:`help dates` for a list of formats valid for -d/--date.
1654 See :hg:`help dates` for a list of formats valid for -d/--date.
1655
1655
1656 Returns 0 on success, 1 if nothing changed.
1656 Returns 0 on success, 1 if nothing changed.
1657
1657
1658 .. container:: verbose
1658 .. container:: verbose
1659
1659
1660 Examples:
1660 Examples:
1661
1661
1662 - commit all files ending in .py::
1662 - commit all files ending in .py::
1663
1663
1664 hg commit --include "set:**.py"
1664 hg commit --include "set:**.py"
1665
1665
1666 - commit all non-binary files::
1666 - commit all non-binary files::
1667
1667
1668 hg commit --exclude "set:binary()"
1668 hg commit --exclude "set:binary()"
1669
1669
1670 - amend the current commit and set the date to now::
1670 - amend the current commit and set the date to now::
1671
1671
1672 hg commit --amend --date now
1672 hg commit --amend --date now
1673 """
1673 """
1674 wlock = lock = None
1674 wlock = lock = None
1675 try:
1675 try:
1676 wlock = repo.wlock()
1676 wlock = repo.wlock()
1677 lock = repo.lock()
1677 lock = repo.lock()
1678 return _docommit(ui, repo, *pats, **opts)
1678 return _docommit(ui, repo, *pats, **opts)
1679 finally:
1679 finally:
1680 release(lock, wlock)
1680 release(lock, wlock)
1681
1681
1682 def _docommit(ui, repo, *pats, **opts):
1682 def _docommit(ui, repo, *pats, **opts):
1683 if opts.get('interactive'):
1683 if opts.get('interactive'):
1684 opts.pop('interactive')
1684 opts.pop('interactive')
1685 cmdutil.dorecord(ui, repo, commit, None, False,
1685 cmdutil.dorecord(ui, repo, commit, None, False,
1686 cmdutil.recordfilter, *pats, **opts)
1686 cmdutil.recordfilter, *pats, **opts)
1687 return
1687 return
1688
1688
1689 if opts.get('subrepos'):
1689 if opts.get('subrepos'):
1690 if opts.get('amend'):
1690 if opts.get('amend'):
1691 raise error.Abort(_('cannot amend with --subrepos'))
1691 raise error.Abort(_('cannot amend with --subrepos'))
1692 # Let --subrepos on the command line override config setting.
1692 # Let --subrepos on the command line override config setting.
1693 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1693 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1694
1694
1695 cmdutil.checkunfinished(repo, commit=True)
1695 cmdutil.checkunfinished(repo, commit=True)
1696
1696
1697 branch = repo[None].branch()
1697 branch = repo[None].branch()
1698 bheads = repo.branchheads(branch)
1698 bheads = repo.branchheads(branch)
1699
1699
1700 extra = {}
1700 extra = {}
1701 if opts.get('close_branch'):
1701 if opts.get('close_branch'):
1702 extra['close'] = 1
1702 extra['close'] = 1
1703
1703
1704 if not bheads:
1704 if not bheads:
1705 raise error.Abort(_('can only close branch heads'))
1705 raise error.Abort(_('can only close branch heads'))
1706 elif opts.get('amend'):
1706 elif opts.get('amend'):
1707 if repo[None].parents()[0].p1().branch() != branch and \
1707 if repo[None].parents()[0].p1().branch() != branch and \
1708 repo[None].parents()[0].p2().branch() != branch:
1708 repo[None].parents()[0].p2().branch() != branch:
1709 raise error.Abort(_('can only close branch heads'))
1709 raise error.Abort(_('can only close branch heads'))
1710
1710
1711 if opts.get('amend'):
1711 if opts.get('amend'):
1712 if ui.configbool('ui', 'commitsubrepos'):
1712 if ui.configbool('ui', 'commitsubrepos'):
1713 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1713 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1714
1714
1715 old = repo['.']
1715 old = repo['.']
1716 if not old.mutable():
1716 if not old.mutable():
1717 raise error.Abort(_('cannot amend public changesets'))
1717 raise error.Abort(_('cannot amend public changesets'))
1718 if len(repo[None].parents()) > 1:
1718 if len(repo[None].parents()) > 1:
1719 raise error.Abort(_('cannot amend while merging'))
1719 raise error.Abort(_('cannot amend while merging'))
1720 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1720 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1721 if not allowunstable and old.children():
1721 if not allowunstable and old.children():
1722 raise error.Abort(_('cannot amend changeset with children'))
1722 raise error.Abort(_('cannot amend changeset with children'))
1723
1723
1724 # Currently histedit gets confused if an amend happens while histedit
1724 # Currently histedit gets confused if an amend happens while histedit
1725 # is in progress. Since we have a checkunfinished command, we are
1725 # is in progress. Since we have a checkunfinished command, we are
1726 # temporarily honoring it.
1726 # temporarily honoring it.
1727 #
1727 #
1728 # Note: eventually this guard will be removed. Please do not expect
1728 # Note: eventually this guard will be removed. Please do not expect
1729 # this behavior to remain.
1729 # this behavior to remain.
1730 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1730 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1731 cmdutil.checkunfinished(repo)
1731 cmdutil.checkunfinished(repo)
1732
1732
1733 # commitfunc is used only for temporary amend commit by cmdutil.amend
1733 # commitfunc is used only for temporary amend commit by cmdutil.amend
1734 def commitfunc(ui, repo, message, match, opts):
1734 def commitfunc(ui, repo, message, match, opts):
1735 return repo.commit(message,
1735 return repo.commit(message,
1736 opts.get('user') or old.user(),
1736 opts.get('user') or old.user(),
1737 opts.get('date') or old.date(),
1737 opts.get('date') or old.date(),
1738 match,
1738 match,
1739 extra=extra)
1739 extra=extra)
1740
1740
1741 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1741 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1742 if node == old.node():
1742 if node == old.node():
1743 ui.status(_("nothing changed\n"))
1743 ui.status(_("nothing changed\n"))
1744 return 1
1744 return 1
1745 else:
1745 else:
1746 def commitfunc(ui, repo, message, match, opts):
1746 def commitfunc(ui, repo, message, match, opts):
1747 backup = ui.backupconfig('phases', 'new-commit')
1747 backup = ui.backupconfig('phases', 'new-commit')
1748 baseui = repo.baseui
1748 baseui = repo.baseui
1749 basebackup = baseui.backupconfig('phases', 'new-commit')
1749 basebackup = baseui.backupconfig('phases', 'new-commit')
1750 try:
1750 try:
1751 if opts.get('secret'):
1751 if opts.get('secret'):
1752 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1752 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1753 # Propagate to subrepos
1753 # Propagate to subrepos
1754 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1754 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1755
1755
1756 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1756 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1757 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1757 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1758 return repo.commit(message, opts.get('user'), opts.get('date'),
1758 return repo.commit(message, opts.get('user'), opts.get('date'),
1759 match,
1759 match,
1760 editor=editor,
1760 editor=editor,
1761 extra=extra)
1761 extra=extra)
1762 finally:
1762 finally:
1763 ui.restoreconfig(backup)
1763 ui.restoreconfig(backup)
1764 repo.baseui.restoreconfig(basebackup)
1764 repo.baseui.restoreconfig(basebackup)
1765
1765
1766
1766
1767 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1767 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1768
1768
1769 if not node:
1769 if not node:
1770 stat = cmdutil.postcommitstatus(repo, pats, opts)
1770 stat = cmdutil.postcommitstatus(repo, pats, opts)
1771 if stat[3]:
1771 if stat[3]:
1772 ui.status(_("nothing changed (%d missing files, see "
1772 ui.status(_("nothing changed (%d missing files, see "
1773 "'hg status')\n") % len(stat[3]))
1773 "'hg status')\n") % len(stat[3]))
1774 else:
1774 else:
1775 ui.status(_("nothing changed\n"))
1775 ui.status(_("nothing changed\n"))
1776 return 1
1776 return 1
1777
1777
1778 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1778 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1779
1779
1780 @command('config|showconfig|debugconfig',
1780 @command('config|showconfig|debugconfig',
1781 [('u', 'untrusted', None, _('show untrusted configuration options')),
1781 [('u', 'untrusted', None, _('show untrusted configuration options')),
1782 ('e', 'edit', None, _('edit user config')),
1782 ('e', 'edit', None, _('edit user config')),
1783 ('l', 'local', None, _('edit repository config')),
1783 ('l', 'local', None, _('edit repository config')),
1784 ('g', 'global', None, _('edit global config'))],
1784 ('g', 'global', None, _('edit global config'))],
1785 _('[-u] [NAME]...'),
1785 _('[-u] [NAME]...'),
1786 optionalrepo=True)
1786 optionalrepo=True)
1787 def config(ui, repo, *values, **opts):
1787 def config(ui, repo, *values, **opts):
1788 """show combined config settings from all hgrc files
1788 """show combined config settings from all hgrc files
1789
1789
1790 With no arguments, print names and values of all config items.
1790 With no arguments, print names and values of all config items.
1791
1791
1792 With one argument of the form section.name, print just the value
1792 With one argument of the form section.name, print just the value
1793 of that config item.
1793 of that config item.
1794
1794
1795 With multiple arguments, print names and values of all config
1795 With multiple arguments, print names and values of all config
1796 items with matching section names.
1796 items with matching section names.
1797
1797
1798 With --edit, start an editor on the user-level config file. With
1798 With --edit, start an editor on the user-level config file. With
1799 --global, edit the system-wide config file. With --local, edit the
1799 --global, edit the system-wide config file. With --local, edit the
1800 repository-level config file.
1800 repository-level config file.
1801
1801
1802 With --debug, the source (filename and line number) is printed
1802 With --debug, the source (filename and line number) is printed
1803 for each config item.
1803 for each config item.
1804
1804
1805 See :hg:`help config` for more information about config files.
1805 See :hg:`help config` for more information about config files.
1806
1806
1807 Returns 0 on success, 1 if NAME does not exist.
1807 Returns 0 on success, 1 if NAME does not exist.
1808
1808
1809 """
1809 """
1810
1810
1811 if opts.get('edit') or opts.get('local') or opts.get('global'):
1811 if opts.get('edit') or opts.get('local') or opts.get('global'):
1812 if opts.get('local') and opts.get('global'):
1812 if opts.get('local') and opts.get('global'):
1813 raise error.Abort(_("can't use --local and --global together"))
1813 raise error.Abort(_("can't use --local and --global together"))
1814
1814
1815 if opts.get('local'):
1815 if opts.get('local'):
1816 if not repo:
1816 if not repo:
1817 raise error.Abort(_("can't use --local outside a repository"))
1817 raise error.Abort(_("can't use --local outside a repository"))
1818 paths = [repo.join('hgrc')]
1818 paths = [repo.join('hgrc')]
1819 elif opts.get('global'):
1819 elif opts.get('global'):
1820 paths = scmutil.systemrcpath()
1820 paths = scmutil.systemrcpath()
1821 else:
1821 else:
1822 paths = scmutil.userrcpath()
1822 paths = scmutil.userrcpath()
1823
1823
1824 for f in paths:
1824 for f in paths:
1825 if os.path.exists(f):
1825 if os.path.exists(f):
1826 break
1826 break
1827 else:
1827 else:
1828 if opts.get('global'):
1828 if opts.get('global'):
1829 samplehgrc = uimod.samplehgrcs['global']
1829 samplehgrc = uimod.samplehgrcs['global']
1830 elif opts.get('local'):
1830 elif opts.get('local'):
1831 samplehgrc = uimod.samplehgrcs['local']
1831 samplehgrc = uimod.samplehgrcs['local']
1832 else:
1832 else:
1833 samplehgrc = uimod.samplehgrcs['user']
1833 samplehgrc = uimod.samplehgrcs['user']
1834
1834
1835 f = paths[0]
1835 f = paths[0]
1836 fp = open(f, "w")
1836 fp = open(f, "w")
1837 fp.write(samplehgrc)
1837 fp.write(samplehgrc)
1838 fp.close()
1838 fp.close()
1839
1839
1840 editor = ui.geteditor()
1840 editor = ui.geteditor()
1841 ui.system("%s \"%s\"" % (editor, f),
1841 ui.system("%s \"%s\"" % (editor, f),
1842 onerr=error.Abort, errprefix=_("edit failed"))
1842 onerr=error.Abort, errprefix=_("edit failed"))
1843 return
1843 return
1844
1844
1845 for f in scmutil.rcpath():
1845 for f in scmutil.rcpath():
1846 ui.debug('read config from: %s\n' % f)
1846 ui.debug('read config from: %s\n' % f)
1847 untrusted = bool(opts.get('untrusted'))
1847 untrusted = bool(opts.get('untrusted'))
1848 if values:
1848 if values:
1849 sections = [v for v in values if '.' not in v]
1849 sections = [v for v in values if '.' not in v]
1850 items = [v for v in values if '.' in v]
1850 items = [v for v in values if '.' in v]
1851 if len(items) > 1 or items and sections:
1851 if len(items) > 1 or items and sections:
1852 raise error.Abort(_('only one config item permitted'))
1852 raise error.Abort(_('only one config item permitted'))
1853 matched = False
1853 matched = False
1854 for section, name, value in ui.walkconfig(untrusted=untrusted):
1854 for section, name, value in ui.walkconfig(untrusted=untrusted):
1855 value = str(value).replace('\n', '\\n')
1855 value = str(value).replace('\n', '\\n')
1856 sectname = section + '.' + name
1856 sectname = section + '.' + name
1857 if values:
1857 if values:
1858 for v in values:
1858 for v in values:
1859 if v == section:
1859 if v == section:
1860 ui.debug('%s: ' %
1860 ui.debug('%s: ' %
1861 ui.configsource(section, name, untrusted))
1861 ui.configsource(section, name, untrusted))
1862 ui.write('%s=%s\n' % (sectname, value))
1862 ui.write('%s=%s\n' % (sectname, value))
1863 matched = True
1863 matched = True
1864 elif v == sectname:
1864 elif v == sectname:
1865 ui.debug('%s: ' %
1865 ui.debug('%s: ' %
1866 ui.configsource(section, name, untrusted))
1866 ui.configsource(section, name, untrusted))
1867 ui.write(value, '\n')
1867 ui.write(value, '\n')
1868 matched = True
1868 matched = True
1869 else:
1869 else:
1870 ui.debug('%s: ' %
1870 ui.debug('%s: ' %
1871 ui.configsource(section, name, untrusted))
1871 ui.configsource(section, name, untrusted))
1872 ui.write('%s=%s\n' % (sectname, value))
1872 ui.write('%s=%s\n' % (sectname, value))
1873 matched = True
1873 matched = True
1874 if matched:
1874 if matched:
1875 return 0
1875 return 0
1876 return 1
1876 return 1
1877
1877
1878 @command('copy|cp',
1878 @command('copy|cp',
1879 [('A', 'after', None, _('record a copy that has already occurred')),
1879 [('A', 'after', None, _('record a copy that has already occurred')),
1880 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1880 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1881 ] + walkopts + dryrunopts,
1881 ] + walkopts + dryrunopts,
1882 _('[OPTION]... [SOURCE]... DEST'))
1882 _('[OPTION]... [SOURCE]... DEST'))
1883 def copy(ui, repo, *pats, **opts):
1883 def copy(ui, repo, *pats, **opts):
1884 """mark files as copied for the next commit
1884 """mark files as copied for the next commit
1885
1885
1886 Mark dest as having copies of source files. If dest is a
1886 Mark dest as having copies of source files. If dest is a
1887 directory, copies are put in that directory. If dest is a file,
1887 directory, copies are put in that directory. If dest is a file,
1888 the source must be a single file.
1888 the source must be a single file.
1889
1889
1890 By default, this command copies the contents of files as they
1890 By default, this command copies the contents of files as they
1891 exist in the working directory. If invoked with -A/--after, the
1891 exist in the working directory. If invoked with -A/--after, the
1892 operation is recorded, but no copying is performed.
1892 operation is recorded, but no copying is performed.
1893
1893
1894 This command takes effect with the next commit. To undo a copy
1894 This command takes effect with the next commit. To undo a copy
1895 before that, see :hg:`revert`.
1895 before that, see :hg:`revert`.
1896
1896
1897 Returns 0 on success, 1 if errors are encountered.
1897 Returns 0 on success, 1 if errors are encountered.
1898 """
1898 """
1899 with repo.wlock(False):
1899 with repo.wlock(False):
1900 return cmdutil.copy(ui, repo, pats, opts)
1900 return cmdutil.copy(ui, repo, pats, opts)
1901
1901
1902 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1902 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1903 def debugancestor(ui, repo, *args):
1903 def debugancestor(ui, repo, *args):
1904 """find the ancestor revision of two revisions in a given index"""
1904 """find the ancestor revision of two revisions in a given index"""
1905 if len(args) == 3:
1905 if len(args) == 3:
1906 index, rev1, rev2 = args
1906 index, rev1, rev2 = args
1907 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1907 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1908 lookup = r.lookup
1908 lookup = r.lookup
1909 elif len(args) == 2:
1909 elif len(args) == 2:
1910 if not repo:
1910 if not repo:
1911 raise error.Abort(_("there is no Mercurial repository here "
1911 raise error.Abort(_("there is no Mercurial repository here "
1912 "(.hg not found)"))
1912 "(.hg not found)"))
1913 rev1, rev2 = args
1913 rev1, rev2 = args
1914 r = repo.changelog
1914 r = repo.changelog
1915 lookup = repo.lookup
1915 lookup = repo.lookup
1916 else:
1916 else:
1917 raise error.Abort(_('either two or three arguments required'))
1917 raise error.Abort(_('either two or three arguments required'))
1918 a = r.ancestor(lookup(rev1), lookup(rev2))
1918 a = r.ancestor(lookup(rev1), lookup(rev2))
1919 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1919 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1920
1920
1921 @command('debugbuilddag',
1921 @command('debugbuilddag',
1922 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1922 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1923 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1923 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1924 ('n', 'new-file', None, _('add new file at each rev'))],
1924 ('n', 'new-file', None, _('add new file at each rev'))],
1925 _('[OPTION]... [TEXT]'))
1925 _('[OPTION]... [TEXT]'))
1926 def debugbuilddag(ui, repo, text=None,
1926 def debugbuilddag(ui, repo, text=None,
1927 mergeable_file=False,
1927 mergeable_file=False,
1928 overwritten_file=False,
1928 overwritten_file=False,
1929 new_file=False):
1929 new_file=False):
1930 """builds a repo with a given DAG from scratch in the current empty repo
1930 """builds a repo with a given DAG from scratch in the current empty repo
1931
1931
1932 The description of the DAG is read from stdin if not given on the
1932 The description of the DAG is read from stdin if not given on the
1933 command line.
1933 command line.
1934
1934
1935 Elements:
1935 Elements:
1936
1936
1937 - "+n" is a linear run of n nodes based on the current default parent
1937 - "+n" is a linear run of n nodes based on the current default parent
1938 - "." is a single node based on the current default parent
1938 - "." is a single node based on the current default parent
1939 - "$" resets the default parent to null (implied at the start);
1939 - "$" resets the default parent to null (implied at the start);
1940 otherwise the default parent is always the last node created
1940 otherwise the default parent is always the last node created
1941 - "<p" sets the default parent to the backref p
1941 - "<p" sets the default parent to the backref p
1942 - "*p" is a fork at parent p, which is a backref
1942 - "*p" is a fork at parent p, which is a backref
1943 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1943 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1944 - "/p2" is a merge of the preceding node and p2
1944 - "/p2" is a merge of the preceding node and p2
1945 - ":tag" defines a local tag for the preceding node
1945 - ":tag" defines a local tag for the preceding node
1946 - "@branch" sets the named branch for subsequent nodes
1946 - "@branch" sets the named branch for subsequent nodes
1947 - "#...\\n" is a comment up to the end of the line
1947 - "#...\\n" is a comment up to the end of the line
1948
1948
1949 Whitespace between the above elements is ignored.
1949 Whitespace between the above elements is ignored.
1950
1950
1951 A backref is either
1951 A backref is either
1952
1952
1953 - a number n, which references the node curr-n, where curr is the current
1953 - a number n, which references the node curr-n, where curr is the current
1954 node, or
1954 node, or
1955 - the name of a local tag you placed earlier using ":tag", or
1955 - the name of a local tag you placed earlier using ":tag", or
1956 - empty to denote the default parent.
1956 - empty to denote the default parent.
1957
1957
1958 All string valued-elements are either strictly alphanumeric, or must
1958 All string valued-elements are either strictly alphanumeric, or must
1959 be enclosed in double quotes ("..."), with "\\" as escape character.
1959 be enclosed in double quotes ("..."), with "\\" as escape character.
1960 """
1960 """
1961
1961
1962 if text is None:
1962 if text is None:
1963 ui.status(_("reading DAG from stdin\n"))
1963 ui.status(_("reading DAG from stdin\n"))
1964 text = ui.fin.read()
1964 text = ui.fin.read()
1965
1965
1966 cl = repo.changelog
1966 cl = repo.changelog
1967 if len(cl) > 0:
1967 if len(cl) > 0:
1968 raise error.Abort(_('repository is not empty'))
1968 raise error.Abort(_('repository is not empty'))
1969
1969
1970 # determine number of revs in DAG
1970 # determine number of revs in DAG
1971 total = 0
1971 total = 0
1972 for type, data in dagparser.parsedag(text):
1972 for type, data in dagparser.parsedag(text):
1973 if type == 'n':
1973 if type == 'n':
1974 total += 1
1974 total += 1
1975
1975
1976 if mergeable_file:
1976 if mergeable_file:
1977 linesperrev = 2
1977 linesperrev = 2
1978 # make a file with k lines per rev
1978 # make a file with k lines per rev
1979 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1979 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1980 initialmergedlines.append("")
1980 initialmergedlines.append("")
1981
1981
1982 tags = []
1982 tags = []
1983
1983
1984 lock = tr = None
1984 lock = tr = None
1985 try:
1985 try:
1986 lock = repo.lock()
1986 lock = repo.lock()
1987 tr = repo.transaction("builddag")
1987 tr = repo.transaction("builddag")
1988
1988
1989 at = -1
1989 at = -1
1990 atbranch = 'default'
1990 atbranch = 'default'
1991 nodeids = []
1991 nodeids = []
1992 id = 0
1992 id = 0
1993 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1993 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1994 for type, data in dagparser.parsedag(text):
1994 for type, data in dagparser.parsedag(text):
1995 if type == 'n':
1995 if type == 'n':
1996 ui.note(('node %s\n' % str(data)))
1996 ui.note(('node %s\n' % str(data)))
1997 id, ps = data
1997 id, ps = data
1998
1998
1999 files = []
1999 files = []
2000 fctxs = {}
2000 fctxs = {}
2001
2001
2002 p2 = None
2002 p2 = None
2003 if mergeable_file:
2003 if mergeable_file:
2004 fn = "mf"
2004 fn = "mf"
2005 p1 = repo[ps[0]]
2005 p1 = repo[ps[0]]
2006 if len(ps) > 1:
2006 if len(ps) > 1:
2007 p2 = repo[ps[1]]
2007 p2 = repo[ps[1]]
2008 pa = p1.ancestor(p2)
2008 pa = p1.ancestor(p2)
2009 base, local, other = [x[fn].data() for x in (pa, p1,
2009 base, local, other = [x[fn].data() for x in (pa, p1,
2010 p2)]
2010 p2)]
2011 m3 = simplemerge.Merge3Text(base, local, other)
2011 m3 = simplemerge.Merge3Text(base, local, other)
2012 ml = [l.strip() for l in m3.merge_lines()]
2012 ml = [l.strip() for l in m3.merge_lines()]
2013 ml.append("")
2013 ml.append("")
2014 elif at > 0:
2014 elif at > 0:
2015 ml = p1[fn].data().split("\n")
2015 ml = p1[fn].data().split("\n")
2016 else:
2016 else:
2017 ml = initialmergedlines
2017 ml = initialmergedlines
2018 ml[id * linesperrev] += " r%i" % id
2018 ml[id * linesperrev] += " r%i" % id
2019 mergedtext = "\n".join(ml)
2019 mergedtext = "\n".join(ml)
2020 files.append(fn)
2020 files.append(fn)
2021 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
2021 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
2022
2022
2023 if overwritten_file:
2023 if overwritten_file:
2024 fn = "of"
2024 fn = "of"
2025 files.append(fn)
2025 files.append(fn)
2026 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
2026 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
2027
2027
2028 if new_file:
2028 if new_file:
2029 fn = "nf%i" % id
2029 fn = "nf%i" % id
2030 files.append(fn)
2030 files.append(fn)
2031 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
2031 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
2032 if len(ps) > 1:
2032 if len(ps) > 1:
2033 if not p2:
2033 if not p2:
2034 p2 = repo[ps[1]]
2034 p2 = repo[ps[1]]
2035 for fn in p2:
2035 for fn in p2:
2036 if fn.startswith("nf"):
2036 if fn.startswith("nf"):
2037 files.append(fn)
2037 files.append(fn)
2038 fctxs[fn] = p2[fn]
2038 fctxs[fn] = p2[fn]
2039
2039
2040 def fctxfn(repo, cx, path):
2040 def fctxfn(repo, cx, path):
2041 return fctxs.get(path)
2041 return fctxs.get(path)
2042
2042
2043 if len(ps) == 0 or ps[0] < 0:
2043 if len(ps) == 0 or ps[0] < 0:
2044 pars = [None, None]
2044 pars = [None, None]
2045 elif len(ps) == 1:
2045 elif len(ps) == 1:
2046 pars = [nodeids[ps[0]], None]
2046 pars = [nodeids[ps[0]], None]
2047 else:
2047 else:
2048 pars = [nodeids[p] for p in ps]
2048 pars = [nodeids[p] for p in ps]
2049 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
2049 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
2050 date=(id, 0),
2050 date=(id, 0),
2051 user="debugbuilddag",
2051 user="debugbuilddag",
2052 extra={'branch': atbranch})
2052 extra={'branch': atbranch})
2053 nodeid = repo.commitctx(cx)
2053 nodeid = repo.commitctx(cx)
2054 nodeids.append(nodeid)
2054 nodeids.append(nodeid)
2055 at = id
2055 at = id
2056 elif type == 'l':
2056 elif type == 'l':
2057 id, name = data
2057 id, name = data
2058 ui.note(('tag %s\n' % name))
2058 ui.note(('tag %s\n' % name))
2059 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
2059 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
2060 elif type == 'a':
2060 elif type == 'a':
2061 ui.note(('branch %s\n' % data))
2061 ui.note(('branch %s\n' % data))
2062 atbranch = data
2062 atbranch = data
2063 ui.progress(_('building'), id, unit=_('revisions'), total=total)
2063 ui.progress(_('building'), id, unit=_('revisions'), total=total)
2064 tr.close()
2064 tr.close()
2065
2065
2066 if tags:
2066 if tags:
2067 repo.vfs.write("localtags", "".join(tags))
2067 repo.vfs.write("localtags", "".join(tags))
2068 finally:
2068 finally:
2069 ui.progress(_('building'), None)
2069 ui.progress(_('building'), None)
2070 release(tr, lock)
2070 release(tr, lock)
2071
2071
2072 @command('debugbundle',
2072 @command('debugbundle',
2073 [('a', 'all', None, _('show all details')),
2073 [('a', 'all', None, _('show all details')),
2074 ('', 'spec', None, _('print the bundlespec of the bundle'))],
2074 ('', 'spec', None, _('print the bundlespec of the bundle'))],
2075 _('FILE'),
2075 _('FILE'),
2076 norepo=True)
2076 norepo=True)
2077 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
2077 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
2078 """lists the contents of a bundle"""
2078 """lists the contents of a bundle"""
2079 with hg.openpath(ui, bundlepath) as f:
2079 with hg.openpath(ui, bundlepath) as f:
2080 if spec:
2080 if spec:
2081 spec = exchange.getbundlespec(ui, f)
2081 spec = exchange.getbundlespec(ui, f)
2082 ui.write('%s\n' % spec)
2082 ui.write('%s\n' % spec)
2083 return
2083 return
2084
2084
2085 gen = exchange.readbundle(ui, f, bundlepath)
2085 gen = exchange.readbundle(ui, f, bundlepath)
2086 if isinstance(gen, bundle2.unbundle20):
2086 if isinstance(gen, bundle2.unbundle20):
2087 return _debugbundle2(ui, gen, all=all, **opts)
2087 return _debugbundle2(ui, gen, all=all, **opts)
2088 if all:
2088 if all:
2089 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
2089 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
2090
2090
2091 def showchunks(named):
2091 def showchunks(named):
2092 ui.write("\n%s\n" % named)
2092 ui.write("\n%s\n" % named)
2093 chain = None
2093 chain = None
2094 while True:
2094 while True:
2095 chunkdata = gen.deltachunk(chain)
2095 chunkdata = gen.deltachunk(chain)
2096 if not chunkdata:
2096 if not chunkdata:
2097 break
2097 break
2098 node = chunkdata['node']
2098 node = chunkdata['node']
2099 p1 = chunkdata['p1']
2099 p1 = chunkdata['p1']
2100 p2 = chunkdata['p2']
2100 p2 = chunkdata['p2']
2101 cs = chunkdata['cs']
2101 cs = chunkdata['cs']
2102 deltabase = chunkdata['deltabase']
2102 deltabase = chunkdata['deltabase']
2103 delta = chunkdata['delta']
2103 delta = chunkdata['delta']
2104 ui.write("%s %s %s %s %s %s\n" %
2104 ui.write("%s %s %s %s %s %s\n" %
2105 (hex(node), hex(p1), hex(p2),
2105 (hex(node), hex(p1), hex(p2),
2106 hex(cs), hex(deltabase), len(delta)))
2106 hex(cs), hex(deltabase), len(delta)))
2107 chain = node
2107 chain = node
2108
2108
2109 chunkdata = gen.changelogheader()
2109 chunkdata = gen.changelogheader()
2110 showchunks("changelog")
2110 showchunks("changelog")
2111 chunkdata = gen.manifestheader()
2111 chunkdata = gen.manifestheader()
2112 showchunks("manifest")
2112 showchunks("manifest")
2113 while True:
2113 while True:
2114 chunkdata = gen.filelogheader()
2114 chunkdata = gen.filelogheader()
2115 if not chunkdata:
2115 if not chunkdata:
2116 break
2116 break
2117 fname = chunkdata['filename']
2117 fname = chunkdata['filename']
2118 showchunks(fname)
2118 showchunks(fname)
2119 else:
2119 else:
2120 if isinstance(gen, bundle2.unbundle20):
2120 if isinstance(gen, bundle2.unbundle20):
2121 raise error.Abort(_('use debugbundle2 for this file'))
2121 raise error.Abort(_('use debugbundle2 for this file'))
2122 chunkdata = gen.changelogheader()
2122 chunkdata = gen.changelogheader()
2123 chain = None
2123 chain = None
2124 while True:
2124 while True:
2125 chunkdata = gen.deltachunk(chain)
2125 chunkdata = gen.deltachunk(chain)
2126 if not chunkdata:
2126 if not chunkdata:
2127 break
2127 break
2128 node = chunkdata['node']
2128 node = chunkdata['node']
2129 ui.write("%s\n" % hex(node))
2129 ui.write("%s\n" % hex(node))
2130 chain = node
2130 chain = node
2131
2131
2132 def _debugbundle2(ui, gen, **opts):
2132 def _debugbundle2(ui, gen, **opts):
2133 """lists the contents of a bundle2"""
2133 """lists the contents of a bundle2"""
2134 if not isinstance(gen, bundle2.unbundle20):
2134 if not isinstance(gen, bundle2.unbundle20):
2135 raise error.Abort(_('not a bundle2 file'))
2135 raise error.Abort(_('not a bundle2 file'))
2136 ui.write(('Stream params: %s\n' % repr(gen.params)))
2136 ui.write(('Stream params: %s\n' % repr(gen.params)))
2137 for part in gen.iterparts():
2137 for part in gen.iterparts():
2138 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
2138 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
2139 if part.type == 'changegroup':
2139 if part.type == 'changegroup':
2140 version = part.params.get('version', '01')
2140 version = part.params.get('version', '01')
2141 cg = changegroup.getunbundler(version, part, 'UN')
2141 cg = changegroup.getunbundler(version, part, 'UN')
2142 chunkdata = cg.changelogheader()
2142 chunkdata = cg.changelogheader()
2143 chain = None
2143 chain = None
2144 while True:
2144 while True:
2145 chunkdata = cg.deltachunk(chain)
2145 chunkdata = cg.deltachunk(chain)
2146 if not chunkdata:
2146 if not chunkdata:
2147 break
2147 break
2148 node = chunkdata['node']
2148 node = chunkdata['node']
2149 ui.write(" %s\n" % hex(node))
2149 ui.write(" %s\n" % hex(node))
2150 chain = node
2150 chain = node
2151
2151
2152 @command('debugcreatestreamclonebundle', [], 'FILE')
2152 @command('debugcreatestreamclonebundle', [], 'FILE')
2153 def debugcreatestreamclonebundle(ui, repo, fname):
2153 def debugcreatestreamclonebundle(ui, repo, fname):
2154 """create a stream clone bundle file
2154 """create a stream clone bundle file
2155
2155
2156 Stream bundles are special bundles that are essentially archives of
2156 Stream bundles are special bundles that are essentially archives of
2157 revlog files. They are commonly used for cloning very quickly.
2157 revlog files. They are commonly used for cloning very quickly.
2158 """
2158 """
2159 requirements, gen = streamclone.generatebundlev1(repo)
2159 requirements, gen = streamclone.generatebundlev1(repo)
2160 changegroup.writechunks(ui, gen, fname)
2160 changegroup.writechunks(ui, gen, fname)
2161
2161
2162 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
2162 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
2163
2163
2164 @command('debugapplystreamclonebundle', [], 'FILE')
2164 @command('debugapplystreamclonebundle', [], 'FILE')
2165 def debugapplystreamclonebundle(ui, repo, fname):
2165 def debugapplystreamclonebundle(ui, repo, fname):
2166 """apply a stream clone bundle file"""
2166 """apply a stream clone bundle file"""
2167 f = hg.openpath(ui, fname)
2167 f = hg.openpath(ui, fname)
2168 gen = exchange.readbundle(ui, f, fname)
2168 gen = exchange.readbundle(ui, f, fname)
2169 gen.apply(repo)
2169 gen.apply(repo)
2170
2170
2171 @command('debugcheckstate', [], '')
2171 @command('debugcheckstate', [], '')
2172 def debugcheckstate(ui, repo):
2172 def debugcheckstate(ui, repo):
2173 """validate the correctness of the current dirstate"""
2173 """validate the correctness of the current dirstate"""
2174 parent1, parent2 = repo.dirstate.parents()
2174 parent1, parent2 = repo.dirstate.parents()
2175 m1 = repo[parent1].manifest()
2175 m1 = repo[parent1].manifest()
2176 m2 = repo[parent2].manifest()
2176 m2 = repo[parent2].manifest()
2177 errors = 0
2177 errors = 0
2178 for f in repo.dirstate:
2178 for f in repo.dirstate:
2179 state = repo.dirstate[f]
2179 state = repo.dirstate[f]
2180 if state in "nr" and f not in m1:
2180 if state in "nr" and f not in m1:
2181 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
2181 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
2182 errors += 1
2182 errors += 1
2183 if state in "a" and f in m1:
2183 if state in "a" and f in m1:
2184 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
2184 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
2185 errors += 1
2185 errors += 1
2186 if state in "m" and f not in m1 and f not in m2:
2186 if state in "m" and f not in m1 and f not in m2:
2187 ui.warn(_("%s in state %s, but not in either manifest\n") %
2187 ui.warn(_("%s in state %s, but not in either manifest\n") %
2188 (f, state))
2188 (f, state))
2189 errors += 1
2189 errors += 1
2190 for f in m1:
2190 for f in m1:
2191 state = repo.dirstate[f]
2191 state = repo.dirstate[f]
2192 if state not in "nrm":
2192 if state not in "nrm":
2193 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
2193 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
2194 errors += 1
2194 errors += 1
2195 if errors:
2195 if errors:
2196 error = _(".hg/dirstate inconsistent with current parent's manifest")
2196 error = _(".hg/dirstate inconsistent with current parent's manifest")
2197 raise error.Abort(error)
2197 raise error.Abort(error)
2198
2198
2199 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
2199 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
2200 def debugcommands(ui, cmd='', *args):
2200 def debugcommands(ui, cmd='', *args):
2201 """list all available commands and options"""
2201 """list all available commands and options"""
2202 for cmd, vals in sorted(table.iteritems()):
2202 for cmd, vals in sorted(table.iteritems()):
2203 cmd = cmd.split('|')[0].strip('^')
2203 cmd = cmd.split('|')[0].strip('^')
2204 opts = ', '.join([i[1] for i in vals[1]])
2204 opts = ', '.join([i[1] for i in vals[1]])
2205 ui.write('%s: %s\n' % (cmd, opts))
2205 ui.write('%s: %s\n' % (cmd, opts))
2206
2206
2207 @command('debugcomplete',
2207 @command('debugcomplete',
2208 [('o', 'options', None, _('show the command options'))],
2208 [('o', 'options', None, _('show the command options'))],
2209 _('[-o] CMD'),
2209 _('[-o] CMD'),
2210 norepo=True)
2210 norepo=True)
2211 def debugcomplete(ui, cmd='', **opts):
2211 def debugcomplete(ui, cmd='', **opts):
2212 """returns the completion list associated with the given command"""
2212 """returns the completion list associated with the given command"""
2213
2213
2214 if opts.get('options'):
2214 if opts.get('options'):
2215 options = []
2215 options = []
2216 otables = [globalopts]
2216 otables = [globalopts]
2217 if cmd:
2217 if cmd:
2218 aliases, entry = cmdutil.findcmd(cmd, table, False)
2218 aliases, entry = cmdutil.findcmd(cmd, table, False)
2219 otables.append(entry[1])
2219 otables.append(entry[1])
2220 for t in otables:
2220 for t in otables:
2221 for o in t:
2221 for o in t:
2222 if "(DEPRECATED)" in o[3]:
2222 if "(DEPRECATED)" in o[3]:
2223 continue
2223 continue
2224 if o[0]:
2224 if o[0]:
2225 options.append('-%s' % o[0])
2225 options.append('-%s' % o[0])
2226 options.append('--%s' % o[1])
2226 options.append('--%s' % o[1])
2227 ui.write("%s\n" % "\n".join(options))
2227 ui.write("%s\n" % "\n".join(options))
2228 return
2228 return
2229
2229
2230 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2230 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2231 if ui.verbose:
2231 if ui.verbose:
2232 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
2232 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
2233 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
2233 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
2234
2234
2235 @command('debugdag',
2235 @command('debugdag',
2236 [('t', 'tags', None, _('use tags as labels')),
2236 [('t', 'tags', None, _('use tags as labels')),
2237 ('b', 'branches', None, _('annotate with branch names')),
2237 ('b', 'branches', None, _('annotate with branch names')),
2238 ('', 'dots', None, _('use dots for runs')),
2238 ('', 'dots', None, _('use dots for runs')),
2239 ('s', 'spaces', None, _('separate elements by spaces'))],
2239 ('s', 'spaces', None, _('separate elements by spaces'))],
2240 _('[OPTION]... [FILE [REV]...]'),
2240 _('[OPTION]... [FILE [REV]...]'),
2241 optionalrepo=True)
2241 optionalrepo=True)
2242 def debugdag(ui, repo, file_=None, *revs, **opts):
2242 def debugdag(ui, repo, file_=None, *revs, **opts):
2243 """format the changelog or an index DAG as a concise textual description
2243 """format the changelog or an index DAG as a concise textual description
2244
2244
2245 If you pass a revlog index, the revlog's DAG is emitted. If you list
2245 If you pass a revlog index, the revlog's DAG is emitted. If you list
2246 revision numbers, they get labeled in the output as rN.
2246 revision numbers, they get labeled in the output as rN.
2247
2247
2248 Otherwise, the changelog DAG of the current repo is emitted.
2248 Otherwise, the changelog DAG of the current repo is emitted.
2249 """
2249 """
2250 spaces = opts.get('spaces')
2250 spaces = opts.get('spaces')
2251 dots = opts.get('dots')
2251 dots = opts.get('dots')
2252 if file_:
2252 if file_:
2253 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2253 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2254 revs = set((int(r) for r in revs))
2254 revs = set((int(r) for r in revs))
2255 def events():
2255 def events():
2256 for r in rlog:
2256 for r in rlog:
2257 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2257 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2258 if p != -1))
2258 if p != -1))
2259 if r in revs:
2259 if r in revs:
2260 yield 'l', (r, "r%i" % r)
2260 yield 'l', (r, "r%i" % r)
2261 elif repo:
2261 elif repo:
2262 cl = repo.changelog
2262 cl = repo.changelog
2263 tags = opts.get('tags')
2263 tags = opts.get('tags')
2264 branches = opts.get('branches')
2264 branches = opts.get('branches')
2265 if tags:
2265 if tags:
2266 labels = {}
2266 labels = {}
2267 for l, n in repo.tags().items():
2267 for l, n in repo.tags().items():
2268 labels.setdefault(cl.rev(n), []).append(l)
2268 labels.setdefault(cl.rev(n), []).append(l)
2269 def events():
2269 def events():
2270 b = "default"
2270 b = "default"
2271 for r in cl:
2271 for r in cl:
2272 if branches:
2272 if branches:
2273 newb = cl.read(cl.node(r))[5]['branch']
2273 newb = cl.read(cl.node(r))[5]['branch']
2274 if newb != b:
2274 if newb != b:
2275 yield 'a', newb
2275 yield 'a', newb
2276 b = newb
2276 b = newb
2277 yield 'n', (r, list(p for p in cl.parentrevs(r)
2277 yield 'n', (r, list(p for p in cl.parentrevs(r)
2278 if p != -1))
2278 if p != -1))
2279 if tags:
2279 if tags:
2280 ls = labels.get(r)
2280 ls = labels.get(r)
2281 if ls:
2281 if ls:
2282 for l in ls:
2282 for l in ls:
2283 yield 'l', (r, l)
2283 yield 'l', (r, l)
2284 else:
2284 else:
2285 raise error.Abort(_('need repo for changelog dag'))
2285 raise error.Abort(_('need repo for changelog dag'))
2286
2286
2287 for line in dagparser.dagtextlines(events(),
2287 for line in dagparser.dagtextlines(events(),
2288 addspaces=spaces,
2288 addspaces=spaces,
2289 wraplabels=True,
2289 wraplabels=True,
2290 wrapannotations=True,
2290 wrapannotations=True,
2291 wrapnonlinear=dots,
2291 wrapnonlinear=dots,
2292 usedots=dots,
2292 usedots=dots,
2293 maxlinewidth=70):
2293 maxlinewidth=70):
2294 ui.write(line)
2294 ui.write(line)
2295 ui.write("\n")
2295 ui.write("\n")
2296
2296
2297 @command('debugdata', debugrevlogopts, _('-c|-m|FILE REV'))
2297 @command('debugdata', debugrevlogopts, _('-c|-m|FILE REV'))
2298 def debugdata(ui, repo, file_, rev=None, **opts):
2298 def debugdata(ui, repo, file_, rev=None, **opts):
2299 """dump the contents of a data file revision"""
2299 """dump the contents of a data file revision"""
2300 if opts.get('changelog') or opts.get('manifest'):
2300 if opts.get('changelog') or opts.get('manifest'):
2301 file_, rev = None, file_
2301 file_, rev = None, file_
2302 elif rev is None:
2302 elif rev is None:
2303 raise error.CommandError('debugdata', _('invalid arguments'))
2303 raise error.CommandError('debugdata', _('invalid arguments'))
2304 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2304 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2305 try:
2305 try:
2306 ui.write(r.revision(r.lookup(rev)))
2306 ui.write(r.revision(r.lookup(rev)))
2307 except KeyError:
2307 except KeyError:
2308 raise error.Abort(_('invalid revision identifier %s') % rev)
2308 raise error.Abort(_('invalid revision identifier %s') % rev)
2309
2309
2310 @command('debugdate',
2310 @command('debugdate',
2311 [('e', 'extended', None, _('try extended date formats'))],
2311 [('e', 'extended', None, _('try extended date formats'))],
2312 _('[-e] DATE [RANGE]'),
2312 _('[-e] DATE [RANGE]'),
2313 norepo=True, optionalrepo=True)
2313 norepo=True, optionalrepo=True)
2314 def debugdate(ui, date, range=None, **opts):
2314 def debugdate(ui, date, range=None, **opts):
2315 """parse and display a date"""
2315 """parse and display a date"""
2316 if opts["extended"]:
2316 if opts["extended"]:
2317 d = util.parsedate(date, util.extendeddateformats)
2317 d = util.parsedate(date, util.extendeddateformats)
2318 else:
2318 else:
2319 d = util.parsedate(date)
2319 d = util.parsedate(date)
2320 ui.write(("internal: %s %s\n") % d)
2320 ui.write(("internal: %s %s\n") % d)
2321 ui.write(("standard: %s\n") % util.datestr(d))
2321 ui.write(("standard: %s\n") % util.datestr(d))
2322 if range:
2322 if range:
2323 m = util.matchdate(range)
2323 m = util.matchdate(range)
2324 ui.write(("match: %s\n") % m(d[0]))
2324 ui.write(("match: %s\n") % m(d[0]))
2325
2325
2326 @command('debugdiscovery',
2326 @command('debugdiscovery',
2327 [('', 'old', None, _('use old-style discovery')),
2327 [('', 'old', None, _('use old-style discovery')),
2328 ('', 'nonheads', None,
2328 ('', 'nonheads', None,
2329 _('use old-style discovery with non-heads included')),
2329 _('use old-style discovery with non-heads included')),
2330 ] + remoteopts,
2330 ] + remoteopts,
2331 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2331 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2332 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2332 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2333 """runs the changeset discovery protocol in isolation"""
2333 """runs the changeset discovery protocol in isolation"""
2334 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2334 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2335 opts.get('branch'))
2335 opts.get('branch'))
2336 remote = hg.peer(repo, opts, remoteurl)
2336 remote = hg.peer(repo, opts, remoteurl)
2337 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2337 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2338
2338
2339 # make sure tests are repeatable
2339 # make sure tests are repeatable
2340 random.seed(12323)
2340 random.seed(12323)
2341
2341
2342 def doit(localheads, remoteheads, remote=remote):
2342 def doit(localheads, remoteheads, remote=remote):
2343 if opts.get('old'):
2343 if opts.get('old'):
2344 if localheads:
2344 if localheads:
2345 raise error.Abort('cannot use localheads with old style '
2345 raise error.Abort('cannot use localheads with old style '
2346 'discovery')
2346 'discovery')
2347 if not util.safehasattr(remote, 'branches'):
2347 if not util.safehasattr(remote, 'branches'):
2348 # enable in-client legacy support
2348 # enable in-client legacy support
2349 remote = localrepo.locallegacypeer(remote.local())
2349 remote = localrepo.locallegacypeer(remote.local())
2350 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2350 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2351 force=True)
2351 force=True)
2352 common = set(common)
2352 common = set(common)
2353 if not opts.get('nonheads'):
2353 if not opts.get('nonheads'):
2354 ui.write(("unpruned common: %s\n") %
2354 ui.write(("unpruned common: %s\n") %
2355 " ".join(sorted(short(n) for n in common)))
2355 " ".join(sorted(short(n) for n in common)))
2356 dag = dagutil.revlogdag(repo.changelog)
2356 dag = dagutil.revlogdag(repo.changelog)
2357 all = dag.ancestorset(dag.internalizeall(common))
2357 all = dag.ancestorset(dag.internalizeall(common))
2358 common = dag.externalizeall(dag.headsetofconnecteds(all))
2358 common = dag.externalizeall(dag.headsetofconnecteds(all))
2359 else:
2359 else:
2360 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2360 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2361 common = set(common)
2361 common = set(common)
2362 rheads = set(hds)
2362 rheads = set(hds)
2363 lheads = set(repo.heads())
2363 lheads = set(repo.heads())
2364 ui.write(("common heads: %s\n") %
2364 ui.write(("common heads: %s\n") %
2365 " ".join(sorted(short(n) for n in common)))
2365 " ".join(sorted(short(n) for n in common)))
2366 if lheads <= common:
2366 if lheads <= common:
2367 ui.write(("local is subset\n"))
2367 ui.write(("local is subset\n"))
2368 elif rheads <= common:
2368 elif rheads <= common:
2369 ui.write(("remote is subset\n"))
2369 ui.write(("remote is subset\n"))
2370
2370
2371 serverlogs = opts.get('serverlog')
2371 serverlogs = opts.get('serverlog')
2372 if serverlogs:
2372 if serverlogs:
2373 for filename in serverlogs:
2373 for filename in serverlogs:
2374 with open(filename, 'r') as logfile:
2374 with open(filename, 'r') as logfile:
2375 line = logfile.readline()
2375 line = logfile.readline()
2376 while line:
2376 while line:
2377 parts = line.strip().split(';')
2377 parts = line.strip().split(';')
2378 op = parts[1]
2378 op = parts[1]
2379 if op == 'cg':
2379 if op == 'cg':
2380 pass
2380 pass
2381 elif op == 'cgss':
2381 elif op == 'cgss':
2382 doit(parts[2].split(' '), parts[3].split(' '))
2382 doit(parts[2].split(' '), parts[3].split(' '))
2383 elif op == 'unb':
2383 elif op == 'unb':
2384 doit(parts[3].split(' '), parts[2].split(' '))
2384 doit(parts[3].split(' '), parts[2].split(' '))
2385 line = logfile.readline()
2385 line = logfile.readline()
2386 else:
2386 else:
2387 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2387 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2388 opts.get('remote_head'))
2388 opts.get('remote_head'))
2389 localrevs = opts.get('local_head')
2389 localrevs = opts.get('local_head')
2390 doit(localrevs, remoterevs)
2390 doit(localrevs, remoterevs)
2391
2391
2392 @command('debugextensions', formatteropts, [], norepo=True)
2392 @command('debugextensions', formatteropts, [], norepo=True)
2393 def debugextensions(ui, **opts):
2393 def debugextensions(ui, **opts):
2394 '''show information about active extensions'''
2394 '''show information about active extensions'''
2395 exts = extensions.extensions(ui)
2395 exts = extensions.extensions(ui)
2396 fm = ui.formatter('debugextensions', opts)
2396 fm = ui.formatter('debugextensions', opts)
2397 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2397 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2398 extsource = extmod.__file__
2398 extsource = extmod.__file__
2399 exttestedwith = getattr(extmod, 'testedwith', None)
2399 exttestedwith = getattr(extmod, 'testedwith', None)
2400 if exttestedwith is not None:
2400 if exttestedwith is not None:
2401 exttestedwith = exttestedwith.split()
2401 exttestedwith = exttestedwith.split()
2402 extbuglink = getattr(extmod, 'buglink', None)
2402 extbuglink = getattr(extmod, 'buglink', None)
2403
2403
2404 fm.startitem()
2404 fm.startitem()
2405
2405
2406 if ui.quiet or ui.verbose:
2406 if ui.quiet or ui.verbose:
2407 fm.write('name', '%s\n', extname)
2407 fm.write('name', '%s\n', extname)
2408 else:
2408 else:
2409 fm.write('name', '%s', extname)
2409 fm.write('name', '%s', extname)
2410 if not exttestedwith:
2410 if not exttestedwith:
2411 fm.plain(_(' (untested!)\n'))
2411 fm.plain(_(' (untested!)\n'))
2412 else:
2412 else:
2413 if exttestedwith == ['internal'] or \
2413 if exttestedwith == ['internal'] or \
2414 util.version() in exttestedwith:
2414 util.version() in exttestedwith:
2415 fm.plain('\n')
2415 fm.plain('\n')
2416 else:
2416 else:
2417 lasttestedversion = exttestedwith[-1]
2417 lasttestedversion = exttestedwith[-1]
2418 fm.plain(' (%s!)\n' % lasttestedversion)
2418 fm.plain(' (%s!)\n' % lasttestedversion)
2419
2419
2420 fm.condwrite(ui.verbose and extsource, 'source',
2420 fm.condwrite(ui.verbose and extsource, 'source',
2421 _(' location: %s\n'), extsource or "")
2421 _(' location: %s\n'), extsource or "")
2422
2422
2423 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2423 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2424 _(' tested with: %s\n'), ' '.join(exttestedwith or []))
2424 _(' tested with: %s\n'), ' '.join(exttestedwith or []))
2425
2425
2426 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2426 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2427 _(' bug reporting: %s\n'), extbuglink or "")
2427 _(' bug reporting: %s\n'), extbuglink or "")
2428
2428
2429 fm.end()
2429 fm.end()
2430
2430
2431 @command('debugfileset',
2431 @command('debugfileset',
2432 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2432 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2433 _('[-r REV] FILESPEC'))
2433 _('[-r REV] FILESPEC'))
2434 def debugfileset(ui, repo, expr, **opts):
2434 def debugfileset(ui, repo, expr, **opts):
2435 '''parse and apply a fileset specification'''
2435 '''parse and apply a fileset specification'''
2436 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2436 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2437 if ui.verbose:
2437 if ui.verbose:
2438 tree = fileset.parse(expr)
2438 tree = fileset.parse(expr)
2439 ui.note(fileset.prettyformat(tree), "\n")
2439 ui.note(fileset.prettyformat(tree), "\n")
2440
2440
2441 for f in ctx.getfileset(expr):
2441 for f in ctx.getfileset(expr):
2442 ui.write("%s\n" % f)
2442 ui.write("%s\n" % f)
2443
2443
2444 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2444 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2445 def debugfsinfo(ui, path="."):
2445 def debugfsinfo(ui, path="."):
2446 """show information detected about current filesystem"""
2446 """show information detected about current filesystem"""
2447 util.writefile('.debugfsinfo', '')
2447 util.writefile('.debugfsinfo', '')
2448 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2448 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2449 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2449 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2450 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2450 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2451 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2451 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2452 and 'yes' or 'no'))
2452 and 'yes' or 'no'))
2453 os.unlink('.debugfsinfo')
2453 os.unlink('.debugfsinfo')
2454
2454
2455 @command('debuggetbundle',
2455 @command('debuggetbundle',
2456 [('H', 'head', [], _('id of head node'), _('ID')),
2456 [('H', 'head', [], _('id of head node'), _('ID')),
2457 ('C', 'common', [], _('id of common node'), _('ID')),
2457 ('C', 'common', [], _('id of common node'), _('ID')),
2458 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2458 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2459 _('REPO FILE [-H|-C ID]...'),
2459 _('REPO FILE [-H|-C ID]...'),
2460 norepo=True)
2460 norepo=True)
2461 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2461 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2462 """retrieves a bundle from a repo
2462 """retrieves a bundle from a repo
2463
2463
2464 Every ID must be a full-length hex node id string. Saves the bundle to the
2464 Every ID must be a full-length hex node id string. Saves the bundle to the
2465 given file.
2465 given file.
2466 """
2466 """
2467 repo = hg.peer(ui, opts, repopath)
2467 repo = hg.peer(ui, opts, repopath)
2468 if not repo.capable('getbundle'):
2468 if not repo.capable('getbundle'):
2469 raise error.Abort("getbundle() not supported by target repository")
2469 raise error.Abort("getbundle() not supported by target repository")
2470 args = {}
2470 args = {}
2471 if common:
2471 if common:
2472 args['common'] = [bin(s) for s in common]
2472 args['common'] = [bin(s) for s in common]
2473 if head:
2473 if head:
2474 args['heads'] = [bin(s) for s in head]
2474 args['heads'] = [bin(s) for s in head]
2475 # TODO: get desired bundlecaps from command line.
2475 # TODO: get desired bundlecaps from command line.
2476 args['bundlecaps'] = None
2476 args['bundlecaps'] = None
2477 bundle = repo.getbundle('debug', **args)
2477 bundle = repo.getbundle('debug', **args)
2478
2478
2479 bundletype = opts.get('type', 'bzip2').lower()
2479 bundletype = opts.get('type', 'bzip2').lower()
2480 btypes = {'none': 'HG10UN',
2480 btypes = {'none': 'HG10UN',
2481 'bzip2': 'HG10BZ',
2481 'bzip2': 'HG10BZ',
2482 'gzip': 'HG10GZ',
2482 'gzip': 'HG10GZ',
2483 'bundle2': 'HG20'}
2483 'bundle2': 'HG20'}
2484 bundletype = btypes.get(bundletype)
2484 bundletype = btypes.get(bundletype)
2485 if bundletype not in changegroup.bundletypes:
2485 if bundletype not in changegroup.bundletypes:
2486 raise error.Abort(_('unknown bundle type specified with --type'))
2486 raise error.Abort(_('unknown bundle type specified with --type'))
2487 changegroup.writebundle(ui, bundle, bundlepath, bundletype)
2487 changegroup.writebundle(ui, bundle, bundlepath, bundletype)
2488
2488
2489 @command('debugignore', [], '[FILE]')
2489 @command('debugignore', [], '[FILE]')
2490 def debugignore(ui, repo, *files, **opts):
2490 def debugignore(ui, repo, *files, **opts):
2491 """display the combined ignore pattern and information about ignored files
2491 """display the combined ignore pattern and information about ignored files
2492
2492
2493 With no argument display the combined ignore pattern.
2493 With no argument display the combined ignore pattern.
2494
2494
2495 Given space separated file names, shows if the given file is ignored and
2495 Given space separated file names, shows if the given file is ignored and
2496 if so, show the ignore rule (file and line number) that matched it.
2496 if so, show the ignore rule (file and line number) that matched it.
2497 """
2497 """
2498 ignore = repo.dirstate._ignore
2498 ignore = repo.dirstate._ignore
2499 if not files:
2499 if not files:
2500 # Show all the patterns
2500 # Show all the patterns
2501 includepat = getattr(ignore, 'includepat', None)
2501 includepat = getattr(ignore, 'includepat', None)
2502 if includepat is not None:
2502 if includepat is not None:
2503 ui.write("%s\n" % includepat)
2503 ui.write("%s\n" % includepat)
2504 else:
2504 else:
2505 raise error.Abort(_("no ignore patterns found"))
2505 raise error.Abort(_("no ignore patterns found"))
2506 else:
2506 else:
2507 for f in files:
2507 for f in files:
2508 nf = util.normpath(f)
2508 nf = util.normpath(f)
2509 ignored = None
2509 ignored = None
2510 ignoredata = None
2510 ignoredata = None
2511 if nf != '.':
2511 if nf != '.':
2512 if ignore(nf):
2512 if ignore(nf):
2513 ignored = nf
2513 ignored = nf
2514 ignoredata = repo.dirstate._ignorefileandline(nf)
2514 ignoredata = repo.dirstate._ignorefileandline(nf)
2515 else:
2515 else:
2516 for p in util.finddirs(nf):
2516 for p in util.finddirs(nf):
2517 if ignore(p):
2517 if ignore(p):
2518 ignored = p
2518 ignored = p
2519 ignoredata = repo.dirstate._ignorefileandline(p)
2519 ignoredata = repo.dirstate._ignorefileandline(p)
2520 break
2520 break
2521 if ignored:
2521 if ignored:
2522 if ignored == nf:
2522 if ignored == nf:
2523 ui.write("%s is ignored\n" % f)
2523 ui.write("%s is ignored\n" % f)
2524 else:
2524 else:
2525 ui.write("%s is ignored because of containing folder %s\n"
2525 ui.write("%s is ignored because of containing folder %s\n"
2526 % (f, ignored))
2526 % (f, ignored))
2527 ignorefile, lineno, line = ignoredata
2527 ignorefile, lineno, line = ignoredata
2528 ui.write("(ignore rule in %s, line %d: '%s')\n"
2528 ui.write("(ignore rule in %s, line %d: '%s')\n"
2529 % (ignorefile, lineno, line))
2529 % (ignorefile, lineno, line))
2530 else:
2530 else:
2531 ui.write("%s is not ignored\n" % f)
2531 ui.write("%s is not ignored\n" % f)
2532
2532
2533 @command('debugindex', debugrevlogopts +
2533 @command('debugindex', debugrevlogopts +
2534 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2534 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2535 _('[-f FORMAT] -c|-m|FILE'),
2535 _('[-f FORMAT] -c|-m|FILE'),
2536 optionalrepo=True)
2536 optionalrepo=True)
2537 def debugindex(ui, repo, file_=None, **opts):
2537 def debugindex(ui, repo, file_=None, **opts):
2538 """dump the contents of an index file"""
2538 """dump the contents of an index file"""
2539 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2539 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2540 format = opts.get('format', 0)
2540 format = opts.get('format', 0)
2541 if format not in (0, 1):
2541 if format not in (0, 1):
2542 raise error.Abort(_("unknown format %d") % format)
2542 raise error.Abort(_("unknown format %d") % format)
2543
2543
2544 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2544 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2545 if generaldelta:
2545 if generaldelta:
2546 basehdr = ' delta'
2546 basehdr = ' delta'
2547 else:
2547 else:
2548 basehdr = ' base'
2548 basehdr = ' base'
2549
2549
2550 if ui.debugflag:
2550 if ui.debugflag:
2551 shortfn = hex
2551 shortfn = hex
2552 else:
2552 else:
2553 shortfn = short
2553 shortfn = short
2554
2554
2555 # There might not be anything in r, so have a sane default
2555 # There might not be anything in r, so have a sane default
2556 idlen = 12
2556 idlen = 12
2557 for i in r:
2557 for i in r:
2558 idlen = len(shortfn(r.node(i)))
2558 idlen = len(shortfn(r.node(i)))
2559 break
2559 break
2560
2560
2561 if format == 0:
2561 if format == 0:
2562 ui.write(" rev offset length " + basehdr + " linkrev"
2562 ui.write(" rev offset length " + basehdr + " linkrev"
2563 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2563 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2564 elif format == 1:
2564 elif format == 1:
2565 ui.write(" rev flag offset length"
2565 ui.write(" rev flag offset length"
2566 " size " + basehdr + " link p1 p2"
2566 " size " + basehdr + " link p1 p2"
2567 " %s\n" % "nodeid".rjust(idlen))
2567 " %s\n" % "nodeid".rjust(idlen))
2568
2568
2569 for i in r:
2569 for i in r:
2570 node = r.node(i)
2570 node = r.node(i)
2571 if generaldelta:
2571 if generaldelta:
2572 base = r.deltaparent(i)
2572 base = r.deltaparent(i)
2573 else:
2573 else:
2574 base = r.chainbase(i)
2574 base = r.chainbase(i)
2575 if format == 0:
2575 if format == 0:
2576 try:
2576 try:
2577 pp = r.parents(node)
2577 pp = r.parents(node)
2578 except Exception:
2578 except Exception:
2579 pp = [nullid, nullid]
2579 pp = [nullid, nullid]
2580 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2580 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2581 i, r.start(i), r.length(i), base, r.linkrev(i),
2581 i, r.start(i), r.length(i), base, r.linkrev(i),
2582 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2582 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2583 elif format == 1:
2583 elif format == 1:
2584 pr = r.parentrevs(i)
2584 pr = r.parentrevs(i)
2585 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2585 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2586 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2586 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2587 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2587 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2588
2588
2589 @command('debugindexdot', debugrevlogopts,
2589 @command('debugindexdot', debugrevlogopts,
2590 _('-c|-m|FILE'), optionalrepo=True)
2590 _('-c|-m|FILE'), optionalrepo=True)
2591 def debugindexdot(ui, repo, file_=None, **opts):
2591 def debugindexdot(ui, repo, file_=None, **opts):
2592 """dump an index DAG as a graphviz dot file"""
2592 """dump an index DAG as a graphviz dot file"""
2593 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
2593 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
2594 ui.write(("digraph G {\n"))
2594 ui.write(("digraph G {\n"))
2595 for i in r:
2595 for i in r:
2596 node = r.node(i)
2596 node = r.node(i)
2597 pp = r.parents(node)
2597 pp = r.parents(node)
2598 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2598 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2599 if pp[1] != nullid:
2599 if pp[1] != nullid:
2600 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2600 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2601 ui.write("}\n")
2601 ui.write("}\n")
2602
2602
2603 @command('debugdeltachain',
2603 @command('debugdeltachain',
2604 debugrevlogopts + formatteropts,
2604 debugrevlogopts + formatteropts,
2605 _('-c|-m|FILE'),
2605 _('-c|-m|FILE'),
2606 optionalrepo=True)
2606 optionalrepo=True)
2607 def debugdeltachain(ui, repo, file_=None, **opts):
2607 def debugdeltachain(ui, repo, file_=None, **opts):
2608 """dump information about delta chains in a revlog
2608 """dump information about delta chains in a revlog
2609
2609
2610 Output can be templatized. Available template keywords are:
2610 Output can be templatized. Available template keywords are:
2611
2611
2612 rev revision number
2612 rev revision number
2613 chainid delta chain identifier (numbered by unique base)
2613 chainid delta chain identifier (numbered by unique base)
2614 chainlen delta chain length to this revision
2614 chainlen delta chain length to this revision
2615 prevrev previous revision in delta chain
2615 prevrev previous revision in delta chain
2616 deltatype role of delta / how it was computed
2616 deltatype role of delta / how it was computed
2617 compsize compressed size of revision
2617 compsize compressed size of revision
2618 uncompsize uncompressed size of revision
2618 uncompsize uncompressed size of revision
2619 chainsize total size of compressed revisions in chain
2619 chainsize total size of compressed revisions in chain
2620 chainratio total chain size divided by uncompressed revision size
2620 chainratio total chain size divided by uncompressed revision size
2621 (new delta chains typically start at ratio 2.00)
2621 (new delta chains typically start at ratio 2.00)
2622 lindist linear distance from base revision in delta chain to end
2622 lindist linear distance from base revision in delta chain to end
2623 of this revision
2623 of this revision
2624 extradist total size of revisions not part of this delta chain from
2624 extradist total size of revisions not part of this delta chain from
2625 base of delta chain to end of this revision; a measurement
2625 base of delta chain to end of this revision; a measurement
2626 of how much extra data we need to read/seek across to read
2626 of how much extra data we need to read/seek across to read
2627 the delta chain for this revision
2627 the delta chain for this revision
2628 extraratio extradist divided by chainsize; another representation of
2628 extraratio extradist divided by chainsize; another representation of
2629 how much unrelated data is needed to load this delta chain
2629 how much unrelated data is needed to load this delta chain
2630 """
2630 """
2631 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
2631 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
2632 index = r.index
2632 index = r.index
2633 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2633 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2634
2634
2635 def revinfo(rev):
2635 def revinfo(rev):
2636 e = index[rev]
2636 e = index[rev]
2637 compsize = e[1]
2637 compsize = e[1]
2638 uncompsize = e[2]
2638 uncompsize = e[2]
2639 chainsize = 0
2639 chainsize = 0
2640
2640
2641 if generaldelta:
2641 if generaldelta:
2642 if e[3] == e[5]:
2642 if e[3] == e[5]:
2643 deltatype = 'p1'
2643 deltatype = 'p1'
2644 elif e[3] == e[6]:
2644 elif e[3] == e[6]:
2645 deltatype = 'p2'
2645 deltatype = 'p2'
2646 elif e[3] == rev - 1:
2646 elif e[3] == rev - 1:
2647 deltatype = 'prev'
2647 deltatype = 'prev'
2648 elif e[3] == rev:
2648 elif e[3] == rev:
2649 deltatype = 'base'
2649 deltatype = 'base'
2650 else:
2650 else:
2651 deltatype = 'other'
2651 deltatype = 'other'
2652 else:
2652 else:
2653 if e[3] == rev:
2653 if e[3] == rev:
2654 deltatype = 'base'
2654 deltatype = 'base'
2655 else:
2655 else:
2656 deltatype = 'prev'
2656 deltatype = 'prev'
2657
2657
2658 chain = r._deltachain(rev)[0]
2658 chain = r._deltachain(rev)[0]
2659 for iterrev in chain:
2659 for iterrev in chain:
2660 e = index[iterrev]
2660 e = index[iterrev]
2661 chainsize += e[1]
2661 chainsize += e[1]
2662
2662
2663 return compsize, uncompsize, deltatype, chain, chainsize
2663 return compsize, uncompsize, deltatype, chain, chainsize
2664
2664
2665 fm = ui.formatter('debugdeltachain', opts)
2665 fm = ui.formatter('debugdeltachain', opts)
2666
2666
2667 fm.plain(' rev chain# chainlen prev delta '
2667 fm.plain(' rev chain# chainlen prev delta '
2668 'size rawsize chainsize ratio lindist extradist '
2668 'size rawsize chainsize ratio lindist extradist '
2669 'extraratio\n')
2669 'extraratio\n')
2670
2670
2671 chainbases = {}
2671 chainbases = {}
2672 for rev in r:
2672 for rev in r:
2673 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
2673 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
2674 chainbase = chain[0]
2674 chainbase = chain[0]
2675 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
2675 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
2676 basestart = r.start(chainbase)
2676 basestart = r.start(chainbase)
2677 revstart = r.start(rev)
2677 revstart = r.start(rev)
2678 lineardist = revstart + comp - basestart
2678 lineardist = revstart + comp - basestart
2679 extradist = lineardist - chainsize
2679 extradist = lineardist - chainsize
2680 try:
2680 try:
2681 prevrev = chain[-2]
2681 prevrev = chain[-2]
2682 except IndexError:
2682 except IndexError:
2683 prevrev = -1
2683 prevrev = -1
2684
2684
2685 chainratio = float(chainsize) / float(uncomp)
2685 chainratio = float(chainsize) / float(uncomp)
2686 extraratio = float(extradist) / float(chainsize)
2686 extraratio = float(extradist) / float(chainsize)
2687
2687
2688 fm.startitem()
2688 fm.startitem()
2689 fm.write('rev chainid chainlen prevrev deltatype compsize '
2689 fm.write('rev chainid chainlen prevrev deltatype compsize '
2690 'uncompsize chainsize chainratio lindist extradist '
2690 'uncompsize chainsize chainratio lindist extradist '
2691 'extraratio',
2691 'extraratio',
2692 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
2692 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
2693 rev, chainid, len(chain), prevrev, deltatype, comp,
2693 rev, chainid, len(chain), prevrev, deltatype, comp,
2694 uncomp, chainsize, chainratio, lineardist, extradist,
2694 uncomp, chainsize, chainratio, lineardist, extradist,
2695 extraratio,
2695 extraratio,
2696 rev=rev, chainid=chainid, chainlen=len(chain),
2696 rev=rev, chainid=chainid, chainlen=len(chain),
2697 prevrev=prevrev, deltatype=deltatype, compsize=comp,
2697 prevrev=prevrev, deltatype=deltatype, compsize=comp,
2698 uncompsize=uncomp, chainsize=chainsize,
2698 uncompsize=uncomp, chainsize=chainsize,
2699 chainratio=chainratio, lindist=lineardist,
2699 chainratio=chainratio, lindist=lineardist,
2700 extradist=extradist, extraratio=extraratio)
2700 extradist=extradist, extraratio=extraratio)
2701
2701
2702 fm.end()
2702 fm.end()
2703
2703
2704 @command('debuginstall', [] + formatteropts, '', norepo=True)
2704 @command('debuginstall', [] + formatteropts, '', norepo=True)
2705 def debuginstall(ui, **opts):
2705 def debuginstall(ui, **opts):
2706 '''test Mercurial installation
2706 '''test Mercurial installation
2707
2707
2708 Returns 0 on success.
2708 Returns 0 on success.
2709 '''
2709 '''
2710
2710
2711 def writetemp(contents):
2711 def writetemp(contents):
2712 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2712 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2713 f = os.fdopen(fd, "wb")
2713 f = os.fdopen(fd, "wb")
2714 f.write(contents)
2714 f.write(contents)
2715 f.close()
2715 f.close()
2716 return name
2716 return name
2717
2717
2718 problems = 0
2718 problems = 0
2719
2719
2720 fm = ui.formatter('debuginstall', opts)
2720 fm = ui.formatter('debuginstall', opts)
2721 fm.startitem()
2721 fm.startitem()
2722
2722
2723 # encoding
2723 # encoding
2724 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
2724 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
2725 err = None
2725 err = None
2726 try:
2726 try:
2727 encoding.fromlocal("test")
2727 encoding.fromlocal("test")
2728 except error.Abort as inst:
2728 except error.Abort as inst:
2729 err = inst
2729 err = inst
2730 problems += 1
2730 problems += 1
2731 fm.condwrite(err, 'encodingerror', _(" %s\n"
2731 fm.condwrite(err, 'encodingerror', _(" %s\n"
2732 " (check that your locale is properly set)\n"), err)
2732 " (check that your locale is properly set)\n"), err)
2733
2733
2734 # Python
2734 # Python
2735 fm.write('pythonexe', _("checking Python executable (%s)\n"),
2735 fm.write('pythonexe', _("checking Python executable (%s)\n"),
2736 sys.executable)
2736 sys.executable)
2737 fm.write('pythonver', _("checking Python version (%s)\n"),
2737 fm.write('pythonver', _("checking Python version (%s)\n"),
2738 ("%s.%s.%s" % sys.version_info[:3]))
2738 ("%s.%s.%s" % sys.version_info[:3]))
2739 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
2739 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
2740 os.path.dirname(os.__file__))
2740 os.path.dirname(os.__file__))
2741
2741
2742 # compiled modules
2742 # compiled modules
2743 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
2743 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
2744 os.path.dirname(__file__))
2744 os.path.dirname(__file__))
2745
2745
2746 err = None
2746 err = None
2747 try:
2747 try:
2748 from . import (
2748 from . import (
2749 base85,
2749 base85,
2750 bdiff,
2750 bdiff,
2751 mpatch,
2751 mpatch,
2752 osutil,
2752 osutil,
2753 )
2753 )
2754 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2754 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2755 except Exception as inst:
2755 except Exception as inst:
2756 err = inst
2756 err = inst
2757 problems += 1
2757 problems += 1
2758 fm.condwrite(err, 'extensionserror', " %s\n", err)
2758 fm.condwrite(err, 'extensionserror', " %s\n", err)
2759
2759
2760 # templates
2760 # templates
2761 p = templater.templatepaths()
2761 p = templater.templatepaths()
2762 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
2762 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
2763 fm.condwrite(not p, '', _(" no template directories found\n"))
2763 fm.condwrite(not p, '', _(" no template directories found\n"))
2764 if p:
2764 if p:
2765 m = templater.templatepath("map-cmdline.default")
2765 m = templater.templatepath("map-cmdline.default")
2766 if m:
2766 if m:
2767 # template found, check if it is working
2767 # template found, check if it is working
2768 err = None
2768 err = None
2769 try:
2769 try:
2770 templater.templater(m)
2770 templater.templater(m)
2771 except Exception as inst:
2771 except Exception as inst:
2772 err = inst
2772 err = inst
2773 p = None
2773 p = None
2774 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
2774 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
2775 else:
2775 else:
2776 p = None
2776 p = None
2777 fm.condwrite(p, 'defaulttemplate',
2777 fm.condwrite(p, 'defaulttemplate',
2778 _("checking default template (%s)\n"), m)
2778 _("checking default template (%s)\n"), m)
2779 fm.condwrite(not m, 'defaulttemplatenotfound',
2779 fm.condwrite(not m, 'defaulttemplatenotfound',
2780 _(" template '%s' not found\n"), "default")
2780 _(" template '%s' not found\n"), "default")
2781 if not p:
2781 if not p:
2782 problems += 1
2782 problems += 1
2783 fm.condwrite(not p, '',
2783 fm.condwrite(not p, '',
2784 _(" (templates seem to have been installed incorrectly)\n"))
2784 _(" (templates seem to have been installed incorrectly)\n"))
2785
2785
2786 # editor
2786 # editor
2787 editor = ui.geteditor()
2787 editor = ui.geteditor()
2788 editor = util.expandpath(editor)
2788 editor = util.expandpath(editor)
2789 fm.write('editor', _("checking commit editor... (%s)\n"), editor)
2789 fm.write('editor', _("checking commit editor... (%s)\n"), editor)
2790 cmdpath = util.findexe(shlex.split(editor)[0])
2790 cmdpath = util.findexe(shlex.split(editor)[0])
2791 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
2791 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
2792 _(" No commit editor set and can't find %s in PATH\n"
2792 _(" No commit editor set and can't find %s in PATH\n"
2793 " (specify a commit editor in your configuration"
2793 " (specify a commit editor in your configuration"
2794 " file)\n"), not cmdpath and editor == 'vi' and editor)
2794 " file)\n"), not cmdpath and editor == 'vi' and editor)
2795 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
2795 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
2796 _(" Can't find editor '%s' in PATH\n"
2796 _(" Can't find editor '%s' in PATH\n"
2797 " (specify a commit editor in your configuration"
2797 " (specify a commit editor in your configuration"
2798 " file)\n"), not cmdpath and editor)
2798 " file)\n"), not cmdpath and editor)
2799 if not cmdpath and editor != 'vi':
2799 if not cmdpath and editor != 'vi':
2800 problems += 1
2800 problems += 1
2801
2801
2802 # check username
2802 # check username
2803 username = None
2803 username = None
2804 err = None
2804 err = None
2805 try:
2805 try:
2806 username = ui.username()
2806 username = ui.username()
2807 except error.Abort as e:
2807 except error.Abort as e:
2808 err = e
2808 err = e
2809 problems += 1
2809 problems += 1
2810
2810
2811 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
2811 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
2812 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
2812 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
2813 " (specify a username in your configuration file)\n"), err)
2813 " (specify a username in your configuration file)\n"), err)
2814
2814
2815 fm.condwrite(not problems, '',
2815 fm.condwrite(not problems, '',
2816 _("no problems detected\n"))
2816 _("no problems detected\n"))
2817 if not problems:
2817 if not problems:
2818 fm.data(problems=problems)
2818 fm.data(problems=problems)
2819 fm.condwrite(problems, 'problems',
2819 fm.condwrite(problems, 'problems',
2820 _("%s problems detected,"
2820 _("%s problems detected,"
2821 " please check your install!\n"), problems)
2821 " please check your install!\n"), problems)
2822 fm.end()
2822 fm.end()
2823
2823
2824 return problems
2824 return problems
2825
2825
2826 @command('debugknown', [], _('REPO ID...'), norepo=True)
2826 @command('debugknown', [], _('REPO ID...'), norepo=True)
2827 def debugknown(ui, repopath, *ids, **opts):
2827 def debugknown(ui, repopath, *ids, **opts):
2828 """test whether node ids are known to a repo
2828 """test whether node ids are known to a repo
2829
2829
2830 Every ID must be a full-length hex node id string. Returns a list of 0s
2830 Every ID must be a full-length hex node id string. Returns a list of 0s
2831 and 1s indicating unknown/known.
2831 and 1s indicating unknown/known.
2832 """
2832 """
2833 repo = hg.peer(ui, opts, repopath)
2833 repo = hg.peer(ui, opts, repopath)
2834 if not repo.capable('known'):
2834 if not repo.capable('known'):
2835 raise error.Abort("known() not supported by target repository")
2835 raise error.Abort("known() not supported by target repository")
2836 flags = repo.known([bin(s) for s in ids])
2836 flags = repo.known([bin(s) for s in ids])
2837 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2837 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2838
2838
2839 @command('debuglabelcomplete', [], _('LABEL...'))
2839 @command('debuglabelcomplete', [], _('LABEL...'))
2840 def debuglabelcomplete(ui, repo, *args):
2840 def debuglabelcomplete(ui, repo, *args):
2841 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2841 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2842 debugnamecomplete(ui, repo, *args)
2842 debugnamecomplete(ui, repo, *args)
2843
2843
2844 @command('debugmergestate', [], '')
2844 @command('debugmergestate', [], '')
2845 def debugmergestate(ui, repo, *args):
2845 def debugmergestate(ui, repo, *args):
2846 """print merge state
2846 """print merge state
2847
2847
2848 Use --verbose to print out information about whether v1 or v2 merge state
2848 Use --verbose to print out information about whether v1 or v2 merge state
2849 was chosen."""
2849 was chosen."""
2850 def _hashornull(h):
2850 def _hashornull(h):
2851 if h == nullhex:
2851 if h == nullhex:
2852 return 'null'
2852 return 'null'
2853 else:
2853 else:
2854 return h
2854 return h
2855
2855
2856 def printrecords(version):
2856 def printrecords(version):
2857 ui.write(('* version %s records\n') % version)
2857 ui.write(('* version %s records\n') % version)
2858 if version == 1:
2858 if version == 1:
2859 records = v1records
2859 records = v1records
2860 else:
2860 else:
2861 records = v2records
2861 records = v2records
2862
2862
2863 for rtype, record in records:
2863 for rtype, record in records:
2864 # pretty print some record types
2864 # pretty print some record types
2865 if rtype == 'L':
2865 if rtype == 'L':
2866 ui.write(('local: %s\n') % record)
2866 ui.write(('local: %s\n') % record)
2867 elif rtype == 'O':
2867 elif rtype == 'O':
2868 ui.write(('other: %s\n') % record)
2868 ui.write(('other: %s\n') % record)
2869 elif rtype == 'm':
2869 elif rtype == 'm':
2870 driver, mdstate = record.split('\0', 1)
2870 driver, mdstate = record.split('\0', 1)
2871 ui.write(('merge driver: %s (state "%s")\n')
2871 ui.write(('merge driver: %s (state "%s")\n')
2872 % (driver, mdstate))
2872 % (driver, mdstate))
2873 elif rtype in 'FDC':
2873 elif rtype in 'FDC':
2874 r = record.split('\0')
2874 r = record.split('\0')
2875 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2875 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2876 if version == 1:
2876 if version == 1:
2877 onode = 'not stored in v1 format'
2877 onode = 'not stored in v1 format'
2878 flags = r[7]
2878 flags = r[7]
2879 else:
2879 else:
2880 onode, flags = r[7:9]
2880 onode, flags = r[7:9]
2881 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
2881 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
2882 % (f, rtype, state, _hashornull(hash)))
2882 % (f, rtype, state, _hashornull(hash)))
2883 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2883 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2884 ui.write((' ancestor path: %s (node %s)\n')
2884 ui.write((' ancestor path: %s (node %s)\n')
2885 % (afile, _hashornull(anode)))
2885 % (afile, _hashornull(anode)))
2886 ui.write((' other path: %s (node %s)\n')
2886 ui.write((' other path: %s (node %s)\n')
2887 % (ofile, _hashornull(onode)))
2887 % (ofile, _hashornull(onode)))
2888 elif rtype == 'f':
2888 elif rtype == 'f':
2889 filename, rawextras = record.split('\0', 1)
2889 filename, rawextras = record.split('\0', 1)
2890 extras = rawextras.split('\0')
2890 extras = rawextras.split('\0')
2891 i = 0
2891 i = 0
2892 extrastrings = []
2892 extrastrings = []
2893 while i < len(extras):
2893 while i < len(extras):
2894 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
2894 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
2895 i += 2
2895 i += 2
2896
2896
2897 ui.write(('file extras: %s (%s)\n')
2897 ui.write(('file extras: %s (%s)\n')
2898 % (filename, ', '.join(extrastrings)))
2898 % (filename, ', '.join(extrastrings)))
2899 elif rtype == 'l':
2900 labels = record.split('\0', 2)
2901 labels = [l for l in labels if len(l) > 0]
2902 ui.write(('labels:\n'))
2903 ui.write((' local: %s\n' % labels[0]))
2904 ui.write((' other: %s\n' % labels[1]))
2905 if len(labels) > 2:
2906 ui.write((' base: %s\n' % labels[2]))
2899 else:
2907 else:
2900 ui.write(('unrecognized entry: %s\t%s\n')
2908 ui.write(('unrecognized entry: %s\t%s\n')
2901 % (rtype, record.replace('\0', '\t')))
2909 % (rtype, record.replace('\0', '\t')))
2902
2910
2903 # Avoid mergestate.read() since it may raise an exception for unsupported
2911 # Avoid mergestate.read() since it may raise an exception for unsupported
2904 # merge state records. We shouldn't be doing this, but this is OK since this
2912 # merge state records. We shouldn't be doing this, but this is OK since this
2905 # command is pretty low-level.
2913 # command is pretty low-level.
2906 ms = mergemod.mergestate(repo)
2914 ms = mergemod.mergestate(repo)
2907
2915
2908 # sort so that reasonable information is on top
2916 # sort so that reasonable information is on top
2909 v1records = ms._readrecordsv1()
2917 v1records = ms._readrecordsv1()
2910 v2records = ms._readrecordsv2()
2918 v2records = ms._readrecordsv2()
2911 order = 'LOm'
2919 order = 'LOml'
2912 def key(r):
2920 def key(r):
2913 idx = order.find(r[0])
2921 idx = order.find(r[0])
2914 if idx == -1:
2922 if idx == -1:
2915 return (1, r[1])
2923 return (1, r[1])
2916 else:
2924 else:
2917 return (0, idx)
2925 return (0, idx)
2918 v1records.sort(key=key)
2926 v1records.sort(key=key)
2919 v2records.sort(key=key)
2927 v2records.sort(key=key)
2920
2928
2921 if not v1records and not v2records:
2929 if not v1records and not v2records:
2922 ui.write(('no merge state found\n'))
2930 ui.write(('no merge state found\n'))
2923 elif not v2records:
2931 elif not v2records:
2924 ui.note(('no version 2 merge state\n'))
2932 ui.note(('no version 2 merge state\n'))
2925 printrecords(1)
2933 printrecords(1)
2926 elif ms._v1v2match(v1records, v2records):
2934 elif ms._v1v2match(v1records, v2records):
2927 ui.note(('v1 and v2 states match: using v2\n'))
2935 ui.note(('v1 and v2 states match: using v2\n'))
2928 printrecords(2)
2936 printrecords(2)
2929 else:
2937 else:
2930 ui.note(('v1 and v2 states mismatch: using v1\n'))
2938 ui.note(('v1 and v2 states mismatch: using v1\n'))
2931 printrecords(1)
2939 printrecords(1)
2932 if ui.verbose:
2940 if ui.verbose:
2933 printrecords(2)
2941 printrecords(2)
2934
2942
2935 @command('debugnamecomplete', [], _('NAME...'))
2943 @command('debugnamecomplete', [], _('NAME...'))
2936 def debugnamecomplete(ui, repo, *args):
2944 def debugnamecomplete(ui, repo, *args):
2937 '''complete "names" - tags, open branch names, bookmark names'''
2945 '''complete "names" - tags, open branch names, bookmark names'''
2938
2946
2939 names = set()
2947 names = set()
2940 # since we previously only listed open branches, we will handle that
2948 # since we previously only listed open branches, we will handle that
2941 # specially (after this for loop)
2949 # specially (after this for loop)
2942 for name, ns in repo.names.iteritems():
2950 for name, ns in repo.names.iteritems():
2943 if name != 'branches':
2951 if name != 'branches':
2944 names.update(ns.listnames(repo))
2952 names.update(ns.listnames(repo))
2945 names.update(tag for (tag, heads, tip, closed)
2953 names.update(tag for (tag, heads, tip, closed)
2946 in repo.branchmap().iterbranches() if not closed)
2954 in repo.branchmap().iterbranches() if not closed)
2947 completions = set()
2955 completions = set()
2948 if not args:
2956 if not args:
2949 args = ['']
2957 args = ['']
2950 for a in args:
2958 for a in args:
2951 completions.update(n for n in names if n.startswith(a))
2959 completions.update(n for n in names if n.startswith(a))
2952 ui.write('\n'.join(sorted(completions)))
2960 ui.write('\n'.join(sorted(completions)))
2953 ui.write('\n')
2961 ui.write('\n')
2954
2962
2955 @command('debuglocks',
2963 @command('debuglocks',
2956 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2964 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2957 ('W', 'force-wlock', None,
2965 ('W', 'force-wlock', None,
2958 _('free the working state lock (DANGEROUS)'))],
2966 _('free the working state lock (DANGEROUS)'))],
2959 _('[OPTION]...'))
2967 _('[OPTION]...'))
2960 def debuglocks(ui, repo, **opts):
2968 def debuglocks(ui, repo, **opts):
2961 """show or modify state of locks
2969 """show or modify state of locks
2962
2970
2963 By default, this command will show which locks are held. This
2971 By default, this command will show which locks are held. This
2964 includes the user and process holding the lock, the amount of time
2972 includes the user and process holding the lock, the amount of time
2965 the lock has been held, and the machine name where the process is
2973 the lock has been held, and the machine name where the process is
2966 running if it's not local.
2974 running if it's not local.
2967
2975
2968 Locks protect the integrity of Mercurial's data, so should be
2976 Locks protect the integrity of Mercurial's data, so should be
2969 treated with care. System crashes or other interruptions may cause
2977 treated with care. System crashes or other interruptions may cause
2970 locks to not be properly released, though Mercurial will usually
2978 locks to not be properly released, though Mercurial will usually
2971 detect and remove such stale locks automatically.
2979 detect and remove such stale locks automatically.
2972
2980
2973 However, detecting stale locks may not always be possible (for
2981 However, detecting stale locks may not always be possible (for
2974 instance, on a shared filesystem). Removing locks may also be
2982 instance, on a shared filesystem). Removing locks may also be
2975 blocked by filesystem permissions.
2983 blocked by filesystem permissions.
2976
2984
2977 Returns 0 if no locks are held.
2985 Returns 0 if no locks are held.
2978
2986
2979 """
2987 """
2980
2988
2981 if opts.get('force_lock'):
2989 if opts.get('force_lock'):
2982 repo.svfs.unlink('lock')
2990 repo.svfs.unlink('lock')
2983 if opts.get('force_wlock'):
2991 if opts.get('force_wlock'):
2984 repo.vfs.unlink('wlock')
2992 repo.vfs.unlink('wlock')
2985 if opts.get('force_lock') or opts.get('force_lock'):
2993 if opts.get('force_lock') or opts.get('force_lock'):
2986 return 0
2994 return 0
2987
2995
2988 now = time.time()
2996 now = time.time()
2989 held = 0
2997 held = 0
2990
2998
2991 def report(vfs, name, method):
2999 def report(vfs, name, method):
2992 # this causes stale locks to get reaped for more accurate reporting
3000 # this causes stale locks to get reaped for more accurate reporting
2993 try:
3001 try:
2994 l = method(False)
3002 l = method(False)
2995 except error.LockHeld:
3003 except error.LockHeld:
2996 l = None
3004 l = None
2997
3005
2998 if l:
3006 if l:
2999 l.release()
3007 l.release()
3000 else:
3008 else:
3001 try:
3009 try:
3002 stat = vfs.lstat(name)
3010 stat = vfs.lstat(name)
3003 age = now - stat.st_mtime
3011 age = now - stat.st_mtime
3004 user = util.username(stat.st_uid)
3012 user = util.username(stat.st_uid)
3005 locker = vfs.readlock(name)
3013 locker = vfs.readlock(name)
3006 if ":" in locker:
3014 if ":" in locker:
3007 host, pid = locker.split(':')
3015 host, pid = locker.split(':')
3008 if host == socket.gethostname():
3016 if host == socket.gethostname():
3009 locker = 'user %s, process %s' % (user, pid)
3017 locker = 'user %s, process %s' % (user, pid)
3010 else:
3018 else:
3011 locker = 'user %s, process %s, host %s' \
3019 locker = 'user %s, process %s, host %s' \
3012 % (user, pid, host)
3020 % (user, pid, host)
3013 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
3021 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
3014 return 1
3022 return 1
3015 except OSError as e:
3023 except OSError as e:
3016 if e.errno != errno.ENOENT:
3024 if e.errno != errno.ENOENT:
3017 raise
3025 raise
3018
3026
3019 ui.write("%-6s free\n" % (name + ":"))
3027 ui.write("%-6s free\n" % (name + ":"))
3020 return 0
3028 return 0
3021
3029
3022 held += report(repo.svfs, "lock", repo.lock)
3030 held += report(repo.svfs, "lock", repo.lock)
3023 held += report(repo.vfs, "wlock", repo.wlock)
3031 held += report(repo.vfs, "wlock", repo.wlock)
3024
3032
3025 return held
3033 return held
3026
3034
3027 @command('debugobsolete',
3035 @command('debugobsolete',
3028 [('', 'flags', 0, _('markers flag')),
3036 [('', 'flags', 0, _('markers flag')),
3029 ('', 'record-parents', False,
3037 ('', 'record-parents', False,
3030 _('record parent information for the precursor')),
3038 _('record parent information for the precursor')),
3031 ('r', 'rev', [], _('display markers relevant to REV')),
3039 ('r', 'rev', [], _('display markers relevant to REV')),
3032 ('', 'index', False, _('display index of the marker')),
3040 ('', 'index', False, _('display index of the marker')),
3033 ] + commitopts2,
3041 ] + commitopts2,
3034 _('[OBSOLETED [REPLACEMENT ...]]'))
3042 _('[OBSOLETED [REPLACEMENT ...]]'))
3035 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
3043 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
3036 """create arbitrary obsolete marker
3044 """create arbitrary obsolete marker
3037
3045
3038 With no arguments, displays the list of obsolescence markers."""
3046 With no arguments, displays the list of obsolescence markers."""
3039
3047
3040 def parsenodeid(s):
3048 def parsenodeid(s):
3041 try:
3049 try:
3042 # We do not use revsingle/revrange functions here to accept
3050 # We do not use revsingle/revrange functions here to accept
3043 # arbitrary node identifiers, possibly not present in the
3051 # arbitrary node identifiers, possibly not present in the
3044 # local repository.
3052 # local repository.
3045 n = bin(s)
3053 n = bin(s)
3046 if len(n) != len(nullid):
3054 if len(n) != len(nullid):
3047 raise TypeError()
3055 raise TypeError()
3048 return n
3056 return n
3049 except TypeError:
3057 except TypeError:
3050 raise error.Abort('changeset references must be full hexadecimal '
3058 raise error.Abort('changeset references must be full hexadecimal '
3051 'node identifiers')
3059 'node identifiers')
3052
3060
3053 if precursor is not None:
3061 if precursor is not None:
3054 if opts['rev']:
3062 if opts['rev']:
3055 raise error.Abort('cannot select revision when creating marker')
3063 raise error.Abort('cannot select revision when creating marker')
3056 metadata = {}
3064 metadata = {}
3057 metadata['user'] = opts['user'] or ui.username()
3065 metadata['user'] = opts['user'] or ui.username()
3058 succs = tuple(parsenodeid(succ) for succ in successors)
3066 succs = tuple(parsenodeid(succ) for succ in successors)
3059 l = repo.lock()
3067 l = repo.lock()
3060 try:
3068 try:
3061 tr = repo.transaction('debugobsolete')
3069 tr = repo.transaction('debugobsolete')
3062 try:
3070 try:
3063 date = opts.get('date')
3071 date = opts.get('date')
3064 if date:
3072 if date:
3065 date = util.parsedate(date)
3073 date = util.parsedate(date)
3066 else:
3074 else:
3067 date = None
3075 date = None
3068 prec = parsenodeid(precursor)
3076 prec = parsenodeid(precursor)
3069 parents = None
3077 parents = None
3070 if opts['record_parents']:
3078 if opts['record_parents']:
3071 if prec not in repo.unfiltered():
3079 if prec not in repo.unfiltered():
3072 raise error.Abort('cannot used --record-parents on '
3080 raise error.Abort('cannot used --record-parents on '
3073 'unknown changesets')
3081 'unknown changesets')
3074 parents = repo.unfiltered()[prec].parents()
3082 parents = repo.unfiltered()[prec].parents()
3075 parents = tuple(p.node() for p in parents)
3083 parents = tuple(p.node() for p in parents)
3076 repo.obsstore.create(tr, prec, succs, opts['flags'],
3084 repo.obsstore.create(tr, prec, succs, opts['flags'],
3077 parents=parents, date=date,
3085 parents=parents, date=date,
3078 metadata=metadata)
3086 metadata=metadata)
3079 tr.close()
3087 tr.close()
3080 except ValueError as exc:
3088 except ValueError as exc:
3081 raise error.Abort(_('bad obsmarker input: %s') % exc)
3089 raise error.Abort(_('bad obsmarker input: %s') % exc)
3082 finally:
3090 finally:
3083 tr.release()
3091 tr.release()
3084 finally:
3092 finally:
3085 l.release()
3093 l.release()
3086 else:
3094 else:
3087 if opts['rev']:
3095 if opts['rev']:
3088 revs = scmutil.revrange(repo, opts['rev'])
3096 revs = scmutil.revrange(repo, opts['rev'])
3089 nodes = [repo[r].node() for r in revs]
3097 nodes = [repo[r].node() for r in revs]
3090 markers = list(obsolete.getmarkers(repo, nodes=nodes))
3098 markers = list(obsolete.getmarkers(repo, nodes=nodes))
3091 markers.sort(key=lambda x: x._data)
3099 markers.sort(key=lambda x: x._data)
3092 else:
3100 else:
3093 markers = obsolete.getmarkers(repo)
3101 markers = obsolete.getmarkers(repo)
3094
3102
3095 for i, m in enumerate(markers):
3103 for i, m in enumerate(markers):
3096 ind = i if opts.get('index') else None
3104 ind = i if opts.get('index') else None
3097 cmdutil.showmarker(ui, m, index=ind)
3105 cmdutil.showmarker(ui, m, index=ind)
3098
3106
3099 @command('debugpathcomplete',
3107 @command('debugpathcomplete',
3100 [('f', 'full', None, _('complete an entire path')),
3108 [('f', 'full', None, _('complete an entire path')),
3101 ('n', 'normal', None, _('show only normal files')),
3109 ('n', 'normal', None, _('show only normal files')),
3102 ('a', 'added', None, _('show only added files')),
3110 ('a', 'added', None, _('show only added files')),
3103 ('r', 'removed', None, _('show only removed files'))],
3111 ('r', 'removed', None, _('show only removed files'))],
3104 _('FILESPEC...'))
3112 _('FILESPEC...'))
3105 def debugpathcomplete(ui, repo, *specs, **opts):
3113 def debugpathcomplete(ui, repo, *specs, **opts):
3106 '''complete part or all of a tracked path
3114 '''complete part or all of a tracked path
3107
3115
3108 This command supports shells that offer path name completion. It
3116 This command supports shells that offer path name completion. It
3109 currently completes only files already known to the dirstate.
3117 currently completes only files already known to the dirstate.
3110
3118
3111 Completion extends only to the next path segment unless
3119 Completion extends only to the next path segment unless
3112 --full is specified, in which case entire paths are used.'''
3120 --full is specified, in which case entire paths are used.'''
3113
3121
3114 def complete(path, acceptable):
3122 def complete(path, acceptable):
3115 dirstate = repo.dirstate
3123 dirstate = repo.dirstate
3116 spec = os.path.normpath(os.path.join(os.getcwd(), path))
3124 spec = os.path.normpath(os.path.join(os.getcwd(), path))
3117 rootdir = repo.root + os.sep
3125 rootdir = repo.root + os.sep
3118 if spec != repo.root and not spec.startswith(rootdir):
3126 if spec != repo.root and not spec.startswith(rootdir):
3119 return [], []
3127 return [], []
3120 if os.path.isdir(spec):
3128 if os.path.isdir(spec):
3121 spec += '/'
3129 spec += '/'
3122 spec = spec[len(rootdir):]
3130 spec = spec[len(rootdir):]
3123 fixpaths = os.sep != '/'
3131 fixpaths = os.sep != '/'
3124 if fixpaths:
3132 if fixpaths:
3125 spec = spec.replace(os.sep, '/')
3133 spec = spec.replace(os.sep, '/')
3126 speclen = len(spec)
3134 speclen = len(spec)
3127 fullpaths = opts['full']
3135 fullpaths = opts['full']
3128 files, dirs = set(), set()
3136 files, dirs = set(), set()
3129 adddir, addfile = dirs.add, files.add
3137 adddir, addfile = dirs.add, files.add
3130 for f, st in dirstate.iteritems():
3138 for f, st in dirstate.iteritems():
3131 if f.startswith(spec) and st[0] in acceptable:
3139 if f.startswith(spec) and st[0] in acceptable:
3132 if fixpaths:
3140 if fixpaths:
3133 f = f.replace('/', os.sep)
3141 f = f.replace('/', os.sep)
3134 if fullpaths:
3142 if fullpaths:
3135 addfile(f)
3143 addfile(f)
3136 continue
3144 continue
3137 s = f.find(os.sep, speclen)
3145 s = f.find(os.sep, speclen)
3138 if s >= 0:
3146 if s >= 0:
3139 adddir(f[:s])
3147 adddir(f[:s])
3140 else:
3148 else:
3141 addfile(f)
3149 addfile(f)
3142 return files, dirs
3150 return files, dirs
3143
3151
3144 acceptable = ''
3152 acceptable = ''
3145 if opts['normal']:
3153 if opts['normal']:
3146 acceptable += 'nm'
3154 acceptable += 'nm'
3147 if opts['added']:
3155 if opts['added']:
3148 acceptable += 'a'
3156 acceptable += 'a'
3149 if opts['removed']:
3157 if opts['removed']:
3150 acceptable += 'r'
3158 acceptable += 'r'
3151 cwd = repo.getcwd()
3159 cwd = repo.getcwd()
3152 if not specs:
3160 if not specs:
3153 specs = ['.']
3161 specs = ['.']
3154
3162
3155 files, dirs = set(), set()
3163 files, dirs = set(), set()
3156 for spec in specs:
3164 for spec in specs:
3157 f, d = complete(spec, acceptable or 'nmar')
3165 f, d = complete(spec, acceptable or 'nmar')
3158 files.update(f)
3166 files.update(f)
3159 dirs.update(d)
3167 dirs.update(d)
3160 files.update(dirs)
3168 files.update(dirs)
3161 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
3169 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
3162 ui.write('\n')
3170 ui.write('\n')
3163
3171
3164 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
3172 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
3165 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
3173 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
3166 '''access the pushkey key/value protocol
3174 '''access the pushkey key/value protocol
3167
3175
3168 With two args, list the keys in the given namespace.
3176 With two args, list the keys in the given namespace.
3169
3177
3170 With five args, set a key to new if it currently is set to old.
3178 With five args, set a key to new if it currently is set to old.
3171 Reports success or failure.
3179 Reports success or failure.
3172 '''
3180 '''
3173
3181
3174 target = hg.peer(ui, {}, repopath)
3182 target = hg.peer(ui, {}, repopath)
3175 if keyinfo:
3183 if keyinfo:
3176 key, old, new = keyinfo
3184 key, old, new = keyinfo
3177 r = target.pushkey(namespace, key, old, new)
3185 r = target.pushkey(namespace, key, old, new)
3178 ui.status(str(r) + '\n')
3186 ui.status(str(r) + '\n')
3179 return not r
3187 return not r
3180 else:
3188 else:
3181 for k, v in sorted(target.listkeys(namespace).iteritems()):
3189 for k, v in sorted(target.listkeys(namespace).iteritems()):
3182 ui.write("%s\t%s\n" % (k.encode('string-escape'),
3190 ui.write("%s\t%s\n" % (k.encode('string-escape'),
3183 v.encode('string-escape')))
3191 v.encode('string-escape')))
3184
3192
3185 @command('debugpvec', [], _('A B'))
3193 @command('debugpvec', [], _('A B'))
3186 def debugpvec(ui, repo, a, b=None):
3194 def debugpvec(ui, repo, a, b=None):
3187 ca = scmutil.revsingle(repo, a)
3195 ca = scmutil.revsingle(repo, a)
3188 cb = scmutil.revsingle(repo, b)
3196 cb = scmutil.revsingle(repo, b)
3189 pa = pvec.ctxpvec(ca)
3197 pa = pvec.ctxpvec(ca)
3190 pb = pvec.ctxpvec(cb)
3198 pb = pvec.ctxpvec(cb)
3191 if pa == pb:
3199 if pa == pb:
3192 rel = "="
3200 rel = "="
3193 elif pa > pb:
3201 elif pa > pb:
3194 rel = ">"
3202 rel = ">"
3195 elif pa < pb:
3203 elif pa < pb:
3196 rel = "<"
3204 rel = "<"
3197 elif pa | pb:
3205 elif pa | pb:
3198 rel = "|"
3206 rel = "|"
3199 ui.write(_("a: %s\n") % pa)
3207 ui.write(_("a: %s\n") % pa)
3200 ui.write(_("b: %s\n") % pb)
3208 ui.write(_("b: %s\n") % pb)
3201 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
3209 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
3202 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
3210 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
3203 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
3211 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
3204 pa.distance(pb), rel))
3212 pa.distance(pb), rel))
3205
3213
3206 @command('debugrebuilddirstate|debugrebuildstate',
3214 @command('debugrebuilddirstate|debugrebuildstate',
3207 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
3215 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
3208 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
3216 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
3209 'the working copy parent')),
3217 'the working copy parent')),
3210 ],
3218 ],
3211 _('[-r REV]'))
3219 _('[-r REV]'))
3212 def debugrebuilddirstate(ui, repo, rev, **opts):
3220 def debugrebuilddirstate(ui, repo, rev, **opts):
3213 """rebuild the dirstate as it would look like for the given revision
3221 """rebuild the dirstate as it would look like for the given revision
3214
3222
3215 If no revision is specified the first current parent will be used.
3223 If no revision is specified the first current parent will be used.
3216
3224
3217 The dirstate will be set to the files of the given revision.
3225 The dirstate will be set to the files of the given revision.
3218 The actual working directory content or existing dirstate
3226 The actual working directory content or existing dirstate
3219 information such as adds or removes is not considered.
3227 information such as adds or removes is not considered.
3220
3228
3221 ``minimal`` will only rebuild the dirstate status for files that claim to be
3229 ``minimal`` will only rebuild the dirstate status for files that claim to be
3222 tracked but are not in the parent manifest, or that exist in the parent
3230 tracked but are not in the parent manifest, or that exist in the parent
3223 manifest but are not in the dirstate. It will not change adds, removes, or
3231 manifest but are not in the dirstate. It will not change adds, removes, or
3224 modified files that are in the working copy parent.
3232 modified files that are in the working copy parent.
3225
3233
3226 One use of this command is to make the next :hg:`status` invocation
3234 One use of this command is to make the next :hg:`status` invocation
3227 check the actual file content.
3235 check the actual file content.
3228 """
3236 """
3229 ctx = scmutil.revsingle(repo, rev)
3237 ctx = scmutil.revsingle(repo, rev)
3230 with repo.wlock():
3238 with repo.wlock():
3231 dirstate = repo.dirstate
3239 dirstate = repo.dirstate
3232 changedfiles = None
3240 changedfiles = None
3233 # See command doc for what minimal does.
3241 # See command doc for what minimal does.
3234 if opts.get('minimal'):
3242 if opts.get('minimal'):
3235 manifestfiles = set(ctx.manifest().keys())
3243 manifestfiles = set(ctx.manifest().keys())
3236 dirstatefiles = set(dirstate)
3244 dirstatefiles = set(dirstate)
3237 manifestonly = manifestfiles - dirstatefiles
3245 manifestonly = manifestfiles - dirstatefiles
3238 dsonly = dirstatefiles - manifestfiles
3246 dsonly = dirstatefiles - manifestfiles
3239 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
3247 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
3240 changedfiles = manifestonly | dsnotadded
3248 changedfiles = manifestonly | dsnotadded
3241
3249
3242 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
3250 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
3243
3251
3244 @command('debugrebuildfncache', [], '')
3252 @command('debugrebuildfncache', [], '')
3245 def debugrebuildfncache(ui, repo):
3253 def debugrebuildfncache(ui, repo):
3246 """rebuild the fncache file"""
3254 """rebuild the fncache file"""
3247 repair.rebuildfncache(ui, repo)
3255 repair.rebuildfncache(ui, repo)
3248
3256
3249 @command('debugrename',
3257 @command('debugrename',
3250 [('r', 'rev', '', _('revision to debug'), _('REV'))],
3258 [('r', 'rev', '', _('revision to debug'), _('REV'))],
3251 _('[-r REV] FILE'))
3259 _('[-r REV] FILE'))
3252 def debugrename(ui, repo, file1, *pats, **opts):
3260 def debugrename(ui, repo, file1, *pats, **opts):
3253 """dump rename information"""
3261 """dump rename information"""
3254
3262
3255 ctx = scmutil.revsingle(repo, opts.get('rev'))
3263 ctx = scmutil.revsingle(repo, opts.get('rev'))
3256 m = scmutil.match(ctx, (file1,) + pats, opts)
3264 m = scmutil.match(ctx, (file1,) + pats, opts)
3257 for abs in ctx.walk(m):
3265 for abs in ctx.walk(m):
3258 fctx = ctx[abs]
3266 fctx = ctx[abs]
3259 o = fctx.filelog().renamed(fctx.filenode())
3267 o = fctx.filelog().renamed(fctx.filenode())
3260 rel = m.rel(abs)
3268 rel = m.rel(abs)
3261 if o:
3269 if o:
3262 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
3270 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
3263 else:
3271 else:
3264 ui.write(_("%s not renamed\n") % rel)
3272 ui.write(_("%s not renamed\n") % rel)
3265
3273
3266 @command('debugrevlog', debugrevlogopts +
3274 @command('debugrevlog', debugrevlogopts +
3267 [('d', 'dump', False, _('dump index data'))],
3275 [('d', 'dump', False, _('dump index data'))],
3268 _('-c|-m|FILE'),
3276 _('-c|-m|FILE'),
3269 optionalrepo=True)
3277 optionalrepo=True)
3270 def debugrevlog(ui, repo, file_=None, **opts):
3278 def debugrevlog(ui, repo, file_=None, **opts):
3271 """show data and statistics about a revlog"""
3279 """show data and statistics about a revlog"""
3272 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
3280 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
3273
3281
3274 if opts.get("dump"):
3282 if opts.get("dump"):
3275 numrevs = len(r)
3283 numrevs = len(r)
3276 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
3284 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
3277 " rawsize totalsize compression heads chainlen\n")
3285 " rawsize totalsize compression heads chainlen\n")
3278 ts = 0
3286 ts = 0
3279 heads = set()
3287 heads = set()
3280
3288
3281 for rev in xrange(numrevs):
3289 for rev in xrange(numrevs):
3282 dbase = r.deltaparent(rev)
3290 dbase = r.deltaparent(rev)
3283 if dbase == -1:
3291 if dbase == -1:
3284 dbase = rev
3292 dbase = rev
3285 cbase = r.chainbase(rev)
3293 cbase = r.chainbase(rev)
3286 clen = r.chainlen(rev)
3294 clen = r.chainlen(rev)
3287 p1, p2 = r.parentrevs(rev)
3295 p1, p2 = r.parentrevs(rev)
3288 rs = r.rawsize(rev)
3296 rs = r.rawsize(rev)
3289 ts = ts + rs
3297 ts = ts + rs
3290 heads -= set(r.parentrevs(rev))
3298 heads -= set(r.parentrevs(rev))
3291 heads.add(rev)
3299 heads.add(rev)
3292 try:
3300 try:
3293 compression = ts / r.end(rev)
3301 compression = ts / r.end(rev)
3294 except ZeroDivisionError:
3302 except ZeroDivisionError:
3295 compression = 0
3303 compression = 0
3296 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
3304 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
3297 "%11d %5d %8d\n" %
3305 "%11d %5d %8d\n" %
3298 (rev, p1, p2, r.start(rev), r.end(rev),
3306 (rev, p1, p2, r.start(rev), r.end(rev),
3299 r.start(dbase), r.start(cbase),
3307 r.start(dbase), r.start(cbase),
3300 r.start(p1), r.start(p2),
3308 r.start(p1), r.start(p2),
3301 rs, ts, compression, len(heads), clen))
3309 rs, ts, compression, len(heads), clen))
3302 return 0
3310 return 0
3303
3311
3304 v = r.version
3312 v = r.version
3305 format = v & 0xFFFF
3313 format = v & 0xFFFF
3306 flags = []
3314 flags = []
3307 gdelta = False
3315 gdelta = False
3308 if v & revlog.REVLOGNGINLINEDATA:
3316 if v & revlog.REVLOGNGINLINEDATA:
3309 flags.append('inline')
3317 flags.append('inline')
3310 if v & revlog.REVLOGGENERALDELTA:
3318 if v & revlog.REVLOGGENERALDELTA:
3311 gdelta = True
3319 gdelta = True
3312 flags.append('generaldelta')
3320 flags.append('generaldelta')
3313 if not flags:
3321 if not flags:
3314 flags = ['(none)']
3322 flags = ['(none)']
3315
3323
3316 nummerges = 0
3324 nummerges = 0
3317 numfull = 0
3325 numfull = 0
3318 numprev = 0
3326 numprev = 0
3319 nump1 = 0
3327 nump1 = 0
3320 nump2 = 0
3328 nump2 = 0
3321 numother = 0
3329 numother = 0
3322 nump1prev = 0
3330 nump1prev = 0
3323 nump2prev = 0
3331 nump2prev = 0
3324 chainlengths = []
3332 chainlengths = []
3325
3333
3326 datasize = [None, 0, 0L]
3334 datasize = [None, 0, 0L]
3327 fullsize = [None, 0, 0L]
3335 fullsize = [None, 0, 0L]
3328 deltasize = [None, 0, 0L]
3336 deltasize = [None, 0, 0L]
3329
3337
3330 def addsize(size, l):
3338 def addsize(size, l):
3331 if l[0] is None or size < l[0]:
3339 if l[0] is None or size < l[0]:
3332 l[0] = size
3340 l[0] = size
3333 if size > l[1]:
3341 if size > l[1]:
3334 l[1] = size
3342 l[1] = size
3335 l[2] += size
3343 l[2] += size
3336
3344
3337 numrevs = len(r)
3345 numrevs = len(r)
3338 for rev in xrange(numrevs):
3346 for rev in xrange(numrevs):
3339 p1, p2 = r.parentrevs(rev)
3347 p1, p2 = r.parentrevs(rev)
3340 delta = r.deltaparent(rev)
3348 delta = r.deltaparent(rev)
3341 if format > 0:
3349 if format > 0:
3342 addsize(r.rawsize(rev), datasize)
3350 addsize(r.rawsize(rev), datasize)
3343 if p2 != nullrev:
3351 if p2 != nullrev:
3344 nummerges += 1
3352 nummerges += 1
3345 size = r.length(rev)
3353 size = r.length(rev)
3346 if delta == nullrev:
3354 if delta == nullrev:
3347 chainlengths.append(0)
3355 chainlengths.append(0)
3348 numfull += 1
3356 numfull += 1
3349 addsize(size, fullsize)
3357 addsize(size, fullsize)
3350 else:
3358 else:
3351 chainlengths.append(chainlengths[delta] + 1)
3359 chainlengths.append(chainlengths[delta] + 1)
3352 addsize(size, deltasize)
3360 addsize(size, deltasize)
3353 if delta == rev - 1:
3361 if delta == rev - 1:
3354 numprev += 1
3362 numprev += 1
3355 if delta == p1:
3363 if delta == p1:
3356 nump1prev += 1
3364 nump1prev += 1
3357 elif delta == p2:
3365 elif delta == p2:
3358 nump2prev += 1
3366 nump2prev += 1
3359 elif delta == p1:
3367 elif delta == p1:
3360 nump1 += 1
3368 nump1 += 1
3361 elif delta == p2:
3369 elif delta == p2:
3362 nump2 += 1
3370 nump2 += 1
3363 elif delta != nullrev:
3371 elif delta != nullrev:
3364 numother += 1
3372 numother += 1
3365
3373
3366 # Adjust size min value for empty cases
3374 # Adjust size min value for empty cases
3367 for size in (datasize, fullsize, deltasize):
3375 for size in (datasize, fullsize, deltasize):
3368 if size[0] is None:
3376 if size[0] is None:
3369 size[0] = 0
3377 size[0] = 0
3370
3378
3371 numdeltas = numrevs - numfull
3379 numdeltas = numrevs - numfull
3372 numoprev = numprev - nump1prev - nump2prev
3380 numoprev = numprev - nump1prev - nump2prev
3373 totalrawsize = datasize[2]
3381 totalrawsize = datasize[2]
3374 datasize[2] /= numrevs
3382 datasize[2] /= numrevs
3375 fulltotal = fullsize[2]
3383 fulltotal = fullsize[2]
3376 fullsize[2] /= numfull
3384 fullsize[2] /= numfull
3377 deltatotal = deltasize[2]
3385 deltatotal = deltasize[2]
3378 if numrevs - numfull > 0:
3386 if numrevs - numfull > 0:
3379 deltasize[2] /= numrevs - numfull
3387 deltasize[2] /= numrevs - numfull
3380 totalsize = fulltotal + deltatotal
3388 totalsize = fulltotal + deltatotal
3381 avgchainlen = sum(chainlengths) / numrevs
3389 avgchainlen = sum(chainlengths) / numrevs
3382 maxchainlen = max(chainlengths)
3390 maxchainlen = max(chainlengths)
3383 compratio = 1
3391 compratio = 1
3384 if totalsize:
3392 if totalsize:
3385 compratio = totalrawsize / totalsize
3393 compratio = totalrawsize / totalsize
3386
3394
3387 basedfmtstr = '%%%dd\n'
3395 basedfmtstr = '%%%dd\n'
3388 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3396 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3389
3397
3390 def dfmtstr(max):
3398 def dfmtstr(max):
3391 return basedfmtstr % len(str(max))
3399 return basedfmtstr % len(str(max))
3392 def pcfmtstr(max, padding=0):
3400 def pcfmtstr(max, padding=0):
3393 return basepcfmtstr % (len(str(max)), ' ' * padding)
3401 return basepcfmtstr % (len(str(max)), ' ' * padding)
3394
3402
3395 def pcfmt(value, total):
3403 def pcfmt(value, total):
3396 if total:
3404 if total:
3397 return (value, 100 * float(value) / total)
3405 return (value, 100 * float(value) / total)
3398 else:
3406 else:
3399 return value, 100.0
3407 return value, 100.0
3400
3408
3401 ui.write(('format : %d\n') % format)
3409 ui.write(('format : %d\n') % format)
3402 ui.write(('flags : %s\n') % ', '.join(flags))
3410 ui.write(('flags : %s\n') % ', '.join(flags))
3403
3411
3404 ui.write('\n')
3412 ui.write('\n')
3405 fmt = pcfmtstr(totalsize)
3413 fmt = pcfmtstr(totalsize)
3406 fmt2 = dfmtstr(totalsize)
3414 fmt2 = dfmtstr(totalsize)
3407 ui.write(('revisions : ') + fmt2 % numrevs)
3415 ui.write(('revisions : ') + fmt2 % numrevs)
3408 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3416 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3409 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3417 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3410 ui.write(('revisions : ') + fmt2 % numrevs)
3418 ui.write(('revisions : ') + fmt2 % numrevs)
3411 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3419 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3412 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3420 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3413 ui.write(('revision size : ') + fmt2 % totalsize)
3421 ui.write(('revision size : ') + fmt2 % totalsize)
3414 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3422 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3415 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3423 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3416
3424
3417 ui.write('\n')
3425 ui.write('\n')
3418 fmt = dfmtstr(max(avgchainlen, compratio))
3426 fmt = dfmtstr(max(avgchainlen, compratio))
3419 ui.write(('avg chain length : ') + fmt % avgchainlen)
3427 ui.write(('avg chain length : ') + fmt % avgchainlen)
3420 ui.write(('max chain length : ') + fmt % maxchainlen)
3428 ui.write(('max chain length : ') + fmt % maxchainlen)
3421 ui.write(('compression ratio : ') + fmt % compratio)
3429 ui.write(('compression ratio : ') + fmt % compratio)
3422
3430
3423 if format > 0:
3431 if format > 0:
3424 ui.write('\n')
3432 ui.write('\n')
3425 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
3433 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
3426 % tuple(datasize))
3434 % tuple(datasize))
3427 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
3435 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
3428 % tuple(fullsize))
3436 % tuple(fullsize))
3429 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3437 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3430 % tuple(deltasize))
3438 % tuple(deltasize))
3431
3439
3432 if numdeltas > 0:
3440 if numdeltas > 0:
3433 ui.write('\n')
3441 ui.write('\n')
3434 fmt = pcfmtstr(numdeltas)
3442 fmt = pcfmtstr(numdeltas)
3435 fmt2 = pcfmtstr(numdeltas, 4)
3443 fmt2 = pcfmtstr(numdeltas, 4)
3436 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3444 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3437 if numprev > 0:
3445 if numprev > 0:
3438 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3446 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3439 numprev))
3447 numprev))
3440 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3448 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3441 numprev))
3449 numprev))
3442 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3450 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3443 numprev))
3451 numprev))
3444 if gdelta:
3452 if gdelta:
3445 ui.write(('deltas against p1 : ')
3453 ui.write(('deltas against p1 : ')
3446 + fmt % pcfmt(nump1, numdeltas))
3454 + fmt % pcfmt(nump1, numdeltas))
3447 ui.write(('deltas against p2 : ')
3455 ui.write(('deltas against p2 : ')
3448 + fmt % pcfmt(nump2, numdeltas))
3456 + fmt % pcfmt(nump2, numdeltas))
3449 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3457 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3450 numdeltas))
3458 numdeltas))
3451
3459
3452 @command('debugrevspec',
3460 @command('debugrevspec',
3453 [('', 'optimize', None, _('print parsed tree after optimizing'))],
3461 [('', 'optimize', None, _('print parsed tree after optimizing'))],
3454 ('REVSPEC'))
3462 ('REVSPEC'))
3455 def debugrevspec(ui, repo, expr, **opts):
3463 def debugrevspec(ui, repo, expr, **opts):
3456 """parse and apply a revision specification
3464 """parse and apply a revision specification
3457
3465
3458 Use --verbose to print the parsed tree before and after aliases
3466 Use --verbose to print the parsed tree before and after aliases
3459 expansion.
3467 expansion.
3460 """
3468 """
3461 if ui.verbose:
3469 if ui.verbose:
3462 tree = revset.parse(expr, lookup=repo.__contains__)
3470 tree = revset.parse(expr, lookup=repo.__contains__)
3463 ui.note(revset.prettyformat(tree), "\n")
3471 ui.note(revset.prettyformat(tree), "\n")
3464 newtree = revset.findaliases(ui, tree)
3472 newtree = revset.findaliases(ui, tree)
3465 if newtree != tree:
3473 if newtree != tree:
3466 ui.note("* expanded:\n", revset.prettyformat(newtree), "\n")
3474 ui.note("* expanded:\n", revset.prettyformat(newtree), "\n")
3467 tree = newtree
3475 tree = newtree
3468 newtree = revset.foldconcat(tree)
3476 newtree = revset.foldconcat(tree)
3469 if newtree != tree:
3477 if newtree != tree:
3470 ui.note("* concatenated:\n", revset.prettyformat(newtree), "\n")
3478 ui.note("* concatenated:\n", revset.prettyformat(newtree), "\n")
3471 if opts["optimize"]:
3479 if opts["optimize"]:
3472 weight, optimizedtree = revset.optimize(newtree, True)
3480 weight, optimizedtree = revset.optimize(newtree, True)
3473 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
3481 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
3474 func = revset.match(ui, expr, repo)
3482 func = revset.match(ui, expr, repo)
3475 revs = func(repo)
3483 revs = func(repo)
3476 if ui.verbose:
3484 if ui.verbose:
3477 ui.note("* set:\n", revset.prettyformatset(revs), "\n")
3485 ui.note("* set:\n", revset.prettyformatset(revs), "\n")
3478 for c in revs:
3486 for c in revs:
3479 ui.write("%s\n" % c)
3487 ui.write("%s\n" % c)
3480
3488
3481 @command('debugsetparents', [], _('REV1 [REV2]'))
3489 @command('debugsetparents', [], _('REV1 [REV2]'))
3482 def debugsetparents(ui, repo, rev1, rev2=None):
3490 def debugsetparents(ui, repo, rev1, rev2=None):
3483 """manually set the parents of the current working directory
3491 """manually set the parents of the current working directory
3484
3492
3485 This is useful for writing repository conversion tools, but should
3493 This is useful for writing repository conversion tools, but should
3486 be used with care. For example, neither the working directory nor the
3494 be used with care. For example, neither the working directory nor the
3487 dirstate is updated, so file status may be incorrect after running this
3495 dirstate is updated, so file status may be incorrect after running this
3488 command.
3496 command.
3489
3497
3490 Returns 0 on success.
3498 Returns 0 on success.
3491 """
3499 """
3492
3500
3493 r1 = scmutil.revsingle(repo, rev1).node()
3501 r1 = scmutil.revsingle(repo, rev1).node()
3494 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3502 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3495
3503
3496 with repo.wlock():
3504 with repo.wlock():
3497 repo.dirstate.beginparentchange()
3505 repo.dirstate.beginparentchange()
3498 repo.setparents(r1, r2)
3506 repo.setparents(r1, r2)
3499 repo.dirstate.endparentchange()
3507 repo.dirstate.endparentchange()
3500
3508
3501 @command('debugdirstate|debugstate',
3509 @command('debugdirstate|debugstate',
3502 [('', 'nodates', None, _('do not display the saved mtime')),
3510 [('', 'nodates', None, _('do not display the saved mtime')),
3503 ('', 'datesort', None, _('sort by saved mtime'))],
3511 ('', 'datesort', None, _('sort by saved mtime'))],
3504 _('[OPTION]...'))
3512 _('[OPTION]...'))
3505 def debugstate(ui, repo, **opts):
3513 def debugstate(ui, repo, **opts):
3506 """show the contents of the current dirstate"""
3514 """show the contents of the current dirstate"""
3507
3515
3508 nodates = opts.get('nodates')
3516 nodates = opts.get('nodates')
3509 datesort = opts.get('datesort')
3517 datesort = opts.get('datesort')
3510
3518
3511 timestr = ""
3519 timestr = ""
3512 if datesort:
3520 if datesort:
3513 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
3521 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
3514 else:
3522 else:
3515 keyfunc = None # sort by filename
3523 keyfunc = None # sort by filename
3516 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3524 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3517 if ent[3] == -1:
3525 if ent[3] == -1:
3518 timestr = 'unset '
3526 timestr = 'unset '
3519 elif nodates:
3527 elif nodates:
3520 timestr = 'set '
3528 timestr = 'set '
3521 else:
3529 else:
3522 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3530 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3523 time.localtime(ent[3]))
3531 time.localtime(ent[3]))
3524 if ent[1] & 0o20000:
3532 if ent[1] & 0o20000:
3525 mode = 'lnk'
3533 mode = 'lnk'
3526 else:
3534 else:
3527 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3535 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3528 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
3536 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
3529 for f in repo.dirstate.copies():
3537 for f in repo.dirstate.copies():
3530 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3538 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3531
3539
3532 @command('debugsub',
3540 @command('debugsub',
3533 [('r', 'rev', '',
3541 [('r', 'rev', '',
3534 _('revision to check'), _('REV'))],
3542 _('revision to check'), _('REV'))],
3535 _('[-r REV] [REV]'))
3543 _('[-r REV] [REV]'))
3536 def debugsub(ui, repo, rev=None):
3544 def debugsub(ui, repo, rev=None):
3537 ctx = scmutil.revsingle(repo, rev, None)
3545 ctx = scmutil.revsingle(repo, rev, None)
3538 for k, v in sorted(ctx.substate.items()):
3546 for k, v in sorted(ctx.substate.items()):
3539 ui.write(('path %s\n') % k)
3547 ui.write(('path %s\n') % k)
3540 ui.write((' source %s\n') % v[0])
3548 ui.write((' source %s\n') % v[0])
3541 ui.write((' revision %s\n') % v[1])
3549 ui.write((' revision %s\n') % v[1])
3542
3550
3543 @command('debugsuccessorssets',
3551 @command('debugsuccessorssets',
3544 [],
3552 [],
3545 _('[REV]'))
3553 _('[REV]'))
3546 def debugsuccessorssets(ui, repo, *revs):
3554 def debugsuccessorssets(ui, repo, *revs):
3547 """show set of successors for revision
3555 """show set of successors for revision
3548
3556
3549 A successors set of changeset A is a consistent group of revisions that
3557 A successors set of changeset A is a consistent group of revisions that
3550 succeed A. It contains non-obsolete changesets only.
3558 succeed A. It contains non-obsolete changesets only.
3551
3559
3552 In most cases a changeset A has a single successors set containing a single
3560 In most cases a changeset A has a single successors set containing a single
3553 successor (changeset A replaced by A').
3561 successor (changeset A replaced by A').
3554
3562
3555 A changeset that is made obsolete with no successors are called "pruned".
3563 A changeset that is made obsolete with no successors are called "pruned".
3556 Such changesets have no successors sets at all.
3564 Such changesets have no successors sets at all.
3557
3565
3558 A changeset that has been "split" will have a successors set containing
3566 A changeset that has been "split" will have a successors set containing
3559 more than one successor.
3567 more than one successor.
3560
3568
3561 A changeset that has been rewritten in multiple different ways is called
3569 A changeset that has been rewritten in multiple different ways is called
3562 "divergent". Such changesets have multiple successor sets (each of which
3570 "divergent". Such changesets have multiple successor sets (each of which
3563 may also be split, i.e. have multiple successors).
3571 may also be split, i.e. have multiple successors).
3564
3572
3565 Results are displayed as follows::
3573 Results are displayed as follows::
3566
3574
3567 <rev1>
3575 <rev1>
3568 <successors-1A>
3576 <successors-1A>
3569 <rev2>
3577 <rev2>
3570 <successors-2A>
3578 <successors-2A>
3571 <successors-2B1> <successors-2B2> <successors-2B3>
3579 <successors-2B1> <successors-2B2> <successors-2B3>
3572
3580
3573 Here rev2 has two possible (i.e. divergent) successors sets. The first
3581 Here rev2 has two possible (i.e. divergent) successors sets. The first
3574 holds one element, whereas the second holds three (i.e. the changeset has
3582 holds one element, whereas the second holds three (i.e. the changeset has
3575 been split).
3583 been split).
3576 """
3584 """
3577 # passed to successorssets caching computation from one call to another
3585 # passed to successorssets caching computation from one call to another
3578 cache = {}
3586 cache = {}
3579 ctx2str = str
3587 ctx2str = str
3580 node2str = short
3588 node2str = short
3581 if ui.debug():
3589 if ui.debug():
3582 def ctx2str(ctx):
3590 def ctx2str(ctx):
3583 return ctx.hex()
3591 return ctx.hex()
3584 node2str = hex
3592 node2str = hex
3585 for rev in scmutil.revrange(repo, revs):
3593 for rev in scmutil.revrange(repo, revs):
3586 ctx = repo[rev]
3594 ctx = repo[rev]
3587 ui.write('%s\n'% ctx2str(ctx))
3595 ui.write('%s\n'% ctx2str(ctx))
3588 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3596 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3589 if succsset:
3597 if succsset:
3590 ui.write(' ')
3598 ui.write(' ')
3591 ui.write(node2str(succsset[0]))
3599 ui.write(node2str(succsset[0]))
3592 for node in succsset[1:]:
3600 for node in succsset[1:]:
3593 ui.write(' ')
3601 ui.write(' ')
3594 ui.write(node2str(node))
3602 ui.write(node2str(node))
3595 ui.write('\n')
3603 ui.write('\n')
3596
3604
3597 @command('debugtemplate',
3605 @command('debugtemplate',
3598 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
3606 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
3599 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
3607 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
3600 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
3608 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
3601 optionalrepo=True)
3609 optionalrepo=True)
3602 def debugtemplate(ui, repo, tmpl, **opts):
3610 def debugtemplate(ui, repo, tmpl, **opts):
3603 """parse and apply a template
3611 """parse and apply a template
3604
3612
3605 If -r/--rev is given, the template is processed as a log template and
3613 If -r/--rev is given, the template is processed as a log template and
3606 applied to the given changesets. Otherwise, it is processed as a generic
3614 applied to the given changesets. Otherwise, it is processed as a generic
3607 template.
3615 template.
3608
3616
3609 Use --verbose to print the parsed tree.
3617 Use --verbose to print the parsed tree.
3610 """
3618 """
3611 revs = None
3619 revs = None
3612 if opts['rev']:
3620 if opts['rev']:
3613 if repo is None:
3621 if repo is None:
3614 raise error.RepoError(_('there is no Mercurial repository here '
3622 raise error.RepoError(_('there is no Mercurial repository here '
3615 '(.hg not found)'))
3623 '(.hg not found)'))
3616 revs = scmutil.revrange(repo, opts['rev'])
3624 revs = scmutil.revrange(repo, opts['rev'])
3617
3625
3618 props = {}
3626 props = {}
3619 for d in opts['define']:
3627 for d in opts['define']:
3620 try:
3628 try:
3621 k, v = (e.strip() for e in d.split('=', 1))
3629 k, v = (e.strip() for e in d.split('=', 1))
3622 if not k:
3630 if not k:
3623 raise ValueError
3631 raise ValueError
3624 props[k] = v
3632 props[k] = v
3625 except ValueError:
3633 except ValueError:
3626 raise error.Abort(_('malformed keyword definition: %s') % d)
3634 raise error.Abort(_('malformed keyword definition: %s') % d)
3627
3635
3628 if ui.verbose:
3636 if ui.verbose:
3629 tree = templater.parse(tmpl)
3637 tree = templater.parse(tmpl)
3630 ui.note(templater.prettyformat(tree), '\n')
3638 ui.note(templater.prettyformat(tree), '\n')
3631
3639
3632 mapfile = None
3640 mapfile = None
3633 if revs is None:
3641 if revs is None:
3634 k = 'debugtemplate'
3642 k = 'debugtemplate'
3635 t = templater.templater(mapfile)
3643 t = templater.templater(mapfile)
3636 t.cache[k] = tmpl
3644 t.cache[k] = tmpl
3637 ui.write(templater.stringify(t(k, **props)))
3645 ui.write(templater.stringify(t(k, **props)))
3638 else:
3646 else:
3639 displayer = cmdutil.changeset_templater(ui, repo, None, opts, tmpl,
3647 displayer = cmdutil.changeset_templater(ui, repo, None, opts, tmpl,
3640 mapfile, buffered=False)
3648 mapfile, buffered=False)
3641 for r in revs:
3649 for r in revs:
3642 displayer.show(repo[r], **props)
3650 displayer.show(repo[r], **props)
3643 displayer.close()
3651 displayer.close()
3644
3652
3645 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3653 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3646 def debugwalk(ui, repo, *pats, **opts):
3654 def debugwalk(ui, repo, *pats, **opts):
3647 """show how files match on given patterns"""
3655 """show how files match on given patterns"""
3648 m = scmutil.match(repo[None], pats, opts)
3656 m = scmutil.match(repo[None], pats, opts)
3649 items = list(repo.walk(m))
3657 items = list(repo.walk(m))
3650 if not items:
3658 if not items:
3651 return
3659 return
3652 f = lambda fn: fn
3660 f = lambda fn: fn
3653 if ui.configbool('ui', 'slash') and os.sep != '/':
3661 if ui.configbool('ui', 'slash') and os.sep != '/':
3654 f = lambda fn: util.normpath(fn)
3662 f = lambda fn: util.normpath(fn)
3655 fmt = 'f %%-%ds %%-%ds %%s' % (
3663 fmt = 'f %%-%ds %%-%ds %%s' % (
3656 max([len(abs) for abs in items]),
3664 max([len(abs) for abs in items]),
3657 max([len(m.rel(abs)) for abs in items]))
3665 max([len(m.rel(abs)) for abs in items]))
3658 for abs in items:
3666 for abs in items:
3659 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3667 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3660 ui.write("%s\n" % line.rstrip())
3668 ui.write("%s\n" % line.rstrip())
3661
3669
3662 @command('debugwireargs',
3670 @command('debugwireargs',
3663 [('', 'three', '', 'three'),
3671 [('', 'three', '', 'three'),
3664 ('', 'four', '', 'four'),
3672 ('', 'four', '', 'four'),
3665 ('', 'five', '', 'five'),
3673 ('', 'five', '', 'five'),
3666 ] + remoteopts,
3674 ] + remoteopts,
3667 _('REPO [OPTIONS]... [ONE [TWO]]'),
3675 _('REPO [OPTIONS]... [ONE [TWO]]'),
3668 norepo=True)
3676 norepo=True)
3669 def debugwireargs(ui, repopath, *vals, **opts):
3677 def debugwireargs(ui, repopath, *vals, **opts):
3670 repo = hg.peer(ui, opts, repopath)
3678 repo = hg.peer(ui, opts, repopath)
3671 for opt in remoteopts:
3679 for opt in remoteopts:
3672 del opts[opt[1]]
3680 del opts[opt[1]]
3673 args = {}
3681 args = {}
3674 for k, v in opts.iteritems():
3682 for k, v in opts.iteritems():
3675 if v:
3683 if v:
3676 args[k] = v
3684 args[k] = v
3677 # run twice to check that we don't mess up the stream for the next command
3685 # run twice to check that we don't mess up the stream for the next command
3678 res1 = repo.debugwireargs(*vals, **args)
3686 res1 = repo.debugwireargs(*vals, **args)
3679 res2 = repo.debugwireargs(*vals, **args)
3687 res2 = repo.debugwireargs(*vals, **args)
3680 ui.write("%s\n" % res1)
3688 ui.write("%s\n" % res1)
3681 if res1 != res2:
3689 if res1 != res2:
3682 ui.warn("%s\n" % res2)
3690 ui.warn("%s\n" % res2)
3683
3691
3684 @command('^diff',
3692 @command('^diff',
3685 [('r', 'rev', [], _('revision'), _('REV')),
3693 [('r', 'rev', [], _('revision'), _('REV')),
3686 ('c', 'change', '', _('change made by revision'), _('REV'))
3694 ('c', 'change', '', _('change made by revision'), _('REV'))
3687 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3695 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3688 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3696 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3689 inferrepo=True)
3697 inferrepo=True)
3690 def diff(ui, repo, *pats, **opts):
3698 def diff(ui, repo, *pats, **opts):
3691 """diff repository (or selected files)
3699 """diff repository (or selected files)
3692
3700
3693 Show differences between revisions for the specified files.
3701 Show differences between revisions for the specified files.
3694
3702
3695 Differences between files are shown using the unified diff format.
3703 Differences between files are shown using the unified diff format.
3696
3704
3697 .. note::
3705 .. note::
3698
3706
3699 :hg:`diff` may generate unexpected results for merges, as it will
3707 :hg:`diff` may generate unexpected results for merges, as it will
3700 default to comparing against the working directory's first
3708 default to comparing against the working directory's first
3701 parent changeset if no revisions are specified.
3709 parent changeset if no revisions are specified.
3702
3710
3703 When two revision arguments are given, then changes are shown
3711 When two revision arguments are given, then changes are shown
3704 between those revisions. If only one revision is specified then
3712 between those revisions. If only one revision is specified then
3705 that revision is compared to the working directory, and, when no
3713 that revision is compared to the working directory, and, when no
3706 revisions are specified, the working directory files are compared
3714 revisions are specified, the working directory files are compared
3707 to its first parent.
3715 to its first parent.
3708
3716
3709 Alternatively you can specify -c/--change with a revision to see
3717 Alternatively you can specify -c/--change with a revision to see
3710 the changes in that changeset relative to its first parent.
3718 the changes in that changeset relative to its first parent.
3711
3719
3712 Without the -a/--text option, diff will avoid generating diffs of
3720 Without the -a/--text option, diff will avoid generating diffs of
3713 files it detects as binary. With -a, diff will generate a diff
3721 files it detects as binary. With -a, diff will generate a diff
3714 anyway, probably with undesirable results.
3722 anyway, probably with undesirable results.
3715
3723
3716 Use the -g/--git option to generate diffs in the git extended diff
3724 Use the -g/--git option to generate diffs in the git extended diff
3717 format. For more information, read :hg:`help diffs`.
3725 format. For more information, read :hg:`help diffs`.
3718
3726
3719 .. container:: verbose
3727 .. container:: verbose
3720
3728
3721 Examples:
3729 Examples:
3722
3730
3723 - compare a file in the current working directory to its parent::
3731 - compare a file in the current working directory to its parent::
3724
3732
3725 hg diff foo.c
3733 hg diff foo.c
3726
3734
3727 - compare two historical versions of a directory, with rename info::
3735 - compare two historical versions of a directory, with rename info::
3728
3736
3729 hg diff --git -r 1.0:1.2 lib/
3737 hg diff --git -r 1.0:1.2 lib/
3730
3738
3731 - get change stats relative to the last change on some date::
3739 - get change stats relative to the last change on some date::
3732
3740
3733 hg diff --stat -r "date('may 2')"
3741 hg diff --stat -r "date('may 2')"
3734
3742
3735 - diff all newly-added files that contain a keyword::
3743 - diff all newly-added files that contain a keyword::
3736
3744
3737 hg diff "set:added() and grep(GNU)"
3745 hg diff "set:added() and grep(GNU)"
3738
3746
3739 - compare a revision and its parents::
3747 - compare a revision and its parents::
3740
3748
3741 hg diff -c 9353 # compare against first parent
3749 hg diff -c 9353 # compare against first parent
3742 hg diff -r 9353^:9353 # same using revset syntax
3750 hg diff -r 9353^:9353 # same using revset syntax
3743 hg diff -r 9353^2:9353 # compare against the second parent
3751 hg diff -r 9353^2:9353 # compare against the second parent
3744
3752
3745 Returns 0 on success.
3753 Returns 0 on success.
3746 """
3754 """
3747
3755
3748 revs = opts.get('rev')
3756 revs = opts.get('rev')
3749 change = opts.get('change')
3757 change = opts.get('change')
3750 stat = opts.get('stat')
3758 stat = opts.get('stat')
3751 reverse = opts.get('reverse')
3759 reverse = opts.get('reverse')
3752
3760
3753 if revs and change:
3761 if revs and change:
3754 msg = _('cannot specify --rev and --change at the same time')
3762 msg = _('cannot specify --rev and --change at the same time')
3755 raise error.Abort(msg)
3763 raise error.Abort(msg)
3756 elif change:
3764 elif change:
3757 node2 = scmutil.revsingle(repo, change, None).node()
3765 node2 = scmutil.revsingle(repo, change, None).node()
3758 node1 = repo[node2].p1().node()
3766 node1 = repo[node2].p1().node()
3759 else:
3767 else:
3760 node1, node2 = scmutil.revpair(repo, revs)
3768 node1, node2 = scmutil.revpair(repo, revs)
3761
3769
3762 if reverse:
3770 if reverse:
3763 node1, node2 = node2, node1
3771 node1, node2 = node2, node1
3764
3772
3765 diffopts = patch.diffallopts(ui, opts)
3773 diffopts = patch.diffallopts(ui, opts)
3766 m = scmutil.match(repo[node2], pats, opts)
3774 m = scmutil.match(repo[node2], pats, opts)
3767 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3775 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3768 listsubrepos=opts.get('subrepos'),
3776 listsubrepos=opts.get('subrepos'),
3769 root=opts.get('root'))
3777 root=opts.get('root'))
3770
3778
3771 @command('^export',
3779 @command('^export',
3772 [('o', 'output', '',
3780 [('o', 'output', '',
3773 _('print output to file with formatted name'), _('FORMAT')),
3781 _('print output to file with formatted name'), _('FORMAT')),
3774 ('', 'switch-parent', None, _('diff against the second parent')),
3782 ('', 'switch-parent', None, _('diff against the second parent')),
3775 ('r', 'rev', [], _('revisions to export'), _('REV')),
3783 ('r', 'rev', [], _('revisions to export'), _('REV')),
3776 ] + diffopts,
3784 ] + diffopts,
3777 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3785 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3778 def export(ui, repo, *changesets, **opts):
3786 def export(ui, repo, *changesets, **opts):
3779 """dump the header and diffs for one or more changesets
3787 """dump the header and diffs for one or more changesets
3780
3788
3781 Print the changeset header and diffs for one or more revisions.
3789 Print the changeset header and diffs for one or more revisions.
3782 If no revision is given, the parent of the working directory is used.
3790 If no revision is given, the parent of the working directory is used.
3783
3791
3784 The information shown in the changeset header is: author, date,
3792 The information shown in the changeset header is: author, date,
3785 branch name (if non-default), changeset hash, parent(s) and commit
3793 branch name (if non-default), changeset hash, parent(s) and commit
3786 comment.
3794 comment.
3787
3795
3788 .. note::
3796 .. note::
3789
3797
3790 :hg:`export` may generate unexpected diff output for merge
3798 :hg:`export` may generate unexpected diff output for merge
3791 changesets, as it will compare the merge changeset against its
3799 changesets, as it will compare the merge changeset against its
3792 first parent only.
3800 first parent only.
3793
3801
3794 Output may be to a file, in which case the name of the file is
3802 Output may be to a file, in which case the name of the file is
3795 given using a format string. The formatting rules are as follows:
3803 given using a format string. The formatting rules are as follows:
3796
3804
3797 :``%%``: literal "%" character
3805 :``%%``: literal "%" character
3798 :``%H``: changeset hash (40 hexadecimal digits)
3806 :``%H``: changeset hash (40 hexadecimal digits)
3799 :``%N``: number of patches being generated
3807 :``%N``: number of patches being generated
3800 :``%R``: changeset revision number
3808 :``%R``: changeset revision number
3801 :``%b``: basename of the exporting repository
3809 :``%b``: basename of the exporting repository
3802 :``%h``: short-form changeset hash (12 hexadecimal digits)
3810 :``%h``: short-form changeset hash (12 hexadecimal digits)
3803 :``%m``: first line of the commit message (only alphanumeric characters)
3811 :``%m``: first line of the commit message (only alphanumeric characters)
3804 :``%n``: zero-padded sequence number, starting at 1
3812 :``%n``: zero-padded sequence number, starting at 1
3805 :``%r``: zero-padded changeset revision number
3813 :``%r``: zero-padded changeset revision number
3806
3814
3807 Without the -a/--text option, export will avoid generating diffs
3815 Without the -a/--text option, export will avoid generating diffs
3808 of files it detects as binary. With -a, export will generate a
3816 of files it detects as binary. With -a, export will generate a
3809 diff anyway, probably with undesirable results.
3817 diff anyway, probably with undesirable results.
3810
3818
3811 Use the -g/--git option to generate diffs in the git extended diff
3819 Use the -g/--git option to generate diffs in the git extended diff
3812 format. See :hg:`help diffs` for more information.
3820 format. See :hg:`help diffs` for more information.
3813
3821
3814 With the --switch-parent option, the diff will be against the
3822 With the --switch-parent option, the diff will be against the
3815 second parent. It can be useful to review a merge.
3823 second parent. It can be useful to review a merge.
3816
3824
3817 .. container:: verbose
3825 .. container:: verbose
3818
3826
3819 Examples:
3827 Examples:
3820
3828
3821 - use export and import to transplant a bugfix to the current
3829 - use export and import to transplant a bugfix to the current
3822 branch::
3830 branch::
3823
3831
3824 hg export -r 9353 | hg import -
3832 hg export -r 9353 | hg import -
3825
3833
3826 - export all the changesets between two revisions to a file with
3834 - export all the changesets between two revisions to a file with
3827 rename information::
3835 rename information::
3828
3836
3829 hg export --git -r 123:150 > changes.txt
3837 hg export --git -r 123:150 > changes.txt
3830
3838
3831 - split outgoing changes into a series of patches with
3839 - split outgoing changes into a series of patches with
3832 descriptive names::
3840 descriptive names::
3833
3841
3834 hg export -r "outgoing()" -o "%n-%m.patch"
3842 hg export -r "outgoing()" -o "%n-%m.patch"
3835
3843
3836 Returns 0 on success.
3844 Returns 0 on success.
3837 """
3845 """
3838 changesets += tuple(opts.get('rev', []))
3846 changesets += tuple(opts.get('rev', []))
3839 if not changesets:
3847 if not changesets:
3840 changesets = ['.']
3848 changesets = ['.']
3841 revs = scmutil.revrange(repo, changesets)
3849 revs = scmutil.revrange(repo, changesets)
3842 if not revs:
3850 if not revs:
3843 raise error.Abort(_("export requires at least one changeset"))
3851 raise error.Abort(_("export requires at least one changeset"))
3844 if len(revs) > 1:
3852 if len(revs) > 1:
3845 ui.note(_('exporting patches:\n'))
3853 ui.note(_('exporting patches:\n'))
3846 else:
3854 else:
3847 ui.note(_('exporting patch:\n'))
3855 ui.note(_('exporting patch:\n'))
3848 cmdutil.export(repo, revs, template=opts.get('output'),
3856 cmdutil.export(repo, revs, template=opts.get('output'),
3849 switch_parent=opts.get('switch_parent'),
3857 switch_parent=opts.get('switch_parent'),
3850 opts=patch.diffallopts(ui, opts))
3858 opts=patch.diffallopts(ui, opts))
3851
3859
3852 @command('files',
3860 @command('files',
3853 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3861 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3854 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3862 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3855 ] + walkopts + formatteropts + subrepoopts,
3863 ] + walkopts + formatteropts + subrepoopts,
3856 _('[OPTION]... [PATTERN]...'))
3864 _('[OPTION]... [PATTERN]...'))
3857 def files(ui, repo, *pats, **opts):
3865 def files(ui, repo, *pats, **opts):
3858 """list tracked files
3866 """list tracked files
3859
3867
3860 Print files under Mercurial control in the working directory or
3868 Print files under Mercurial control in the working directory or
3861 specified revision whose names match the given patterns (excluding
3869 specified revision whose names match the given patterns (excluding
3862 removed files).
3870 removed files).
3863
3871
3864 If no patterns are given to match, this command prints the names
3872 If no patterns are given to match, this command prints the names
3865 of all files under Mercurial control in the working directory.
3873 of all files under Mercurial control in the working directory.
3866
3874
3867 .. container:: verbose
3875 .. container:: verbose
3868
3876
3869 Examples:
3877 Examples:
3870
3878
3871 - list all files under the current directory::
3879 - list all files under the current directory::
3872
3880
3873 hg files .
3881 hg files .
3874
3882
3875 - shows sizes and flags for current revision::
3883 - shows sizes and flags for current revision::
3876
3884
3877 hg files -vr .
3885 hg files -vr .
3878
3886
3879 - list all files named README::
3887 - list all files named README::
3880
3888
3881 hg files -I "**/README"
3889 hg files -I "**/README"
3882
3890
3883 - list all binary files::
3891 - list all binary files::
3884
3892
3885 hg files "set:binary()"
3893 hg files "set:binary()"
3886
3894
3887 - find files containing a regular expression::
3895 - find files containing a regular expression::
3888
3896
3889 hg files "set:grep('bob')"
3897 hg files "set:grep('bob')"
3890
3898
3891 - search tracked file contents with xargs and grep::
3899 - search tracked file contents with xargs and grep::
3892
3900
3893 hg files -0 | xargs -0 grep foo
3901 hg files -0 | xargs -0 grep foo
3894
3902
3895 See :hg:`help patterns` and :hg:`help filesets` for more information
3903 See :hg:`help patterns` and :hg:`help filesets` for more information
3896 on specifying file patterns.
3904 on specifying file patterns.
3897
3905
3898 Returns 0 if a match is found, 1 otherwise.
3906 Returns 0 if a match is found, 1 otherwise.
3899
3907
3900 """
3908 """
3901 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3909 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3902
3910
3903 end = '\n'
3911 end = '\n'
3904 if opts.get('print0'):
3912 if opts.get('print0'):
3905 end = '\0'
3913 end = '\0'
3906 fm = ui.formatter('files', opts)
3914 fm = ui.formatter('files', opts)
3907 fmt = '%s' + end
3915 fmt = '%s' + end
3908
3916
3909 m = scmutil.match(ctx, pats, opts)
3917 m = scmutil.match(ctx, pats, opts)
3910 ret = cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3918 ret = cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3911
3919
3912 fm.end()
3920 fm.end()
3913
3921
3914 return ret
3922 return ret
3915
3923
3916 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3924 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3917 def forget(ui, repo, *pats, **opts):
3925 def forget(ui, repo, *pats, **opts):
3918 """forget the specified files on the next commit
3926 """forget the specified files on the next commit
3919
3927
3920 Mark the specified files so they will no longer be tracked
3928 Mark the specified files so they will no longer be tracked
3921 after the next commit.
3929 after the next commit.
3922
3930
3923 This only removes files from the current branch, not from the
3931 This only removes files from the current branch, not from the
3924 entire project history, and it does not delete them from the
3932 entire project history, and it does not delete them from the
3925 working directory.
3933 working directory.
3926
3934
3927 To delete the file from the working directory, see :hg:`remove`.
3935 To delete the file from the working directory, see :hg:`remove`.
3928
3936
3929 To undo a forget before the next commit, see :hg:`add`.
3937 To undo a forget before the next commit, see :hg:`add`.
3930
3938
3931 .. container:: verbose
3939 .. container:: verbose
3932
3940
3933 Examples:
3941 Examples:
3934
3942
3935 - forget newly-added binary files::
3943 - forget newly-added binary files::
3936
3944
3937 hg forget "set:added() and binary()"
3945 hg forget "set:added() and binary()"
3938
3946
3939 - forget files that would be excluded by .hgignore::
3947 - forget files that would be excluded by .hgignore::
3940
3948
3941 hg forget "set:hgignore()"
3949 hg forget "set:hgignore()"
3942
3950
3943 Returns 0 on success.
3951 Returns 0 on success.
3944 """
3952 """
3945
3953
3946 if not pats:
3954 if not pats:
3947 raise error.Abort(_('no files specified'))
3955 raise error.Abort(_('no files specified'))
3948
3956
3949 m = scmutil.match(repo[None], pats, opts)
3957 m = scmutil.match(repo[None], pats, opts)
3950 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3958 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3951 return rejected and 1 or 0
3959 return rejected and 1 or 0
3952
3960
3953 @command(
3961 @command(
3954 'graft',
3962 'graft',
3955 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3963 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3956 ('c', 'continue', False, _('resume interrupted graft')),
3964 ('c', 'continue', False, _('resume interrupted graft')),
3957 ('e', 'edit', False, _('invoke editor on commit messages')),
3965 ('e', 'edit', False, _('invoke editor on commit messages')),
3958 ('', 'log', None, _('append graft info to log message')),
3966 ('', 'log', None, _('append graft info to log message')),
3959 ('f', 'force', False, _('force graft')),
3967 ('f', 'force', False, _('force graft')),
3960 ('D', 'currentdate', False,
3968 ('D', 'currentdate', False,
3961 _('record the current date as commit date')),
3969 _('record the current date as commit date')),
3962 ('U', 'currentuser', False,
3970 ('U', 'currentuser', False,
3963 _('record the current user as committer'), _('DATE'))]
3971 _('record the current user as committer'), _('DATE'))]
3964 + commitopts2 + mergetoolopts + dryrunopts,
3972 + commitopts2 + mergetoolopts + dryrunopts,
3965 _('[OPTION]... [-r REV]... REV...'))
3973 _('[OPTION]... [-r REV]... REV...'))
3966 def graft(ui, repo, *revs, **opts):
3974 def graft(ui, repo, *revs, **opts):
3967 '''copy changes from other branches onto the current branch
3975 '''copy changes from other branches onto the current branch
3968
3976
3969 This command uses Mercurial's merge logic to copy individual
3977 This command uses Mercurial's merge logic to copy individual
3970 changes from other branches without merging branches in the
3978 changes from other branches without merging branches in the
3971 history graph. This is sometimes known as 'backporting' or
3979 history graph. This is sometimes known as 'backporting' or
3972 'cherry-picking'. By default, graft will copy user, date, and
3980 'cherry-picking'. By default, graft will copy user, date, and
3973 description from the source changesets.
3981 description from the source changesets.
3974
3982
3975 Changesets that are ancestors of the current revision, that have
3983 Changesets that are ancestors of the current revision, that have
3976 already been grafted, or that are merges will be skipped.
3984 already been grafted, or that are merges will be skipped.
3977
3985
3978 If --log is specified, log messages will have a comment appended
3986 If --log is specified, log messages will have a comment appended
3979 of the form::
3987 of the form::
3980
3988
3981 (grafted from CHANGESETHASH)
3989 (grafted from CHANGESETHASH)
3982
3990
3983 If --force is specified, revisions will be grafted even if they
3991 If --force is specified, revisions will be grafted even if they
3984 are already ancestors of or have been grafted to the destination.
3992 are already ancestors of or have been grafted to the destination.
3985 This is useful when the revisions have since been backed out.
3993 This is useful when the revisions have since been backed out.
3986
3994
3987 If a graft merge results in conflicts, the graft process is
3995 If a graft merge results in conflicts, the graft process is
3988 interrupted so that the current merge can be manually resolved.
3996 interrupted so that the current merge can be manually resolved.
3989 Once all conflicts are addressed, the graft process can be
3997 Once all conflicts are addressed, the graft process can be
3990 continued with the -c/--continue option.
3998 continued with the -c/--continue option.
3991
3999
3992 .. note::
4000 .. note::
3993
4001
3994 The -c/--continue option does not reapply earlier options, except
4002 The -c/--continue option does not reapply earlier options, except
3995 for --force.
4003 for --force.
3996
4004
3997 .. container:: verbose
4005 .. container:: verbose
3998
4006
3999 Examples:
4007 Examples:
4000
4008
4001 - copy a single change to the stable branch and edit its description::
4009 - copy a single change to the stable branch and edit its description::
4002
4010
4003 hg update stable
4011 hg update stable
4004 hg graft --edit 9393
4012 hg graft --edit 9393
4005
4013
4006 - graft a range of changesets with one exception, updating dates::
4014 - graft a range of changesets with one exception, updating dates::
4007
4015
4008 hg graft -D "2085::2093 and not 2091"
4016 hg graft -D "2085::2093 and not 2091"
4009
4017
4010 - continue a graft after resolving conflicts::
4018 - continue a graft after resolving conflicts::
4011
4019
4012 hg graft -c
4020 hg graft -c
4013
4021
4014 - show the source of a grafted changeset::
4022 - show the source of a grafted changeset::
4015
4023
4016 hg log --debug -r .
4024 hg log --debug -r .
4017
4025
4018 - show revisions sorted by date::
4026 - show revisions sorted by date::
4019
4027
4020 hg log -r 'sort(all(), date)'
4028 hg log -r 'sort(all(), date)'
4021
4029
4022 See :hg:`help revisions` and :hg:`help revsets` for more about
4030 See :hg:`help revisions` and :hg:`help revsets` for more about
4023 specifying revisions.
4031 specifying revisions.
4024
4032
4025 Returns 0 on successful completion.
4033 Returns 0 on successful completion.
4026 '''
4034 '''
4027 with repo.wlock():
4035 with repo.wlock():
4028 return _dograft(ui, repo, *revs, **opts)
4036 return _dograft(ui, repo, *revs, **opts)
4029
4037
4030 def _dograft(ui, repo, *revs, **opts):
4038 def _dograft(ui, repo, *revs, **opts):
4031 if revs and opts['rev']:
4039 if revs and opts['rev']:
4032 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
4040 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
4033 'revision ordering!\n'))
4041 'revision ordering!\n'))
4034
4042
4035 revs = list(revs)
4043 revs = list(revs)
4036 revs.extend(opts['rev'])
4044 revs.extend(opts['rev'])
4037
4045
4038 if not opts.get('user') and opts.get('currentuser'):
4046 if not opts.get('user') and opts.get('currentuser'):
4039 opts['user'] = ui.username()
4047 opts['user'] = ui.username()
4040 if not opts.get('date') and opts.get('currentdate'):
4048 if not opts.get('date') and opts.get('currentdate'):
4041 opts['date'] = "%d %d" % util.makedate()
4049 opts['date'] = "%d %d" % util.makedate()
4042
4050
4043 editor = cmdutil.getcommiteditor(editform='graft', **opts)
4051 editor = cmdutil.getcommiteditor(editform='graft', **opts)
4044
4052
4045 cont = False
4053 cont = False
4046 if opts['continue']:
4054 if opts['continue']:
4047 cont = True
4055 cont = True
4048 if revs:
4056 if revs:
4049 raise error.Abort(_("can't specify --continue and revisions"))
4057 raise error.Abort(_("can't specify --continue and revisions"))
4050 # read in unfinished revisions
4058 # read in unfinished revisions
4051 try:
4059 try:
4052 nodes = repo.vfs.read('graftstate').splitlines()
4060 nodes = repo.vfs.read('graftstate').splitlines()
4053 revs = [repo[node].rev() for node in nodes]
4061 revs = [repo[node].rev() for node in nodes]
4054 except IOError as inst:
4062 except IOError as inst:
4055 if inst.errno != errno.ENOENT:
4063 if inst.errno != errno.ENOENT:
4056 raise
4064 raise
4057 cmdutil.wrongtooltocontinue(repo, _('graft'))
4065 cmdutil.wrongtooltocontinue(repo, _('graft'))
4058 else:
4066 else:
4059 cmdutil.checkunfinished(repo)
4067 cmdutil.checkunfinished(repo)
4060 cmdutil.bailifchanged(repo)
4068 cmdutil.bailifchanged(repo)
4061 if not revs:
4069 if not revs:
4062 raise error.Abort(_('no revisions specified'))
4070 raise error.Abort(_('no revisions specified'))
4063 revs = scmutil.revrange(repo, revs)
4071 revs = scmutil.revrange(repo, revs)
4064
4072
4065 skipped = set()
4073 skipped = set()
4066 # check for merges
4074 # check for merges
4067 for rev in repo.revs('%ld and merge()', revs):
4075 for rev in repo.revs('%ld and merge()', revs):
4068 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
4076 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
4069 skipped.add(rev)
4077 skipped.add(rev)
4070 revs = [r for r in revs if r not in skipped]
4078 revs = [r for r in revs if r not in skipped]
4071 if not revs:
4079 if not revs:
4072 return -1
4080 return -1
4073
4081
4074 # Don't check in the --continue case, in effect retaining --force across
4082 # Don't check in the --continue case, in effect retaining --force across
4075 # --continues. That's because without --force, any revisions we decided to
4083 # --continues. That's because without --force, any revisions we decided to
4076 # skip would have been filtered out here, so they wouldn't have made their
4084 # skip would have been filtered out here, so they wouldn't have made their
4077 # way to the graftstate. With --force, any revisions we would have otherwise
4085 # way to the graftstate. With --force, any revisions we would have otherwise
4078 # skipped would not have been filtered out, and if they hadn't been applied
4086 # skipped would not have been filtered out, and if they hadn't been applied
4079 # already, they'd have been in the graftstate.
4087 # already, they'd have been in the graftstate.
4080 if not (cont or opts.get('force')):
4088 if not (cont or opts.get('force')):
4081 # check for ancestors of dest branch
4089 # check for ancestors of dest branch
4082 crev = repo['.'].rev()
4090 crev = repo['.'].rev()
4083 ancestors = repo.changelog.ancestors([crev], inclusive=True)
4091 ancestors = repo.changelog.ancestors([crev], inclusive=True)
4084 # Cannot use x.remove(y) on smart set, this has to be a list.
4092 # Cannot use x.remove(y) on smart set, this has to be a list.
4085 # XXX make this lazy in the future
4093 # XXX make this lazy in the future
4086 revs = list(revs)
4094 revs = list(revs)
4087 # don't mutate while iterating, create a copy
4095 # don't mutate while iterating, create a copy
4088 for rev in list(revs):
4096 for rev in list(revs):
4089 if rev in ancestors:
4097 if rev in ancestors:
4090 ui.warn(_('skipping ancestor revision %d:%s\n') %
4098 ui.warn(_('skipping ancestor revision %d:%s\n') %
4091 (rev, repo[rev]))
4099 (rev, repo[rev]))
4092 # XXX remove on list is slow
4100 # XXX remove on list is slow
4093 revs.remove(rev)
4101 revs.remove(rev)
4094 if not revs:
4102 if not revs:
4095 return -1
4103 return -1
4096
4104
4097 # analyze revs for earlier grafts
4105 # analyze revs for earlier grafts
4098 ids = {}
4106 ids = {}
4099 for ctx in repo.set("%ld", revs):
4107 for ctx in repo.set("%ld", revs):
4100 ids[ctx.hex()] = ctx.rev()
4108 ids[ctx.hex()] = ctx.rev()
4101 n = ctx.extra().get('source')
4109 n = ctx.extra().get('source')
4102 if n:
4110 if n:
4103 ids[n] = ctx.rev()
4111 ids[n] = ctx.rev()
4104
4112
4105 # check ancestors for earlier grafts
4113 # check ancestors for earlier grafts
4106 ui.debug('scanning for duplicate grafts\n')
4114 ui.debug('scanning for duplicate grafts\n')
4107
4115
4108 for rev in repo.changelog.findmissingrevs(revs, [crev]):
4116 for rev in repo.changelog.findmissingrevs(revs, [crev]):
4109 ctx = repo[rev]
4117 ctx = repo[rev]
4110 n = ctx.extra().get('source')
4118 n = ctx.extra().get('source')
4111 if n in ids:
4119 if n in ids:
4112 try:
4120 try:
4113 r = repo[n].rev()
4121 r = repo[n].rev()
4114 except error.RepoLookupError:
4122 except error.RepoLookupError:
4115 r = None
4123 r = None
4116 if r in revs:
4124 if r in revs:
4117 ui.warn(_('skipping revision %d:%s '
4125 ui.warn(_('skipping revision %d:%s '
4118 '(already grafted to %d:%s)\n')
4126 '(already grafted to %d:%s)\n')
4119 % (r, repo[r], rev, ctx))
4127 % (r, repo[r], rev, ctx))
4120 revs.remove(r)
4128 revs.remove(r)
4121 elif ids[n] in revs:
4129 elif ids[n] in revs:
4122 if r is None:
4130 if r is None:
4123 ui.warn(_('skipping already grafted revision %d:%s '
4131 ui.warn(_('skipping already grafted revision %d:%s '
4124 '(%d:%s also has unknown origin %s)\n')
4132 '(%d:%s also has unknown origin %s)\n')
4125 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
4133 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
4126 else:
4134 else:
4127 ui.warn(_('skipping already grafted revision %d:%s '
4135 ui.warn(_('skipping already grafted revision %d:%s '
4128 '(%d:%s also has origin %d:%s)\n')
4136 '(%d:%s also has origin %d:%s)\n')
4129 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
4137 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
4130 revs.remove(ids[n])
4138 revs.remove(ids[n])
4131 elif ctx.hex() in ids:
4139 elif ctx.hex() in ids:
4132 r = ids[ctx.hex()]
4140 r = ids[ctx.hex()]
4133 ui.warn(_('skipping already grafted revision %d:%s '
4141 ui.warn(_('skipping already grafted revision %d:%s '
4134 '(was grafted from %d:%s)\n') %
4142 '(was grafted from %d:%s)\n') %
4135 (r, repo[r], rev, ctx))
4143 (r, repo[r], rev, ctx))
4136 revs.remove(r)
4144 revs.remove(r)
4137 if not revs:
4145 if not revs:
4138 return -1
4146 return -1
4139
4147
4140 for pos, ctx in enumerate(repo.set("%ld", revs)):
4148 for pos, ctx in enumerate(repo.set("%ld", revs)):
4141 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
4149 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
4142 ctx.description().split('\n', 1)[0])
4150 ctx.description().split('\n', 1)[0])
4143 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
4151 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
4144 if names:
4152 if names:
4145 desc += ' (%s)' % ' '.join(names)
4153 desc += ' (%s)' % ' '.join(names)
4146 ui.status(_('grafting %s\n') % desc)
4154 ui.status(_('grafting %s\n') % desc)
4147 if opts.get('dry_run'):
4155 if opts.get('dry_run'):
4148 continue
4156 continue
4149
4157
4150 source = ctx.extra().get('source')
4158 source = ctx.extra().get('source')
4151 extra = {}
4159 extra = {}
4152 if source:
4160 if source:
4153 extra['source'] = source
4161 extra['source'] = source
4154 extra['intermediate-source'] = ctx.hex()
4162 extra['intermediate-source'] = ctx.hex()
4155 else:
4163 else:
4156 extra['source'] = ctx.hex()
4164 extra['source'] = ctx.hex()
4157 user = ctx.user()
4165 user = ctx.user()
4158 if opts.get('user'):
4166 if opts.get('user'):
4159 user = opts['user']
4167 user = opts['user']
4160 date = ctx.date()
4168 date = ctx.date()
4161 if opts.get('date'):
4169 if opts.get('date'):
4162 date = opts['date']
4170 date = opts['date']
4163 message = ctx.description()
4171 message = ctx.description()
4164 if opts.get('log'):
4172 if opts.get('log'):
4165 message += '\n(grafted from %s)' % ctx.hex()
4173 message += '\n(grafted from %s)' % ctx.hex()
4166
4174
4167 # we don't merge the first commit when continuing
4175 # we don't merge the first commit when continuing
4168 if not cont:
4176 if not cont:
4169 # perform the graft merge with p1(rev) as 'ancestor'
4177 # perform the graft merge with p1(rev) as 'ancestor'
4170 try:
4178 try:
4171 # ui.forcemerge is an internal variable, do not document
4179 # ui.forcemerge is an internal variable, do not document
4172 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4180 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4173 'graft')
4181 'graft')
4174 stats = mergemod.graft(repo, ctx, ctx.p1(),
4182 stats = mergemod.graft(repo, ctx, ctx.p1(),
4175 ['local', 'graft'])
4183 ['local', 'graft'])
4176 finally:
4184 finally:
4177 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
4185 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
4178 # report any conflicts
4186 # report any conflicts
4179 if stats and stats[3] > 0:
4187 if stats and stats[3] > 0:
4180 # write out state for --continue
4188 # write out state for --continue
4181 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
4189 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
4182 repo.vfs.write('graftstate', ''.join(nodelines))
4190 repo.vfs.write('graftstate', ''.join(nodelines))
4183 extra = ''
4191 extra = ''
4184 if opts.get('user'):
4192 if opts.get('user'):
4185 extra += ' --user %s' % opts['user']
4193 extra += ' --user %s' % opts['user']
4186 if opts.get('date'):
4194 if opts.get('date'):
4187 extra += ' --date %s' % opts['date']
4195 extra += ' --date %s' % opts['date']
4188 if opts.get('log'):
4196 if opts.get('log'):
4189 extra += ' --log'
4197 extra += ' --log'
4190 hint=_('use hg resolve and hg graft --continue%s') % extra
4198 hint=_('use hg resolve and hg graft --continue%s') % extra
4191 raise error.Abort(
4199 raise error.Abort(
4192 _("unresolved conflicts, can't continue"),
4200 _("unresolved conflicts, can't continue"),
4193 hint=hint)
4201 hint=hint)
4194 else:
4202 else:
4195 cont = False
4203 cont = False
4196
4204
4197 # commit
4205 # commit
4198 node = repo.commit(text=message, user=user,
4206 node = repo.commit(text=message, user=user,
4199 date=date, extra=extra, editor=editor)
4207 date=date, extra=extra, editor=editor)
4200 if node is None:
4208 if node is None:
4201 ui.warn(
4209 ui.warn(
4202 _('note: graft of %d:%s created no changes to commit\n') %
4210 _('note: graft of %d:%s created no changes to commit\n') %
4203 (ctx.rev(), ctx))
4211 (ctx.rev(), ctx))
4204
4212
4205 # remove state when we complete successfully
4213 # remove state when we complete successfully
4206 if not opts.get('dry_run'):
4214 if not opts.get('dry_run'):
4207 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
4215 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
4208
4216
4209 return 0
4217 return 0
4210
4218
4211 @command('grep',
4219 @command('grep',
4212 [('0', 'print0', None, _('end fields with NUL')),
4220 [('0', 'print0', None, _('end fields with NUL')),
4213 ('', 'all', None, _('print all revisions that match')),
4221 ('', 'all', None, _('print all revisions that match')),
4214 ('a', 'text', None, _('treat all files as text')),
4222 ('a', 'text', None, _('treat all files as text')),
4215 ('f', 'follow', None,
4223 ('f', 'follow', None,
4216 _('follow changeset history,'
4224 _('follow changeset history,'
4217 ' or file history across copies and renames')),
4225 ' or file history across copies and renames')),
4218 ('i', 'ignore-case', None, _('ignore case when matching')),
4226 ('i', 'ignore-case', None, _('ignore case when matching')),
4219 ('l', 'files-with-matches', None,
4227 ('l', 'files-with-matches', None,
4220 _('print only filenames and revisions that match')),
4228 _('print only filenames and revisions that match')),
4221 ('n', 'line-number', None, _('print matching line numbers')),
4229 ('n', 'line-number', None, _('print matching line numbers')),
4222 ('r', 'rev', [],
4230 ('r', 'rev', [],
4223 _('only search files changed within revision range'), _('REV')),
4231 _('only search files changed within revision range'), _('REV')),
4224 ('u', 'user', None, _('list the author (long with -v)')),
4232 ('u', 'user', None, _('list the author (long with -v)')),
4225 ('d', 'date', None, _('list the date (short with -q)')),
4233 ('d', 'date', None, _('list the date (short with -q)')),
4226 ] + walkopts,
4234 ] + walkopts,
4227 _('[OPTION]... PATTERN [FILE]...'),
4235 _('[OPTION]... PATTERN [FILE]...'),
4228 inferrepo=True)
4236 inferrepo=True)
4229 def grep(ui, repo, pattern, *pats, **opts):
4237 def grep(ui, repo, pattern, *pats, **opts):
4230 """search for a pattern in specified files and revisions
4238 """search for a pattern in specified files and revisions
4231
4239
4232 Search revisions of files for a regular expression.
4240 Search revisions of files for a regular expression.
4233
4241
4234 This command behaves differently than Unix grep. It only accepts
4242 This command behaves differently than Unix grep. It only accepts
4235 Python/Perl regexps. It searches repository history, not the
4243 Python/Perl regexps. It searches repository history, not the
4236 working directory. It always prints the revision number in which a
4244 working directory. It always prints the revision number in which a
4237 match appears.
4245 match appears.
4238
4246
4239 By default, grep only prints output for the first revision of a
4247 By default, grep only prints output for the first revision of a
4240 file in which it finds a match. To get it to print every revision
4248 file in which it finds a match. To get it to print every revision
4241 that contains a change in match status ("-" for a match that
4249 that contains a change in match status ("-" for a match that
4242 becomes a non-match, or "+" for a non-match that becomes a match),
4250 becomes a non-match, or "+" for a non-match that becomes a match),
4243 use the --all flag.
4251 use the --all flag.
4244
4252
4245 Returns 0 if a match is found, 1 otherwise.
4253 Returns 0 if a match is found, 1 otherwise.
4246 """
4254 """
4247 reflags = re.M
4255 reflags = re.M
4248 if opts.get('ignore_case'):
4256 if opts.get('ignore_case'):
4249 reflags |= re.I
4257 reflags |= re.I
4250 try:
4258 try:
4251 regexp = util.re.compile(pattern, reflags)
4259 regexp = util.re.compile(pattern, reflags)
4252 except re.error as inst:
4260 except re.error as inst:
4253 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
4261 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
4254 return 1
4262 return 1
4255 sep, eol = ':', '\n'
4263 sep, eol = ':', '\n'
4256 if opts.get('print0'):
4264 if opts.get('print0'):
4257 sep = eol = '\0'
4265 sep = eol = '\0'
4258
4266
4259 getfile = util.lrucachefunc(repo.file)
4267 getfile = util.lrucachefunc(repo.file)
4260
4268
4261 def matchlines(body):
4269 def matchlines(body):
4262 begin = 0
4270 begin = 0
4263 linenum = 0
4271 linenum = 0
4264 while begin < len(body):
4272 while begin < len(body):
4265 match = regexp.search(body, begin)
4273 match = regexp.search(body, begin)
4266 if not match:
4274 if not match:
4267 break
4275 break
4268 mstart, mend = match.span()
4276 mstart, mend = match.span()
4269 linenum += body.count('\n', begin, mstart) + 1
4277 linenum += body.count('\n', begin, mstart) + 1
4270 lstart = body.rfind('\n', begin, mstart) + 1 or begin
4278 lstart = body.rfind('\n', begin, mstart) + 1 or begin
4271 begin = body.find('\n', mend) + 1 or len(body) + 1
4279 begin = body.find('\n', mend) + 1 or len(body) + 1
4272 lend = begin - 1
4280 lend = begin - 1
4273 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
4281 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
4274
4282
4275 class linestate(object):
4283 class linestate(object):
4276 def __init__(self, line, linenum, colstart, colend):
4284 def __init__(self, line, linenum, colstart, colend):
4277 self.line = line
4285 self.line = line
4278 self.linenum = linenum
4286 self.linenum = linenum
4279 self.colstart = colstart
4287 self.colstart = colstart
4280 self.colend = colend
4288 self.colend = colend
4281
4289
4282 def __hash__(self):
4290 def __hash__(self):
4283 return hash((self.linenum, self.line))
4291 return hash((self.linenum, self.line))
4284
4292
4285 def __eq__(self, other):
4293 def __eq__(self, other):
4286 return self.line == other.line
4294 return self.line == other.line
4287
4295
4288 def __iter__(self):
4296 def __iter__(self):
4289 yield (self.line[:self.colstart], '')
4297 yield (self.line[:self.colstart], '')
4290 yield (self.line[self.colstart:self.colend], 'grep.match')
4298 yield (self.line[self.colstart:self.colend], 'grep.match')
4291 rest = self.line[self.colend:]
4299 rest = self.line[self.colend:]
4292 while rest != '':
4300 while rest != '':
4293 match = regexp.search(rest)
4301 match = regexp.search(rest)
4294 if not match:
4302 if not match:
4295 yield (rest, '')
4303 yield (rest, '')
4296 break
4304 break
4297 mstart, mend = match.span()
4305 mstart, mend = match.span()
4298 yield (rest[:mstart], '')
4306 yield (rest[:mstart], '')
4299 yield (rest[mstart:mend], 'grep.match')
4307 yield (rest[mstart:mend], 'grep.match')
4300 rest = rest[mend:]
4308 rest = rest[mend:]
4301
4309
4302 matches = {}
4310 matches = {}
4303 copies = {}
4311 copies = {}
4304 def grepbody(fn, rev, body):
4312 def grepbody(fn, rev, body):
4305 matches[rev].setdefault(fn, [])
4313 matches[rev].setdefault(fn, [])
4306 m = matches[rev][fn]
4314 m = matches[rev][fn]
4307 for lnum, cstart, cend, line in matchlines(body):
4315 for lnum, cstart, cend, line in matchlines(body):
4308 s = linestate(line, lnum, cstart, cend)
4316 s = linestate(line, lnum, cstart, cend)
4309 m.append(s)
4317 m.append(s)
4310
4318
4311 def difflinestates(a, b):
4319 def difflinestates(a, b):
4312 sm = difflib.SequenceMatcher(None, a, b)
4320 sm = difflib.SequenceMatcher(None, a, b)
4313 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
4321 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
4314 if tag == 'insert':
4322 if tag == 'insert':
4315 for i in xrange(blo, bhi):
4323 for i in xrange(blo, bhi):
4316 yield ('+', b[i])
4324 yield ('+', b[i])
4317 elif tag == 'delete':
4325 elif tag == 'delete':
4318 for i in xrange(alo, ahi):
4326 for i in xrange(alo, ahi):
4319 yield ('-', a[i])
4327 yield ('-', a[i])
4320 elif tag == 'replace':
4328 elif tag == 'replace':
4321 for i in xrange(alo, ahi):
4329 for i in xrange(alo, ahi):
4322 yield ('-', a[i])
4330 yield ('-', a[i])
4323 for i in xrange(blo, bhi):
4331 for i in xrange(blo, bhi):
4324 yield ('+', b[i])
4332 yield ('+', b[i])
4325
4333
4326 def display(fn, ctx, pstates, states):
4334 def display(fn, ctx, pstates, states):
4327 rev = ctx.rev()
4335 rev = ctx.rev()
4328 if ui.quiet:
4336 if ui.quiet:
4329 datefunc = util.shortdate
4337 datefunc = util.shortdate
4330 else:
4338 else:
4331 datefunc = util.datestr
4339 datefunc = util.datestr
4332 found = False
4340 found = False
4333 @util.cachefunc
4341 @util.cachefunc
4334 def binary():
4342 def binary():
4335 flog = getfile(fn)
4343 flog = getfile(fn)
4336 return util.binary(flog.read(ctx.filenode(fn)))
4344 return util.binary(flog.read(ctx.filenode(fn)))
4337
4345
4338 if opts.get('all'):
4346 if opts.get('all'):
4339 iter = difflinestates(pstates, states)
4347 iter = difflinestates(pstates, states)
4340 else:
4348 else:
4341 iter = [('', l) for l in states]
4349 iter = [('', l) for l in states]
4342 for change, l in iter:
4350 for change, l in iter:
4343 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
4351 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
4344
4352
4345 if opts.get('line_number'):
4353 if opts.get('line_number'):
4346 cols.append((str(l.linenum), 'grep.linenumber'))
4354 cols.append((str(l.linenum), 'grep.linenumber'))
4347 if opts.get('all'):
4355 if opts.get('all'):
4348 cols.append((change, 'grep.change'))
4356 cols.append((change, 'grep.change'))
4349 if opts.get('user'):
4357 if opts.get('user'):
4350 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
4358 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
4351 if opts.get('date'):
4359 if opts.get('date'):
4352 cols.append((datefunc(ctx.date()), 'grep.date'))
4360 cols.append((datefunc(ctx.date()), 'grep.date'))
4353 for col, label in cols[:-1]:
4361 for col, label in cols[:-1]:
4354 ui.write(col, label=label)
4362 ui.write(col, label=label)
4355 ui.write(sep, label='grep.sep')
4363 ui.write(sep, label='grep.sep')
4356 ui.write(cols[-1][0], label=cols[-1][1])
4364 ui.write(cols[-1][0], label=cols[-1][1])
4357 if not opts.get('files_with_matches'):
4365 if not opts.get('files_with_matches'):
4358 ui.write(sep, label='grep.sep')
4366 ui.write(sep, label='grep.sep')
4359 if not opts.get('text') and binary():
4367 if not opts.get('text') and binary():
4360 ui.write(" Binary file matches")
4368 ui.write(" Binary file matches")
4361 else:
4369 else:
4362 for s, label in l:
4370 for s, label in l:
4363 ui.write(s, label=label)
4371 ui.write(s, label=label)
4364 ui.write(eol)
4372 ui.write(eol)
4365 found = True
4373 found = True
4366 if opts.get('files_with_matches'):
4374 if opts.get('files_with_matches'):
4367 break
4375 break
4368 return found
4376 return found
4369
4377
4370 skip = {}
4378 skip = {}
4371 revfiles = {}
4379 revfiles = {}
4372 matchfn = scmutil.match(repo[None], pats, opts)
4380 matchfn = scmutil.match(repo[None], pats, opts)
4373 found = False
4381 found = False
4374 follow = opts.get('follow')
4382 follow = opts.get('follow')
4375
4383
4376 def prep(ctx, fns):
4384 def prep(ctx, fns):
4377 rev = ctx.rev()
4385 rev = ctx.rev()
4378 pctx = ctx.p1()
4386 pctx = ctx.p1()
4379 parent = pctx.rev()
4387 parent = pctx.rev()
4380 matches.setdefault(rev, {})
4388 matches.setdefault(rev, {})
4381 matches.setdefault(parent, {})
4389 matches.setdefault(parent, {})
4382 files = revfiles.setdefault(rev, [])
4390 files = revfiles.setdefault(rev, [])
4383 for fn in fns:
4391 for fn in fns:
4384 flog = getfile(fn)
4392 flog = getfile(fn)
4385 try:
4393 try:
4386 fnode = ctx.filenode(fn)
4394 fnode = ctx.filenode(fn)
4387 except error.LookupError:
4395 except error.LookupError:
4388 continue
4396 continue
4389
4397
4390 copied = flog.renamed(fnode)
4398 copied = flog.renamed(fnode)
4391 copy = follow and copied and copied[0]
4399 copy = follow and copied and copied[0]
4392 if copy:
4400 if copy:
4393 copies.setdefault(rev, {})[fn] = copy
4401 copies.setdefault(rev, {})[fn] = copy
4394 if fn in skip:
4402 if fn in skip:
4395 if copy:
4403 if copy:
4396 skip[copy] = True
4404 skip[copy] = True
4397 continue
4405 continue
4398 files.append(fn)
4406 files.append(fn)
4399
4407
4400 if fn not in matches[rev]:
4408 if fn not in matches[rev]:
4401 grepbody(fn, rev, flog.read(fnode))
4409 grepbody(fn, rev, flog.read(fnode))
4402
4410
4403 pfn = copy or fn
4411 pfn = copy or fn
4404 if pfn not in matches[parent]:
4412 if pfn not in matches[parent]:
4405 try:
4413 try:
4406 fnode = pctx.filenode(pfn)
4414 fnode = pctx.filenode(pfn)
4407 grepbody(pfn, parent, flog.read(fnode))
4415 grepbody(pfn, parent, flog.read(fnode))
4408 except error.LookupError:
4416 except error.LookupError:
4409 pass
4417 pass
4410
4418
4411 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4419 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4412 rev = ctx.rev()
4420 rev = ctx.rev()
4413 parent = ctx.p1().rev()
4421 parent = ctx.p1().rev()
4414 for fn in sorted(revfiles.get(rev, [])):
4422 for fn in sorted(revfiles.get(rev, [])):
4415 states = matches[rev][fn]
4423 states = matches[rev][fn]
4416 copy = copies.get(rev, {}).get(fn)
4424 copy = copies.get(rev, {}).get(fn)
4417 if fn in skip:
4425 if fn in skip:
4418 if copy:
4426 if copy:
4419 skip[copy] = True
4427 skip[copy] = True
4420 continue
4428 continue
4421 pstates = matches.get(parent, {}).get(copy or fn, [])
4429 pstates = matches.get(parent, {}).get(copy or fn, [])
4422 if pstates or states:
4430 if pstates or states:
4423 r = display(fn, ctx, pstates, states)
4431 r = display(fn, ctx, pstates, states)
4424 found = found or r
4432 found = found or r
4425 if r and not opts.get('all'):
4433 if r and not opts.get('all'):
4426 skip[fn] = True
4434 skip[fn] = True
4427 if copy:
4435 if copy:
4428 skip[copy] = True
4436 skip[copy] = True
4429 del matches[rev]
4437 del matches[rev]
4430 del revfiles[rev]
4438 del revfiles[rev]
4431
4439
4432 return not found
4440 return not found
4433
4441
4434 @command('heads',
4442 @command('heads',
4435 [('r', 'rev', '',
4443 [('r', 'rev', '',
4436 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
4444 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
4437 ('t', 'topo', False, _('show topological heads only')),
4445 ('t', 'topo', False, _('show topological heads only')),
4438 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
4446 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
4439 ('c', 'closed', False, _('show normal and closed branch heads')),
4447 ('c', 'closed', False, _('show normal and closed branch heads')),
4440 ] + templateopts,
4448 ] + templateopts,
4441 _('[-ct] [-r STARTREV] [REV]...'))
4449 _('[-ct] [-r STARTREV] [REV]...'))
4442 def heads(ui, repo, *branchrevs, **opts):
4450 def heads(ui, repo, *branchrevs, **opts):
4443 """show branch heads
4451 """show branch heads
4444
4452
4445 With no arguments, show all open branch heads in the repository.
4453 With no arguments, show all open branch heads in the repository.
4446 Branch heads are changesets that have no descendants on the
4454 Branch heads are changesets that have no descendants on the
4447 same branch. They are where development generally takes place and
4455 same branch. They are where development generally takes place and
4448 are the usual targets for update and merge operations.
4456 are the usual targets for update and merge operations.
4449
4457
4450 If one or more REVs are given, only open branch heads on the
4458 If one or more REVs are given, only open branch heads on the
4451 branches associated with the specified changesets are shown. This
4459 branches associated with the specified changesets are shown. This
4452 means that you can use :hg:`heads .` to see the heads on the
4460 means that you can use :hg:`heads .` to see the heads on the
4453 currently checked-out branch.
4461 currently checked-out branch.
4454
4462
4455 If -c/--closed is specified, also show branch heads marked closed
4463 If -c/--closed is specified, also show branch heads marked closed
4456 (see :hg:`commit --close-branch`).
4464 (see :hg:`commit --close-branch`).
4457
4465
4458 If STARTREV is specified, only those heads that are descendants of
4466 If STARTREV is specified, only those heads that are descendants of
4459 STARTREV will be displayed.
4467 STARTREV will be displayed.
4460
4468
4461 If -t/--topo is specified, named branch mechanics will be ignored and only
4469 If -t/--topo is specified, named branch mechanics will be ignored and only
4462 topological heads (changesets with no children) will be shown.
4470 topological heads (changesets with no children) will be shown.
4463
4471
4464 Returns 0 if matching heads are found, 1 if not.
4472 Returns 0 if matching heads are found, 1 if not.
4465 """
4473 """
4466
4474
4467 start = None
4475 start = None
4468 if 'rev' in opts:
4476 if 'rev' in opts:
4469 start = scmutil.revsingle(repo, opts['rev'], None).node()
4477 start = scmutil.revsingle(repo, opts['rev'], None).node()
4470
4478
4471 if opts.get('topo'):
4479 if opts.get('topo'):
4472 heads = [repo[h] for h in repo.heads(start)]
4480 heads = [repo[h] for h in repo.heads(start)]
4473 else:
4481 else:
4474 heads = []
4482 heads = []
4475 for branch in repo.branchmap():
4483 for branch in repo.branchmap():
4476 heads += repo.branchheads(branch, start, opts.get('closed'))
4484 heads += repo.branchheads(branch, start, opts.get('closed'))
4477 heads = [repo[h] for h in heads]
4485 heads = [repo[h] for h in heads]
4478
4486
4479 if branchrevs:
4487 if branchrevs:
4480 branches = set(repo[br].branch() for br in branchrevs)
4488 branches = set(repo[br].branch() for br in branchrevs)
4481 heads = [h for h in heads if h.branch() in branches]
4489 heads = [h for h in heads if h.branch() in branches]
4482
4490
4483 if opts.get('active') and branchrevs:
4491 if opts.get('active') and branchrevs:
4484 dagheads = repo.heads(start)
4492 dagheads = repo.heads(start)
4485 heads = [h for h in heads if h.node() in dagheads]
4493 heads = [h for h in heads if h.node() in dagheads]
4486
4494
4487 if branchrevs:
4495 if branchrevs:
4488 haveheads = set(h.branch() for h in heads)
4496 haveheads = set(h.branch() for h in heads)
4489 if branches - haveheads:
4497 if branches - haveheads:
4490 headless = ', '.join(b for b in branches - haveheads)
4498 headless = ', '.join(b for b in branches - haveheads)
4491 msg = _('no open branch heads found on branches %s')
4499 msg = _('no open branch heads found on branches %s')
4492 if opts.get('rev'):
4500 if opts.get('rev'):
4493 msg += _(' (started at %s)') % opts['rev']
4501 msg += _(' (started at %s)') % opts['rev']
4494 ui.warn((msg + '\n') % headless)
4502 ui.warn((msg + '\n') % headless)
4495
4503
4496 if not heads:
4504 if not heads:
4497 return 1
4505 return 1
4498
4506
4499 heads = sorted(heads, key=lambda x: -x.rev())
4507 heads = sorted(heads, key=lambda x: -x.rev())
4500 displayer = cmdutil.show_changeset(ui, repo, opts)
4508 displayer = cmdutil.show_changeset(ui, repo, opts)
4501 for ctx in heads:
4509 for ctx in heads:
4502 displayer.show(ctx)
4510 displayer.show(ctx)
4503 displayer.close()
4511 displayer.close()
4504
4512
4505 @command('help',
4513 @command('help',
4506 [('e', 'extension', None, _('show only help for extensions')),
4514 [('e', 'extension', None, _('show only help for extensions')),
4507 ('c', 'command', None, _('show only help for commands')),
4515 ('c', 'command', None, _('show only help for commands')),
4508 ('k', 'keyword', None, _('show topics matching keyword')),
4516 ('k', 'keyword', None, _('show topics matching keyword')),
4509 ('s', 'system', [], _('show help for specific platform(s)')),
4517 ('s', 'system', [], _('show help for specific platform(s)')),
4510 ],
4518 ],
4511 _('[-ecks] [TOPIC]'),
4519 _('[-ecks] [TOPIC]'),
4512 norepo=True)
4520 norepo=True)
4513 def help_(ui, name=None, **opts):
4521 def help_(ui, name=None, **opts):
4514 """show help for a given topic or a help overview
4522 """show help for a given topic or a help overview
4515
4523
4516 With no arguments, print a list of commands with short help messages.
4524 With no arguments, print a list of commands with short help messages.
4517
4525
4518 Given a topic, extension, or command name, print help for that
4526 Given a topic, extension, or command name, print help for that
4519 topic.
4527 topic.
4520
4528
4521 Returns 0 if successful.
4529 Returns 0 if successful.
4522 """
4530 """
4523
4531
4524 textwidth = min(ui.termwidth(), 80) - 2
4532 textwidth = min(ui.termwidth(), 80) - 2
4525
4533
4526 keep = opts.get('system') or []
4534 keep = opts.get('system') or []
4527 if len(keep) == 0:
4535 if len(keep) == 0:
4528 if sys.platform.startswith('win'):
4536 if sys.platform.startswith('win'):
4529 keep.append('windows')
4537 keep.append('windows')
4530 elif sys.platform == 'OpenVMS':
4538 elif sys.platform == 'OpenVMS':
4531 keep.append('vms')
4539 keep.append('vms')
4532 elif sys.platform == 'plan9':
4540 elif sys.platform == 'plan9':
4533 keep.append('plan9')
4541 keep.append('plan9')
4534 else:
4542 else:
4535 keep.append('unix')
4543 keep.append('unix')
4536 keep.append(sys.platform.lower())
4544 keep.append(sys.platform.lower())
4537 if ui.verbose:
4545 if ui.verbose:
4538 keep.append('verbose')
4546 keep.append('verbose')
4539
4547
4540 section = None
4548 section = None
4541 subtopic = None
4549 subtopic = None
4542 if name and '.' in name:
4550 if name and '.' in name:
4543 name, section = name.split('.', 1)
4551 name, section = name.split('.', 1)
4544 section = section.lower()
4552 section = section.lower()
4545 if '.' in section:
4553 if '.' in section:
4546 subtopic, section = section.split('.', 1)
4554 subtopic, section = section.split('.', 1)
4547 else:
4555 else:
4548 subtopic = section
4556 subtopic = section
4549
4557
4550 text = help.help_(ui, name, subtopic=subtopic, **opts)
4558 text = help.help_(ui, name, subtopic=subtopic, **opts)
4551
4559
4552 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4560 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4553 section=section)
4561 section=section)
4554
4562
4555 # We could have been given a weird ".foo" section without a name
4563 # We could have been given a weird ".foo" section without a name
4556 # to look for, or we could have simply failed to found "foo.bar"
4564 # to look for, or we could have simply failed to found "foo.bar"
4557 # because bar isn't a section of foo
4565 # because bar isn't a section of foo
4558 if section and not (formatted and name):
4566 if section and not (formatted and name):
4559 raise error.Abort(_("help section not found"))
4567 raise error.Abort(_("help section not found"))
4560
4568
4561 if 'verbose' in pruned:
4569 if 'verbose' in pruned:
4562 keep.append('omitted')
4570 keep.append('omitted')
4563 else:
4571 else:
4564 keep.append('notomitted')
4572 keep.append('notomitted')
4565 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4573 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4566 section=section)
4574 section=section)
4567 ui.write(formatted)
4575 ui.write(formatted)
4568
4576
4569
4577
4570 @command('identify|id',
4578 @command('identify|id',
4571 [('r', 'rev', '',
4579 [('r', 'rev', '',
4572 _('identify the specified revision'), _('REV')),
4580 _('identify the specified revision'), _('REV')),
4573 ('n', 'num', None, _('show local revision number')),
4581 ('n', 'num', None, _('show local revision number')),
4574 ('i', 'id', None, _('show global revision id')),
4582 ('i', 'id', None, _('show global revision id')),
4575 ('b', 'branch', None, _('show branch')),
4583 ('b', 'branch', None, _('show branch')),
4576 ('t', 'tags', None, _('show tags')),
4584 ('t', 'tags', None, _('show tags')),
4577 ('B', 'bookmarks', None, _('show bookmarks')),
4585 ('B', 'bookmarks', None, _('show bookmarks')),
4578 ] + remoteopts,
4586 ] + remoteopts,
4579 _('[-nibtB] [-r REV] [SOURCE]'),
4587 _('[-nibtB] [-r REV] [SOURCE]'),
4580 optionalrepo=True)
4588 optionalrepo=True)
4581 def identify(ui, repo, source=None, rev=None,
4589 def identify(ui, repo, source=None, rev=None,
4582 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4590 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4583 """identify the working directory or specified revision
4591 """identify the working directory or specified revision
4584
4592
4585 Print a summary identifying the repository state at REV using one or
4593 Print a summary identifying the repository state at REV using one or
4586 two parent hash identifiers, followed by a "+" if the working
4594 two parent hash identifiers, followed by a "+" if the working
4587 directory has uncommitted changes, the branch name (if not default),
4595 directory has uncommitted changes, the branch name (if not default),
4588 a list of tags, and a list of bookmarks.
4596 a list of tags, and a list of bookmarks.
4589
4597
4590 When REV is not given, print a summary of the current state of the
4598 When REV is not given, print a summary of the current state of the
4591 repository.
4599 repository.
4592
4600
4593 Specifying a path to a repository root or Mercurial bundle will
4601 Specifying a path to a repository root or Mercurial bundle will
4594 cause lookup to operate on that repository/bundle.
4602 cause lookup to operate on that repository/bundle.
4595
4603
4596 .. container:: verbose
4604 .. container:: verbose
4597
4605
4598 Examples:
4606 Examples:
4599
4607
4600 - generate a build identifier for the working directory::
4608 - generate a build identifier for the working directory::
4601
4609
4602 hg id --id > build-id.dat
4610 hg id --id > build-id.dat
4603
4611
4604 - find the revision corresponding to a tag::
4612 - find the revision corresponding to a tag::
4605
4613
4606 hg id -n -r 1.3
4614 hg id -n -r 1.3
4607
4615
4608 - check the most recent revision of a remote repository::
4616 - check the most recent revision of a remote repository::
4609
4617
4610 hg id -r tip http://selenic.com/hg/
4618 hg id -r tip http://selenic.com/hg/
4611
4619
4612 See :hg:`log` for generating more information about specific revisions,
4620 See :hg:`log` for generating more information about specific revisions,
4613 including full hash identifiers.
4621 including full hash identifiers.
4614
4622
4615 Returns 0 if successful.
4623 Returns 0 if successful.
4616 """
4624 """
4617
4625
4618 if not repo and not source:
4626 if not repo and not source:
4619 raise error.Abort(_("there is no Mercurial repository here "
4627 raise error.Abort(_("there is no Mercurial repository here "
4620 "(.hg not found)"))
4628 "(.hg not found)"))
4621
4629
4622 if ui.debugflag:
4630 if ui.debugflag:
4623 hexfunc = hex
4631 hexfunc = hex
4624 else:
4632 else:
4625 hexfunc = short
4633 hexfunc = short
4626 default = not (num or id or branch or tags or bookmarks)
4634 default = not (num or id or branch or tags or bookmarks)
4627 output = []
4635 output = []
4628 revs = []
4636 revs = []
4629
4637
4630 if source:
4638 if source:
4631 source, branches = hg.parseurl(ui.expandpath(source))
4639 source, branches = hg.parseurl(ui.expandpath(source))
4632 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4640 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4633 repo = peer.local()
4641 repo = peer.local()
4634 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4642 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4635
4643
4636 if not repo:
4644 if not repo:
4637 if num or branch or tags:
4645 if num or branch or tags:
4638 raise error.Abort(
4646 raise error.Abort(
4639 _("can't query remote revision number, branch, or tags"))
4647 _("can't query remote revision number, branch, or tags"))
4640 if not rev and revs:
4648 if not rev and revs:
4641 rev = revs[0]
4649 rev = revs[0]
4642 if not rev:
4650 if not rev:
4643 rev = "tip"
4651 rev = "tip"
4644
4652
4645 remoterev = peer.lookup(rev)
4653 remoterev = peer.lookup(rev)
4646 if default or id:
4654 if default or id:
4647 output = [hexfunc(remoterev)]
4655 output = [hexfunc(remoterev)]
4648
4656
4649 def getbms():
4657 def getbms():
4650 bms = []
4658 bms = []
4651
4659
4652 if 'bookmarks' in peer.listkeys('namespaces'):
4660 if 'bookmarks' in peer.listkeys('namespaces'):
4653 hexremoterev = hex(remoterev)
4661 hexremoterev = hex(remoterev)
4654 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4662 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4655 if bmr == hexremoterev]
4663 if bmr == hexremoterev]
4656
4664
4657 return sorted(bms)
4665 return sorted(bms)
4658
4666
4659 if bookmarks:
4667 if bookmarks:
4660 output.extend(getbms())
4668 output.extend(getbms())
4661 elif default and not ui.quiet:
4669 elif default and not ui.quiet:
4662 # multiple bookmarks for a single parent separated by '/'
4670 # multiple bookmarks for a single parent separated by '/'
4663 bm = '/'.join(getbms())
4671 bm = '/'.join(getbms())
4664 if bm:
4672 if bm:
4665 output.append(bm)
4673 output.append(bm)
4666 else:
4674 else:
4667 ctx = scmutil.revsingle(repo, rev, None)
4675 ctx = scmutil.revsingle(repo, rev, None)
4668
4676
4669 if ctx.rev() is None:
4677 if ctx.rev() is None:
4670 ctx = repo[None]
4678 ctx = repo[None]
4671 parents = ctx.parents()
4679 parents = ctx.parents()
4672 taglist = []
4680 taglist = []
4673 for p in parents:
4681 for p in parents:
4674 taglist.extend(p.tags())
4682 taglist.extend(p.tags())
4675
4683
4676 changed = ""
4684 changed = ""
4677 if default or id or num:
4685 if default or id or num:
4678 if (any(repo.status())
4686 if (any(repo.status())
4679 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4687 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4680 changed = '+'
4688 changed = '+'
4681 if default or id:
4689 if default or id:
4682 output = ["%s%s" %
4690 output = ["%s%s" %
4683 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4691 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4684 if num:
4692 if num:
4685 output.append("%s%s" %
4693 output.append("%s%s" %
4686 ('+'.join([str(p.rev()) for p in parents]), changed))
4694 ('+'.join([str(p.rev()) for p in parents]), changed))
4687 else:
4695 else:
4688 if default or id:
4696 if default or id:
4689 output = [hexfunc(ctx.node())]
4697 output = [hexfunc(ctx.node())]
4690 if num:
4698 if num:
4691 output.append(str(ctx.rev()))
4699 output.append(str(ctx.rev()))
4692 taglist = ctx.tags()
4700 taglist = ctx.tags()
4693
4701
4694 if default and not ui.quiet:
4702 if default and not ui.quiet:
4695 b = ctx.branch()
4703 b = ctx.branch()
4696 if b != 'default':
4704 if b != 'default':
4697 output.append("(%s)" % b)
4705 output.append("(%s)" % b)
4698
4706
4699 # multiple tags for a single parent separated by '/'
4707 # multiple tags for a single parent separated by '/'
4700 t = '/'.join(taglist)
4708 t = '/'.join(taglist)
4701 if t:
4709 if t:
4702 output.append(t)
4710 output.append(t)
4703
4711
4704 # multiple bookmarks for a single parent separated by '/'
4712 # multiple bookmarks for a single parent separated by '/'
4705 bm = '/'.join(ctx.bookmarks())
4713 bm = '/'.join(ctx.bookmarks())
4706 if bm:
4714 if bm:
4707 output.append(bm)
4715 output.append(bm)
4708 else:
4716 else:
4709 if branch:
4717 if branch:
4710 output.append(ctx.branch())
4718 output.append(ctx.branch())
4711
4719
4712 if tags:
4720 if tags:
4713 output.extend(taglist)
4721 output.extend(taglist)
4714
4722
4715 if bookmarks:
4723 if bookmarks:
4716 output.extend(ctx.bookmarks())
4724 output.extend(ctx.bookmarks())
4717
4725
4718 ui.write("%s\n" % ' '.join(output))
4726 ui.write("%s\n" % ' '.join(output))
4719
4727
4720 @command('import|patch',
4728 @command('import|patch',
4721 [('p', 'strip', 1,
4729 [('p', 'strip', 1,
4722 _('directory strip option for patch. This has the same '
4730 _('directory strip option for patch. This has the same '
4723 'meaning as the corresponding patch option'), _('NUM')),
4731 'meaning as the corresponding patch option'), _('NUM')),
4724 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4732 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4725 ('e', 'edit', False, _('invoke editor on commit messages')),
4733 ('e', 'edit', False, _('invoke editor on commit messages')),
4726 ('f', 'force', None,
4734 ('f', 'force', None,
4727 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4735 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4728 ('', 'no-commit', None,
4736 ('', 'no-commit', None,
4729 _("don't commit, just update the working directory")),
4737 _("don't commit, just update the working directory")),
4730 ('', 'bypass', None,
4738 ('', 'bypass', None,
4731 _("apply patch without touching the working directory")),
4739 _("apply patch without touching the working directory")),
4732 ('', 'partial', None,
4740 ('', 'partial', None,
4733 _('commit even if some hunks fail')),
4741 _('commit even if some hunks fail')),
4734 ('', 'exact', None,
4742 ('', 'exact', None,
4735 _('apply patch to the nodes from which it was generated')),
4743 _('apply patch to the nodes from which it was generated')),
4736 ('', 'prefix', '',
4744 ('', 'prefix', '',
4737 _('apply patch to subdirectory'), _('DIR')),
4745 _('apply patch to subdirectory'), _('DIR')),
4738 ('', 'import-branch', None,
4746 ('', 'import-branch', None,
4739 _('use any branch information in patch (implied by --exact)'))] +
4747 _('use any branch information in patch (implied by --exact)'))] +
4740 commitopts + commitopts2 + similarityopts,
4748 commitopts + commitopts2 + similarityopts,
4741 _('[OPTION]... PATCH...'))
4749 _('[OPTION]... PATCH...'))
4742 def import_(ui, repo, patch1=None, *patches, **opts):
4750 def import_(ui, repo, patch1=None, *patches, **opts):
4743 """import an ordered set of patches
4751 """import an ordered set of patches
4744
4752
4745 Import a list of patches and commit them individually (unless
4753 Import a list of patches and commit them individually (unless
4746 --no-commit is specified).
4754 --no-commit is specified).
4747
4755
4748 To read a patch from standard input, use "-" as the patch name. If
4756 To read a patch from standard input, use "-" as the patch name. If
4749 a URL is specified, the patch will be downloaded from there.
4757 a URL is specified, the patch will be downloaded from there.
4750
4758
4751 Import first applies changes to the working directory (unless
4759 Import first applies changes to the working directory (unless
4752 --bypass is specified), import will abort if there are outstanding
4760 --bypass is specified), import will abort if there are outstanding
4753 changes.
4761 changes.
4754
4762
4755 Use --bypass to apply and commit patches directly to the
4763 Use --bypass to apply and commit patches directly to the
4756 repository, without affecting the working directory. Without
4764 repository, without affecting the working directory. Without
4757 --exact, patches will be applied on top of the working directory
4765 --exact, patches will be applied on top of the working directory
4758 parent revision.
4766 parent revision.
4759
4767
4760 You can import a patch straight from a mail message. Even patches
4768 You can import a patch straight from a mail message. Even patches
4761 as attachments work (to use the body part, it must have type
4769 as attachments work (to use the body part, it must have type
4762 text/plain or text/x-patch). From and Subject headers of email
4770 text/plain or text/x-patch). From and Subject headers of email
4763 message are used as default committer and commit message. All
4771 message are used as default committer and commit message. All
4764 text/plain body parts before first diff are added to the commit
4772 text/plain body parts before first diff are added to the commit
4765 message.
4773 message.
4766
4774
4767 If the imported patch was generated by :hg:`export`, user and
4775 If the imported patch was generated by :hg:`export`, user and
4768 description from patch override values from message headers and
4776 description from patch override values from message headers and
4769 body. Values given on command line with -m/--message and -u/--user
4777 body. Values given on command line with -m/--message and -u/--user
4770 override these.
4778 override these.
4771
4779
4772 If --exact is specified, import will set the working directory to
4780 If --exact is specified, import will set the working directory to
4773 the parent of each patch before applying it, and will abort if the
4781 the parent of each patch before applying it, and will abort if the
4774 resulting changeset has a different ID than the one recorded in
4782 resulting changeset has a different ID than the one recorded in
4775 the patch. This may happen due to character set problems or other
4783 the patch. This may happen due to character set problems or other
4776 deficiencies in the text patch format.
4784 deficiencies in the text patch format.
4777
4785
4778 Use --partial to ensure a changeset will be created from the patch
4786 Use --partial to ensure a changeset will be created from the patch
4779 even if some hunks fail to apply. Hunks that fail to apply will be
4787 even if some hunks fail to apply. Hunks that fail to apply will be
4780 written to a <target-file>.rej file. Conflicts can then be resolved
4788 written to a <target-file>.rej file. Conflicts can then be resolved
4781 by hand before :hg:`commit --amend` is run to update the created
4789 by hand before :hg:`commit --amend` is run to update the created
4782 changeset. This flag exists to let people import patches that
4790 changeset. This flag exists to let people import patches that
4783 partially apply without losing the associated metadata (author,
4791 partially apply without losing the associated metadata (author,
4784 date, description, ...).
4792 date, description, ...).
4785
4793
4786 .. note::
4794 .. note::
4787
4795
4788 When no hunks apply cleanly, :hg:`import --partial` will create
4796 When no hunks apply cleanly, :hg:`import --partial` will create
4789 an empty changeset, importing only the patch metadata.
4797 an empty changeset, importing only the patch metadata.
4790
4798
4791 With -s/--similarity, hg will attempt to discover renames and
4799 With -s/--similarity, hg will attempt to discover renames and
4792 copies in the patch in the same way as :hg:`addremove`.
4800 copies in the patch in the same way as :hg:`addremove`.
4793
4801
4794 It is possible to use external patch programs to perform the patch
4802 It is possible to use external patch programs to perform the patch
4795 by setting the ``ui.patch`` configuration option. For the default
4803 by setting the ``ui.patch`` configuration option. For the default
4796 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4804 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4797 See :hg:`help config` for more information about configuration
4805 See :hg:`help config` for more information about configuration
4798 files and how to use these options.
4806 files and how to use these options.
4799
4807
4800 See :hg:`help dates` for a list of formats valid for -d/--date.
4808 See :hg:`help dates` for a list of formats valid for -d/--date.
4801
4809
4802 .. container:: verbose
4810 .. container:: verbose
4803
4811
4804 Examples:
4812 Examples:
4805
4813
4806 - import a traditional patch from a website and detect renames::
4814 - import a traditional patch from a website and detect renames::
4807
4815
4808 hg import -s 80 http://example.com/bugfix.patch
4816 hg import -s 80 http://example.com/bugfix.patch
4809
4817
4810 - import a changeset from an hgweb server::
4818 - import a changeset from an hgweb server::
4811
4819
4812 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4820 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4813
4821
4814 - import all the patches in an Unix-style mbox::
4822 - import all the patches in an Unix-style mbox::
4815
4823
4816 hg import incoming-patches.mbox
4824 hg import incoming-patches.mbox
4817
4825
4818 - attempt to exactly restore an exported changeset (not always
4826 - attempt to exactly restore an exported changeset (not always
4819 possible)::
4827 possible)::
4820
4828
4821 hg import --exact proposed-fix.patch
4829 hg import --exact proposed-fix.patch
4822
4830
4823 - use an external tool to apply a patch which is too fuzzy for
4831 - use an external tool to apply a patch which is too fuzzy for
4824 the default internal tool.
4832 the default internal tool.
4825
4833
4826 hg import --config ui.patch="patch --merge" fuzzy.patch
4834 hg import --config ui.patch="patch --merge" fuzzy.patch
4827
4835
4828 - change the default fuzzing from 2 to a less strict 7
4836 - change the default fuzzing from 2 to a less strict 7
4829
4837
4830 hg import --config ui.fuzz=7 fuzz.patch
4838 hg import --config ui.fuzz=7 fuzz.patch
4831
4839
4832 Returns 0 on success, 1 on partial success (see --partial).
4840 Returns 0 on success, 1 on partial success (see --partial).
4833 """
4841 """
4834
4842
4835 if not patch1:
4843 if not patch1:
4836 raise error.Abort(_('need at least one patch to import'))
4844 raise error.Abort(_('need at least one patch to import'))
4837
4845
4838 patches = (patch1,) + patches
4846 patches = (patch1,) + patches
4839
4847
4840 date = opts.get('date')
4848 date = opts.get('date')
4841 if date:
4849 if date:
4842 opts['date'] = util.parsedate(date)
4850 opts['date'] = util.parsedate(date)
4843
4851
4844 exact = opts.get('exact')
4852 exact = opts.get('exact')
4845 update = not opts.get('bypass')
4853 update = not opts.get('bypass')
4846 if not update and opts.get('no_commit'):
4854 if not update and opts.get('no_commit'):
4847 raise error.Abort(_('cannot use --no-commit with --bypass'))
4855 raise error.Abort(_('cannot use --no-commit with --bypass'))
4848 try:
4856 try:
4849 sim = float(opts.get('similarity') or 0)
4857 sim = float(opts.get('similarity') or 0)
4850 except ValueError:
4858 except ValueError:
4851 raise error.Abort(_('similarity must be a number'))
4859 raise error.Abort(_('similarity must be a number'))
4852 if sim < 0 or sim > 100:
4860 if sim < 0 or sim > 100:
4853 raise error.Abort(_('similarity must be between 0 and 100'))
4861 raise error.Abort(_('similarity must be between 0 and 100'))
4854 if sim and not update:
4862 if sim and not update:
4855 raise error.Abort(_('cannot use --similarity with --bypass'))
4863 raise error.Abort(_('cannot use --similarity with --bypass'))
4856 if exact:
4864 if exact:
4857 if opts.get('edit'):
4865 if opts.get('edit'):
4858 raise error.Abort(_('cannot use --exact with --edit'))
4866 raise error.Abort(_('cannot use --exact with --edit'))
4859 if opts.get('prefix'):
4867 if opts.get('prefix'):
4860 raise error.Abort(_('cannot use --exact with --prefix'))
4868 raise error.Abort(_('cannot use --exact with --prefix'))
4861
4869
4862 base = opts["base"]
4870 base = opts["base"]
4863 wlock = dsguard = lock = tr = None
4871 wlock = dsguard = lock = tr = None
4864 msgs = []
4872 msgs = []
4865 ret = 0
4873 ret = 0
4866
4874
4867
4875
4868 try:
4876 try:
4869 wlock = repo.wlock()
4877 wlock = repo.wlock()
4870
4878
4871 if update:
4879 if update:
4872 cmdutil.checkunfinished(repo)
4880 cmdutil.checkunfinished(repo)
4873 if (exact or not opts.get('force')):
4881 if (exact or not opts.get('force')):
4874 cmdutil.bailifchanged(repo)
4882 cmdutil.bailifchanged(repo)
4875
4883
4876 if not opts.get('no_commit'):
4884 if not opts.get('no_commit'):
4877 lock = repo.lock()
4885 lock = repo.lock()
4878 tr = repo.transaction('import')
4886 tr = repo.transaction('import')
4879 else:
4887 else:
4880 dsguard = cmdutil.dirstateguard(repo, 'import')
4888 dsguard = cmdutil.dirstateguard(repo, 'import')
4881 parents = repo[None].parents()
4889 parents = repo[None].parents()
4882 for patchurl in patches:
4890 for patchurl in patches:
4883 if patchurl == '-':
4891 if patchurl == '-':
4884 ui.status(_('applying patch from stdin\n'))
4892 ui.status(_('applying patch from stdin\n'))
4885 patchfile = ui.fin
4893 patchfile = ui.fin
4886 patchurl = 'stdin' # for error message
4894 patchurl = 'stdin' # for error message
4887 else:
4895 else:
4888 patchurl = os.path.join(base, patchurl)
4896 patchurl = os.path.join(base, patchurl)
4889 ui.status(_('applying %s\n') % patchurl)
4897 ui.status(_('applying %s\n') % patchurl)
4890 patchfile = hg.openpath(ui, patchurl)
4898 patchfile = hg.openpath(ui, patchurl)
4891
4899
4892 haspatch = False
4900 haspatch = False
4893 for hunk in patch.split(patchfile):
4901 for hunk in patch.split(patchfile):
4894 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4902 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4895 parents, opts,
4903 parents, opts,
4896 msgs, hg.clean)
4904 msgs, hg.clean)
4897 if msg:
4905 if msg:
4898 haspatch = True
4906 haspatch = True
4899 ui.note(msg + '\n')
4907 ui.note(msg + '\n')
4900 if update or exact:
4908 if update or exact:
4901 parents = repo[None].parents()
4909 parents = repo[None].parents()
4902 else:
4910 else:
4903 parents = [repo[node]]
4911 parents = [repo[node]]
4904 if rej:
4912 if rej:
4905 ui.write_err(_("patch applied partially\n"))
4913 ui.write_err(_("patch applied partially\n"))
4906 ui.write_err(_("(fix the .rej files and run "
4914 ui.write_err(_("(fix the .rej files and run "
4907 "`hg commit --amend`)\n"))
4915 "`hg commit --amend`)\n"))
4908 ret = 1
4916 ret = 1
4909 break
4917 break
4910
4918
4911 if not haspatch:
4919 if not haspatch:
4912 raise error.Abort(_('%s: no diffs found') % patchurl)
4920 raise error.Abort(_('%s: no diffs found') % patchurl)
4913
4921
4914 if tr:
4922 if tr:
4915 tr.close()
4923 tr.close()
4916 if msgs:
4924 if msgs:
4917 repo.savecommitmessage('\n* * *\n'.join(msgs))
4925 repo.savecommitmessage('\n* * *\n'.join(msgs))
4918 if dsguard:
4926 if dsguard:
4919 dsguard.close()
4927 dsguard.close()
4920 return ret
4928 return ret
4921 finally:
4929 finally:
4922 if tr:
4930 if tr:
4923 tr.release()
4931 tr.release()
4924 release(lock, dsguard, wlock)
4932 release(lock, dsguard, wlock)
4925
4933
4926 @command('incoming|in',
4934 @command('incoming|in',
4927 [('f', 'force', None,
4935 [('f', 'force', None,
4928 _('run even if remote repository is unrelated')),
4936 _('run even if remote repository is unrelated')),
4929 ('n', 'newest-first', None, _('show newest record first')),
4937 ('n', 'newest-first', None, _('show newest record first')),
4930 ('', 'bundle', '',
4938 ('', 'bundle', '',
4931 _('file to store the bundles into'), _('FILE')),
4939 _('file to store the bundles into'), _('FILE')),
4932 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4940 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4933 ('B', 'bookmarks', False, _("compare bookmarks")),
4941 ('B', 'bookmarks', False, _("compare bookmarks")),
4934 ('b', 'branch', [],
4942 ('b', 'branch', [],
4935 _('a specific branch you would like to pull'), _('BRANCH')),
4943 _('a specific branch you would like to pull'), _('BRANCH')),
4936 ] + logopts + remoteopts + subrepoopts,
4944 ] + logopts + remoteopts + subrepoopts,
4937 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4945 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4938 def incoming(ui, repo, source="default", **opts):
4946 def incoming(ui, repo, source="default", **opts):
4939 """show new changesets found in source
4947 """show new changesets found in source
4940
4948
4941 Show new changesets found in the specified path/URL or the default
4949 Show new changesets found in the specified path/URL or the default
4942 pull location. These are the changesets that would have been pulled
4950 pull location. These are the changesets that would have been pulled
4943 if a pull at the time you issued this command.
4951 if a pull at the time you issued this command.
4944
4952
4945 See pull for valid source format details.
4953 See pull for valid source format details.
4946
4954
4947 .. container:: verbose
4955 .. container:: verbose
4948
4956
4949 With -B/--bookmarks, the result of bookmark comparison between
4957 With -B/--bookmarks, the result of bookmark comparison between
4950 local and remote repositories is displayed. With -v/--verbose,
4958 local and remote repositories is displayed. With -v/--verbose,
4951 status is also displayed for each bookmark like below::
4959 status is also displayed for each bookmark like below::
4952
4960
4953 BM1 01234567890a added
4961 BM1 01234567890a added
4954 BM2 1234567890ab advanced
4962 BM2 1234567890ab advanced
4955 BM3 234567890abc diverged
4963 BM3 234567890abc diverged
4956 BM4 34567890abcd changed
4964 BM4 34567890abcd changed
4957
4965
4958 The action taken locally when pulling depends on the
4966 The action taken locally when pulling depends on the
4959 status of each bookmark:
4967 status of each bookmark:
4960
4968
4961 :``added``: pull will create it
4969 :``added``: pull will create it
4962 :``advanced``: pull will update it
4970 :``advanced``: pull will update it
4963 :``diverged``: pull will create a divergent bookmark
4971 :``diverged``: pull will create a divergent bookmark
4964 :``changed``: result depends on remote changesets
4972 :``changed``: result depends on remote changesets
4965
4973
4966 From the point of view of pulling behavior, bookmark
4974 From the point of view of pulling behavior, bookmark
4967 existing only in the remote repository are treated as ``added``,
4975 existing only in the remote repository are treated as ``added``,
4968 even if it is in fact locally deleted.
4976 even if it is in fact locally deleted.
4969
4977
4970 .. container:: verbose
4978 .. container:: verbose
4971
4979
4972 For remote repository, using --bundle avoids downloading the
4980 For remote repository, using --bundle avoids downloading the
4973 changesets twice if the incoming is followed by a pull.
4981 changesets twice if the incoming is followed by a pull.
4974
4982
4975 Examples:
4983 Examples:
4976
4984
4977 - show incoming changes with patches and full description::
4985 - show incoming changes with patches and full description::
4978
4986
4979 hg incoming -vp
4987 hg incoming -vp
4980
4988
4981 - show incoming changes excluding merges, store a bundle::
4989 - show incoming changes excluding merges, store a bundle::
4982
4990
4983 hg in -vpM --bundle incoming.hg
4991 hg in -vpM --bundle incoming.hg
4984 hg pull incoming.hg
4992 hg pull incoming.hg
4985
4993
4986 - briefly list changes inside a bundle::
4994 - briefly list changes inside a bundle::
4987
4995
4988 hg in changes.hg -T "{desc|firstline}\\n"
4996 hg in changes.hg -T "{desc|firstline}\\n"
4989
4997
4990 Returns 0 if there are incoming changes, 1 otherwise.
4998 Returns 0 if there are incoming changes, 1 otherwise.
4991 """
4999 """
4992 if opts.get('graph'):
5000 if opts.get('graph'):
4993 cmdutil.checkunsupportedgraphflags([], opts)
5001 cmdutil.checkunsupportedgraphflags([], opts)
4994 def display(other, chlist, displayer):
5002 def display(other, chlist, displayer):
4995 revdag = cmdutil.graphrevs(other, chlist, opts)
5003 revdag = cmdutil.graphrevs(other, chlist, opts)
4996 cmdutil.displaygraph(ui, repo, revdag, displayer,
5004 cmdutil.displaygraph(ui, repo, revdag, displayer,
4997 graphmod.asciiedges)
5005 graphmod.asciiedges)
4998
5006
4999 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
5007 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
5000 return 0
5008 return 0
5001
5009
5002 if opts.get('bundle') and opts.get('subrepos'):
5010 if opts.get('bundle') and opts.get('subrepos'):
5003 raise error.Abort(_('cannot combine --bundle and --subrepos'))
5011 raise error.Abort(_('cannot combine --bundle and --subrepos'))
5004
5012
5005 if opts.get('bookmarks'):
5013 if opts.get('bookmarks'):
5006 source, branches = hg.parseurl(ui.expandpath(source),
5014 source, branches = hg.parseurl(ui.expandpath(source),
5007 opts.get('branch'))
5015 opts.get('branch'))
5008 other = hg.peer(repo, opts, source)
5016 other = hg.peer(repo, opts, source)
5009 if 'bookmarks' not in other.listkeys('namespaces'):
5017 if 'bookmarks' not in other.listkeys('namespaces'):
5010 ui.warn(_("remote doesn't support bookmarks\n"))
5018 ui.warn(_("remote doesn't support bookmarks\n"))
5011 return 0
5019 return 0
5012 ui.status(_('comparing with %s\n') % util.hidepassword(source))
5020 ui.status(_('comparing with %s\n') % util.hidepassword(source))
5013 return bookmarks.incoming(ui, repo, other)
5021 return bookmarks.incoming(ui, repo, other)
5014
5022
5015 repo._subtoppath = ui.expandpath(source)
5023 repo._subtoppath = ui.expandpath(source)
5016 try:
5024 try:
5017 return hg.incoming(ui, repo, source, opts)
5025 return hg.incoming(ui, repo, source, opts)
5018 finally:
5026 finally:
5019 del repo._subtoppath
5027 del repo._subtoppath
5020
5028
5021
5029
5022 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
5030 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
5023 norepo=True)
5031 norepo=True)
5024 def init(ui, dest=".", **opts):
5032 def init(ui, dest=".", **opts):
5025 """create a new repository in the given directory
5033 """create a new repository in the given directory
5026
5034
5027 Initialize a new repository in the given directory. If the given
5035 Initialize a new repository in the given directory. If the given
5028 directory does not exist, it will be created.
5036 directory does not exist, it will be created.
5029
5037
5030 If no directory is given, the current directory is used.
5038 If no directory is given, the current directory is used.
5031
5039
5032 It is possible to specify an ``ssh://`` URL as the destination.
5040 It is possible to specify an ``ssh://`` URL as the destination.
5033 See :hg:`help urls` for more information.
5041 See :hg:`help urls` for more information.
5034
5042
5035 Returns 0 on success.
5043 Returns 0 on success.
5036 """
5044 """
5037 hg.peer(ui, opts, ui.expandpath(dest), create=True)
5045 hg.peer(ui, opts, ui.expandpath(dest), create=True)
5038
5046
5039 @command('locate',
5047 @command('locate',
5040 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
5048 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
5041 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5049 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5042 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
5050 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
5043 ] + walkopts,
5051 ] + walkopts,
5044 _('[OPTION]... [PATTERN]...'))
5052 _('[OPTION]... [PATTERN]...'))
5045 def locate(ui, repo, *pats, **opts):
5053 def locate(ui, repo, *pats, **opts):
5046 """locate files matching specific patterns (DEPRECATED)
5054 """locate files matching specific patterns (DEPRECATED)
5047
5055
5048 Print files under Mercurial control in the working directory whose
5056 Print files under Mercurial control in the working directory whose
5049 names match the given patterns.
5057 names match the given patterns.
5050
5058
5051 By default, this command searches all directories in the working
5059 By default, this command searches all directories in the working
5052 directory. To search just the current directory and its
5060 directory. To search just the current directory and its
5053 subdirectories, use "--include .".
5061 subdirectories, use "--include .".
5054
5062
5055 If no patterns are given to match, this command prints the names
5063 If no patterns are given to match, this command prints the names
5056 of all files under Mercurial control in the working directory.
5064 of all files under Mercurial control in the working directory.
5057
5065
5058 If you want to feed the output of this command into the "xargs"
5066 If you want to feed the output of this command into the "xargs"
5059 command, use the -0 option to both this command and "xargs". This
5067 command, use the -0 option to both this command and "xargs". This
5060 will avoid the problem of "xargs" treating single filenames that
5068 will avoid the problem of "xargs" treating single filenames that
5061 contain whitespace as multiple filenames.
5069 contain whitespace as multiple filenames.
5062
5070
5063 See :hg:`help files` for a more versatile command.
5071 See :hg:`help files` for a more versatile command.
5064
5072
5065 Returns 0 if a match is found, 1 otherwise.
5073 Returns 0 if a match is found, 1 otherwise.
5066 """
5074 """
5067 if opts.get('print0'):
5075 if opts.get('print0'):
5068 end = '\0'
5076 end = '\0'
5069 else:
5077 else:
5070 end = '\n'
5078 end = '\n'
5071 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
5079 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
5072
5080
5073 ret = 1
5081 ret = 1
5074 ctx = repo[rev]
5082 ctx = repo[rev]
5075 m = scmutil.match(ctx, pats, opts, default='relglob',
5083 m = scmutil.match(ctx, pats, opts, default='relglob',
5076 badfn=lambda x, y: False)
5084 badfn=lambda x, y: False)
5077
5085
5078 for abs in ctx.matches(m):
5086 for abs in ctx.matches(m):
5079 if opts.get('fullpath'):
5087 if opts.get('fullpath'):
5080 ui.write(repo.wjoin(abs), end)
5088 ui.write(repo.wjoin(abs), end)
5081 else:
5089 else:
5082 ui.write(((pats and m.rel(abs)) or abs), end)
5090 ui.write(((pats and m.rel(abs)) or abs), end)
5083 ret = 0
5091 ret = 0
5084
5092
5085 return ret
5093 return ret
5086
5094
5087 @command('^log|history',
5095 @command('^log|history',
5088 [('f', 'follow', None,
5096 [('f', 'follow', None,
5089 _('follow changeset history, or file history across copies and renames')),
5097 _('follow changeset history, or file history across copies and renames')),
5090 ('', 'follow-first', None,
5098 ('', 'follow-first', None,
5091 _('only follow the first parent of merge changesets (DEPRECATED)')),
5099 _('only follow the first parent of merge changesets (DEPRECATED)')),
5092 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
5100 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
5093 ('C', 'copies', None, _('show copied files')),
5101 ('C', 'copies', None, _('show copied files')),
5094 ('k', 'keyword', [],
5102 ('k', 'keyword', [],
5095 _('do case-insensitive search for a given text'), _('TEXT')),
5103 _('do case-insensitive search for a given text'), _('TEXT')),
5096 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
5104 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
5097 ('', 'removed', None, _('include revisions where files were removed')),
5105 ('', 'removed', None, _('include revisions where files were removed')),
5098 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
5106 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
5099 ('u', 'user', [], _('revisions committed by user'), _('USER')),
5107 ('u', 'user', [], _('revisions committed by user'), _('USER')),
5100 ('', 'only-branch', [],
5108 ('', 'only-branch', [],
5101 _('show only changesets within the given named branch (DEPRECATED)'),
5109 _('show only changesets within the given named branch (DEPRECATED)'),
5102 _('BRANCH')),
5110 _('BRANCH')),
5103 ('b', 'branch', [],
5111 ('b', 'branch', [],
5104 _('show changesets within the given named branch'), _('BRANCH')),
5112 _('show changesets within the given named branch'), _('BRANCH')),
5105 ('P', 'prune', [],
5113 ('P', 'prune', [],
5106 _('do not display revision or any of its ancestors'), _('REV')),
5114 _('do not display revision or any of its ancestors'), _('REV')),
5107 ] + logopts + walkopts,
5115 ] + logopts + walkopts,
5108 _('[OPTION]... [FILE]'),
5116 _('[OPTION]... [FILE]'),
5109 inferrepo=True)
5117 inferrepo=True)
5110 def log(ui, repo, *pats, **opts):
5118 def log(ui, repo, *pats, **opts):
5111 """show revision history of entire repository or files
5119 """show revision history of entire repository or files
5112
5120
5113 Print the revision history of the specified files or the entire
5121 Print the revision history of the specified files or the entire
5114 project.
5122 project.
5115
5123
5116 If no revision range is specified, the default is ``tip:0`` unless
5124 If no revision range is specified, the default is ``tip:0`` unless
5117 --follow is set, in which case the working directory parent is
5125 --follow is set, in which case the working directory parent is
5118 used as the starting revision.
5126 used as the starting revision.
5119
5127
5120 File history is shown without following rename or copy history of
5128 File history is shown without following rename or copy history of
5121 files. Use -f/--follow with a filename to follow history across
5129 files. Use -f/--follow with a filename to follow history across
5122 renames and copies. --follow without a filename will only show
5130 renames and copies. --follow without a filename will only show
5123 ancestors or descendants of the starting revision.
5131 ancestors or descendants of the starting revision.
5124
5132
5125 By default this command prints revision number and changeset id,
5133 By default this command prints revision number and changeset id,
5126 tags, non-trivial parents, user, date and time, and a summary for
5134 tags, non-trivial parents, user, date and time, and a summary for
5127 each commit. When the -v/--verbose switch is used, the list of
5135 each commit. When the -v/--verbose switch is used, the list of
5128 changed files and full commit message are shown.
5136 changed files and full commit message are shown.
5129
5137
5130 With --graph the revisions are shown as an ASCII art DAG with the most
5138 With --graph the revisions are shown as an ASCII art DAG with the most
5131 recent changeset at the top.
5139 recent changeset at the top.
5132 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
5140 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
5133 and '+' represents a fork where the changeset from the lines below is a
5141 and '+' represents a fork where the changeset from the lines below is a
5134 parent of the 'o' merge on the same line.
5142 parent of the 'o' merge on the same line.
5135
5143
5136 .. note::
5144 .. note::
5137
5145
5138 :hg:`log --patch` may generate unexpected diff output for merge
5146 :hg:`log --patch` may generate unexpected diff output for merge
5139 changesets, as it will only compare the merge changeset against
5147 changesets, as it will only compare the merge changeset against
5140 its first parent. Also, only files different from BOTH parents
5148 its first parent. Also, only files different from BOTH parents
5141 will appear in files:.
5149 will appear in files:.
5142
5150
5143 .. note::
5151 .. note::
5144
5152
5145 For performance reasons, :hg:`log FILE` may omit duplicate changes
5153 For performance reasons, :hg:`log FILE` may omit duplicate changes
5146 made on branches and will not show removals or mode changes. To
5154 made on branches and will not show removals or mode changes. To
5147 see all such changes, use the --removed switch.
5155 see all such changes, use the --removed switch.
5148
5156
5149 .. container:: verbose
5157 .. container:: verbose
5150
5158
5151 Some examples:
5159 Some examples:
5152
5160
5153 - changesets with full descriptions and file lists::
5161 - changesets with full descriptions and file lists::
5154
5162
5155 hg log -v
5163 hg log -v
5156
5164
5157 - changesets ancestral to the working directory::
5165 - changesets ancestral to the working directory::
5158
5166
5159 hg log -f
5167 hg log -f
5160
5168
5161 - last 10 commits on the current branch::
5169 - last 10 commits on the current branch::
5162
5170
5163 hg log -l 10 -b .
5171 hg log -l 10 -b .
5164
5172
5165 - changesets showing all modifications of a file, including removals::
5173 - changesets showing all modifications of a file, including removals::
5166
5174
5167 hg log --removed file.c
5175 hg log --removed file.c
5168
5176
5169 - all changesets that touch a directory, with diffs, excluding merges::
5177 - all changesets that touch a directory, with diffs, excluding merges::
5170
5178
5171 hg log -Mp lib/
5179 hg log -Mp lib/
5172
5180
5173 - all revision numbers that match a keyword::
5181 - all revision numbers that match a keyword::
5174
5182
5175 hg log -k bug --template "{rev}\\n"
5183 hg log -k bug --template "{rev}\\n"
5176
5184
5177 - the full hash identifier of the working directory parent::
5185 - the full hash identifier of the working directory parent::
5178
5186
5179 hg log -r . --template "{node}\\n"
5187 hg log -r . --template "{node}\\n"
5180
5188
5181 - list available log templates::
5189 - list available log templates::
5182
5190
5183 hg log -T list
5191 hg log -T list
5184
5192
5185 - check if a given changeset is included in a tagged release::
5193 - check if a given changeset is included in a tagged release::
5186
5194
5187 hg log -r "a21ccf and ancestor(1.9)"
5195 hg log -r "a21ccf and ancestor(1.9)"
5188
5196
5189 - find all changesets by some user in a date range::
5197 - find all changesets by some user in a date range::
5190
5198
5191 hg log -k alice -d "may 2008 to jul 2008"
5199 hg log -k alice -d "may 2008 to jul 2008"
5192
5200
5193 - summary of all changesets after the last tag::
5201 - summary of all changesets after the last tag::
5194
5202
5195 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
5203 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
5196
5204
5197 See :hg:`help dates` for a list of formats valid for -d/--date.
5205 See :hg:`help dates` for a list of formats valid for -d/--date.
5198
5206
5199 See :hg:`help revisions` and :hg:`help revsets` for more about
5207 See :hg:`help revisions` and :hg:`help revsets` for more about
5200 specifying and ordering revisions.
5208 specifying and ordering revisions.
5201
5209
5202 See :hg:`help templates` for more about pre-packaged styles and
5210 See :hg:`help templates` for more about pre-packaged styles and
5203 specifying custom templates.
5211 specifying custom templates.
5204
5212
5205 Returns 0 on success.
5213 Returns 0 on success.
5206
5214
5207 """
5215 """
5208 if opts.get('follow') and opts.get('rev'):
5216 if opts.get('follow') and opts.get('rev'):
5209 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
5217 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
5210 del opts['follow']
5218 del opts['follow']
5211
5219
5212 if opts.get('graph'):
5220 if opts.get('graph'):
5213 return cmdutil.graphlog(ui, repo, *pats, **opts)
5221 return cmdutil.graphlog(ui, repo, *pats, **opts)
5214
5222
5215 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
5223 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
5216 limit = cmdutil.loglimit(opts)
5224 limit = cmdutil.loglimit(opts)
5217 count = 0
5225 count = 0
5218
5226
5219 getrenamed = None
5227 getrenamed = None
5220 if opts.get('copies'):
5228 if opts.get('copies'):
5221 endrev = None
5229 endrev = None
5222 if opts.get('rev'):
5230 if opts.get('rev'):
5223 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
5231 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
5224 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
5232 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
5225
5233
5226 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5234 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5227 for rev in revs:
5235 for rev in revs:
5228 if count == limit:
5236 if count == limit:
5229 break
5237 break
5230 ctx = repo[rev]
5238 ctx = repo[rev]
5231 copies = None
5239 copies = None
5232 if getrenamed is not None and rev:
5240 if getrenamed is not None and rev:
5233 copies = []
5241 copies = []
5234 for fn in ctx.files():
5242 for fn in ctx.files():
5235 rename = getrenamed(fn, rev)
5243 rename = getrenamed(fn, rev)
5236 if rename:
5244 if rename:
5237 copies.append((fn, rename[0]))
5245 copies.append((fn, rename[0]))
5238 if filematcher:
5246 if filematcher:
5239 revmatchfn = filematcher(ctx.rev())
5247 revmatchfn = filematcher(ctx.rev())
5240 else:
5248 else:
5241 revmatchfn = None
5249 revmatchfn = None
5242 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
5250 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
5243 if displayer.flush(ctx):
5251 if displayer.flush(ctx):
5244 count += 1
5252 count += 1
5245
5253
5246 displayer.close()
5254 displayer.close()
5247
5255
5248 @command('manifest',
5256 @command('manifest',
5249 [('r', 'rev', '', _('revision to display'), _('REV')),
5257 [('r', 'rev', '', _('revision to display'), _('REV')),
5250 ('', 'all', False, _("list files from all revisions"))]
5258 ('', 'all', False, _("list files from all revisions"))]
5251 + formatteropts,
5259 + formatteropts,
5252 _('[-r REV]'))
5260 _('[-r REV]'))
5253 def manifest(ui, repo, node=None, rev=None, **opts):
5261 def manifest(ui, repo, node=None, rev=None, **opts):
5254 """output the current or given revision of the project manifest
5262 """output the current or given revision of the project manifest
5255
5263
5256 Print a list of version controlled files for the given revision.
5264 Print a list of version controlled files for the given revision.
5257 If no revision is given, the first parent of the working directory
5265 If no revision is given, the first parent of the working directory
5258 is used, or the null revision if no revision is checked out.
5266 is used, or the null revision if no revision is checked out.
5259
5267
5260 With -v, print file permissions, symlink and executable bits.
5268 With -v, print file permissions, symlink and executable bits.
5261 With --debug, print file revision hashes.
5269 With --debug, print file revision hashes.
5262
5270
5263 If option --all is specified, the list of all files from all revisions
5271 If option --all is specified, the list of all files from all revisions
5264 is printed. This includes deleted and renamed files.
5272 is printed. This includes deleted and renamed files.
5265
5273
5266 Returns 0 on success.
5274 Returns 0 on success.
5267 """
5275 """
5268
5276
5269 fm = ui.formatter('manifest', opts)
5277 fm = ui.formatter('manifest', opts)
5270
5278
5271 if opts.get('all'):
5279 if opts.get('all'):
5272 if rev or node:
5280 if rev or node:
5273 raise error.Abort(_("can't specify a revision with --all"))
5281 raise error.Abort(_("can't specify a revision with --all"))
5274
5282
5275 res = []
5283 res = []
5276 prefix = "data/"
5284 prefix = "data/"
5277 suffix = ".i"
5285 suffix = ".i"
5278 plen = len(prefix)
5286 plen = len(prefix)
5279 slen = len(suffix)
5287 slen = len(suffix)
5280 with repo.lock():
5288 with repo.lock():
5281 for fn, b, size in repo.store.datafiles():
5289 for fn, b, size in repo.store.datafiles():
5282 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
5290 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
5283 res.append(fn[plen:-slen])
5291 res.append(fn[plen:-slen])
5284 for f in res:
5292 for f in res:
5285 fm.startitem()
5293 fm.startitem()
5286 fm.write("path", '%s\n', f)
5294 fm.write("path", '%s\n', f)
5287 fm.end()
5295 fm.end()
5288 return
5296 return
5289
5297
5290 if rev and node:
5298 if rev and node:
5291 raise error.Abort(_("please specify just one revision"))
5299 raise error.Abort(_("please specify just one revision"))
5292
5300
5293 if not node:
5301 if not node:
5294 node = rev
5302 node = rev
5295
5303
5296 char = {'l': '@', 'x': '*', '': ''}
5304 char = {'l': '@', 'x': '*', '': ''}
5297 mode = {'l': '644', 'x': '755', '': '644'}
5305 mode = {'l': '644', 'x': '755', '': '644'}
5298 ctx = scmutil.revsingle(repo, node)
5306 ctx = scmutil.revsingle(repo, node)
5299 mf = ctx.manifest()
5307 mf = ctx.manifest()
5300 for f in ctx:
5308 for f in ctx:
5301 fm.startitem()
5309 fm.startitem()
5302 fl = ctx[f].flags()
5310 fl = ctx[f].flags()
5303 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
5311 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
5304 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
5312 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
5305 fm.write('path', '%s\n', f)
5313 fm.write('path', '%s\n', f)
5306 fm.end()
5314 fm.end()
5307
5315
5308 @command('^merge',
5316 @command('^merge',
5309 [('f', 'force', None,
5317 [('f', 'force', None,
5310 _('force a merge including outstanding changes (DEPRECATED)')),
5318 _('force a merge including outstanding changes (DEPRECATED)')),
5311 ('r', 'rev', '', _('revision to merge'), _('REV')),
5319 ('r', 'rev', '', _('revision to merge'), _('REV')),
5312 ('P', 'preview', None,
5320 ('P', 'preview', None,
5313 _('review revisions to merge (no merge is performed)'))
5321 _('review revisions to merge (no merge is performed)'))
5314 ] + mergetoolopts,
5322 ] + mergetoolopts,
5315 _('[-P] [[-r] REV]'))
5323 _('[-P] [[-r] REV]'))
5316 def merge(ui, repo, node=None, **opts):
5324 def merge(ui, repo, node=None, **opts):
5317 """merge another revision into working directory
5325 """merge another revision into working directory
5318
5326
5319 The current working directory is updated with all changes made in
5327 The current working directory is updated with all changes made in
5320 the requested revision since the last common predecessor revision.
5328 the requested revision since the last common predecessor revision.
5321
5329
5322 Files that changed between either parent are marked as changed for
5330 Files that changed between either parent are marked as changed for
5323 the next commit and a commit must be performed before any further
5331 the next commit and a commit must be performed before any further
5324 updates to the repository are allowed. The next commit will have
5332 updates to the repository are allowed. The next commit will have
5325 two parents.
5333 two parents.
5326
5334
5327 ``--tool`` can be used to specify the merge tool used for file
5335 ``--tool`` can be used to specify the merge tool used for file
5328 merges. It overrides the HGMERGE environment variable and your
5336 merges. It overrides the HGMERGE environment variable and your
5329 configuration files. See :hg:`help merge-tools` for options.
5337 configuration files. See :hg:`help merge-tools` for options.
5330
5338
5331 If no revision is specified, the working directory's parent is a
5339 If no revision is specified, the working directory's parent is a
5332 head revision, and the current branch contains exactly one other
5340 head revision, and the current branch contains exactly one other
5333 head, the other head is merged with by default. Otherwise, an
5341 head, the other head is merged with by default. Otherwise, an
5334 explicit revision with which to merge with must be provided.
5342 explicit revision with which to merge with must be provided.
5335
5343
5336 See :hg:`help resolve` for information on handling file conflicts.
5344 See :hg:`help resolve` for information on handling file conflicts.
5337
5345
5338 To undo an uncommitted merge, use :hg:`update --clean .` which
5346 To undo an uncommitted merge, use :hg:`update --clean .` which
5339 will check out a clean copy of the original merge parent, losing
5347 will check out a clean copy of the original merge parent, losing
5340 all changes.
5348 all changes.
5341
5349
5342 Returns 0 on success, 1 if there are unresolved files.
5350 Returns 0 on success, 1 if there are unresolved files.
5343 """
5351 """
5344
5352
5345 if opts.get('rev') and node:
5353 if opts.get('rev') and node:
5346 raise error.Abort(_("please specify just one revision"))
5354 raise error.Abort(_("please specify just one revision"))
5347 if not node:
5355 if not node:
5348 node = opts.get('rev')
5356 node = opts.get('rev')
5349
5357
5350 if node:
5358 if node:
5351 node = scmutil.revsingle(repo, node).node()
5359 node = scmutil.revsingle(repo, node).node()
5352
5360
5353 if not node:
5361 if not node:
5354 node = repo[destutil.destmerge(repo)].node()
5362 node = repo[destutil.destmerge(repo)].node()
5355
5363
5356 if opts.get('preview'):
5364 if opts.get('preview'):
5357 # find nodes that are ancestors of p2 but not of p1
5365 # find nodes that are ancestors of p2 but not of p1
5358 p1 = repo.lookup('.')
5366 p1 = repo.lookup('.')
5359 p2 = repo.lookup(node)
5367 p2 = repo.lookup(node)
5360 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
5368 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
5361
5369
5362 displayer = cmdutil.show_changeset(ui, repo, opts)
5370 displayer = cmdutil.show_changeset(ui, repo, opts)
5363 for node in nodes:
5371 for node in nodes:
5364 displayer.show(repo[node])
5372 displayer.show(repo[node])
5365 displayer.close()
5373 displayer.close()
5366 return 0
5374 return 0
5367
5375
5368 try:
5376 try:
5369 # ui.forcemerge is an internal variable, do not document
5377 # ui.forcemerge is an internal variable, do not document
5370 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
5378 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
5371 force = opts.get('force')
5379 force = opts.get('force')
5372 return hg.merge(repo, node, force=force, mergeforce=force)
5380 return hg.merge(repo, node, force=force, mergeforce=force)
5373 finally:
5381 finally:
5374 ui.setconfig('ui', 'forcemerge', '', 'merge')
5382 ui.setconfig('ui', 'forcemerge', '', 'merge')
5375
5383
5376 @command('outgoing|out',
5384 @command('outgoing|out',
5377 [('f', 'force', None, _('run even when the destination is unrelated')),
5385 [('f', 'force', None, _('run even when the destination is unrelated')),
5378 ('r', 'rev', [],
5386 ('r', 'rev', [],
5379 _('a changeset intended to be included in the destination'), _('REV')),
5387 _('a changeset intended to be included in the destination'), _('REV')),
5380 ('n', 'newest-first', None, _('show newest record first')),
5388 ('n', 'newest-first', None, _('show newest record first')),
5381 ('B', 'bookmarks', False, _('compare bookmarks')),
5389 ('B', 'bookmarks', False, _('compare bookmarks')),
5382 ('b', 'branch', [], _('a specific branch you would like to push'),
5390 ('b', 'branch', [], _('a specific branch you would like to push'),
5383 _('BRANCH')),
5391 _('BRANCH')),
5384 ] + logopts + remoteopts + subrepoopts,
5392 ] + logopts + remoteopts + subrepoopts,
5385 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
5393 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
5386 def outgoing(ui, repo, dest=None, **opts):
5394 def outgoing(ui, repo, dest=None, **opts):
5387 """show changesets not found in the destination
5395 """show changesets not found in the destination
5388
5396
5389 Show changesets not found in the specified destination repository
5397 Show changesets not found in the specified destination repository
5390 or the default push location. These are the changesets that would
5398 or the default push location. These are the changesets that would
5391 be pushed if a push was requested.
5399 be pushed if a push was requested.
5392
5400
5393 See pull for details of valid destination formats.
5401 See pull for details of valid destination formats.
5394
5402
5395 .. container:: verbose
5403 .. container:: verbose
5396
5404
5397 With -B/--bookmarks, the result of bookmark comparison between
5405 With -B/--bookmarks, the result of bookmark comparison between
5398 local and remote repositories is displayed. With -v/--verbose,
5406 local and remote repositories is displayed. With -v/--verbose,
5399 status is also displayed for each bookmark like below::
5407 status is also displayed for each bookmark like below::
5400
5408
5401 BM1 01234567890a added
5409 BM1 01234567890a added
5402 BM2 deleted
5410 BM2 deleted
5403 BM3 234567890abc advanced
5411 BM3 234567890abc advanced
5404 BM4 34567890abcd diverged
5412 BM4 34567890abcd diverged
5405 BM5 4567890abcde changed
5413 BM5 4567890abcde changed
5406
5414
5407 The action taken when pushing depends on the
5415 The action taken when pushing depends on the
5408 status of each bookmark:
5416 status of each bookmark:
5409
5417
5410 :``added``: push with ``-B`` will create it
5418 :``added``: push with ``-B`` will create it
5411 :``deleted``: push with ``-B`` will delete it
5419 :``deleted``: push with ``-B`` will delete it
5412 :``advanced``: push will update it
5420 :``advanced``: push will update it
5413 :``diverged``: push with ``-B`` will update it
5421 :``diverged``: push with ``-B`` will update it
5414 :``changed``: push with ``-B`` will update it
5422 :``changed``: push with ``-B`` will update it
5415
5423
5416 From the point of view of pushing behavior, bookmarks
5424 From the point of view of pushing behavior, bookmarks
5417 existing only in the remote repository are treated as
5425 existing only in the remote repository are treated as
5418 ``deleted``, even if it is in fact added remotely.
5426 ``deleted``, even if it is in fact added remotely.
5419
5427
5420 Returns 0 if there are outgoing changes, 1 otherwise.
5428 Returns 0 if there are outgoing changes, 1 otherwise.
5421 """
5429 """
5422 if opts.get('graph'):
5430 if opts.get('graph'):
5423 cmdutil.checkunsupportedgraphflags([], opts)
5431 cmdutil.checkunsupportedgraphflags([], opts)
5424 o, other = hg._outgoing(ui, repo, dest, opts)
5432 o, other = hg._outgoing(ui, repo, dest, opts)
5425 if not o:
5433 if not o:
5426 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5434 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5427 return
5435 return
5428
5436
5429 revdag = cmdutil.graphrevs(repo, o, opts)
5437 revdag = cmdutil.graphrevs(repo, o, opts)
5430 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5438 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5431 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
5439 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
5432 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5440 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5433 return 0
5441 return 0
5434
5442
5435 if opts.get('bookmarks'):
5443 if opts.get('bookmarks'):
5436 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5444 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5437 dest, branches = hg.parseurl(dest, opts.get('branch'))
5445 dest, branches = hg.parseurl(dest, opts.get('branch'))
5438 other = hg.peer(repo, opts, dest)
5446 other = hg.peer(repo, opts, dest)
5439 if 'bookmarks' not in other.listkeys('namespaces'):
5447 if 'bookmarks' not in other.listkeys('namespaces'):
5440 ui.warn(_("remote doesn't support bookmarks\n"))
5448 ui.warn(_("remote doesn't support bookmarks\n"))
5441 return 0
5449 return 0
5442 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
5450 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
5443 return bookmarks.outgoing(ui, repo, other)
5451 return bookmarks.outgoing(ui, repo, other)
5444
5452
5445 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
5453 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
5446 try:
5454 try:
5447 return hg.outgoing(ui, repo, dest, opts)
5455 return hg.outgoing(ui, repo, dest, opts)
5448 finally:
5456 finally:
5449 del repo._subtoppath
5457 del repo._subtoppath
5450
5458
5451 @command('parents',
5459 @command('parents',
5452 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
5460 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
5453 ] + templateopts,
5461 ] + templateopts,
5454 _('[-r REV] [FILE]'),
5462 _('[-r REV] [FILE]'),
5455 inferrepo=True)
5463 inferrepo=True)
5456 def parents(ui, repo, file_=None, **opts):
5464 def parents(ui, repo, file_=None, **opts):
5457 """show the parents of the working directory or revision (DEPRECATED)
5465 """show the parents of the working directory or revision (DEPRECATED)
5458
5466
5459 Print the working directory's parent revisions. If a revision is
5467 Print the working directory's parent revisions. If a revision is
5460 given via -r/--rev, the parent of that revision will be printed.
5468 given via -r/--rev, the parent of that revision will be printed.
5461 If a file argument is given, the revision in which the file was
5469 If a file argument is given, the revision in which the file was
5462 last changed (before the working directory revision or the
5470 last changed (before the working directory revision or the
5463 argument to --rev if given) is printed.
5471 argument to --rev if given) is printed.
5464
5472
5465 This command is equivalent to::
5473 This command is equivalent to::
5466
5474
5467 hg log -r "p1()+p2()" or
5475 hg log -r "p1()+p2()" or
5468 hg log -r "p1(REV)+p2(REV)" or
5476 hg log -r "p1(REV)+p2(REV)" or
5469 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5477 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5470 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5478 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5471
5479
5472 See :hg:`summary` and :hg:`help revsets` for related information.
5480 See :hg:`summary` and :hg:`help revsets` for related information.
5473
5481
5474 Returns 0 on success.
5482 Returns 0 on success.
5475 """
5483 """
5476
5484
5477 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5485 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5478
5486
5479 if file_:
5487 if file_:
5480 m = scmutil.match(ctx, (file_,), opts)
5488 m = scmutil.match(ctx, (file_,), opts)
5481 if m.anypats() or len(m.files()) != 1:
5489 if m.anypats() or len(m.files()) != 1:
5482 raise error.Abort(_('can only specify an explicit filename'))
5490 raise error.Abort(_('can only specify an explicit filename'))
5483 file_ = m.files()[0]
5491 file_ = m.files()[0]
5484 filenodes = []
5492 filenodes = []
5485 for cp in ctx.parents():
5493 for cp in ctx.parents():
5486 if not cp:
5494 if not cp:
5487 continue
5495 continue
5488 try:
5496 try:
5489 filenodes.append(cp.filenode(file_))
5497 filenodes.append(cp.filenode(file_))
5490 except error.LookupError:
5498 except error.LookupError:
5491 pass
5499 pass
5492 if not filenodes:
5500 if not filenodes:
5493 raise error.Abort(_("'%s' not found in manifest!") % file_)
5501 raise error.Abort(_("'%s' not found in manifest!") % file_)
5494 p = []
5502 p = []
5495 for fn in filenodes:
5503 for fn in filenodes:
5496 fctx = repo.filectx(file_, fileid=fn)
5504 fctx = repo.filectx(file_, fileid=fn)
5497 p.append(fctx.node())
5505 p.append(fctx.node())
5498 else:
5506 else:
5499 p = [cp.node() for cp in ctx.parents()]
5507 p = [cp.node() for cp in ctx.parents()]
5500
5508
5501 displayer = cmdutil.show_changeset(ui, repo, opts)
5509 displayer = cmdutil.show_changeset(ui, repo, opts)
5502 for n in p:
5510 for n in p:
5503 if n != nullid:
5511 if n != nullid:
5504 displayer.show(repo[n])
5512 displayer.show(repo[n])
5505 displayer.close()
5513 displayer.close()
5506
5514
5507 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
5515 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
5508 def paths(ui, repo, search=None, **opts):
5516 def paths(ui, repo, search=None, **opts):
5509 """show aliases for remote repositories
5517 """show aliases for remote repositories
5510
5518
5511 Show definition of symbolic path name NAME. If no name is given,
5519 Show definition of symbolic path name NAME. If no name is given,
5512 show definition of all available names.
5520 show definition of all available names.
5513
5521
5514 Option -q/--quiet suppresses all output when searching for NAME
5522 Option -q/--quiet suppresses all output when searching for NAME
5515 and shows only the path names when listing all definitions.
5523 and shows only the path names when listing all definitions.
5516
5524
5517 Path names are defined in the [paths] section of your
5525 Path names are defined in the [paths] section of your
5518 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5526 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5519 repository, ``.hg/hgrc`` is used, too.
5527 repository, ``.hg/hgrc`` is used, too.
5520
5528
5521 The path names ``default`` and ``default-push`` have a special
5529 The path names ``default`` and ``default-push`` have a special
5522 meaning. When performing a push or pull operation, they are used
5530 meaning. When performing a push or pull operation, they are used
5523 as fallbacks if no location is specified on the command-line.
5531 as fallbacks if no location is specified on the command-line.
5524 When ``default-push`` is set, it will be used for push and
5532 When ``default-push`` is set, it will be used for push and
5525 ``default`` will be used for pull; otherwise ``default`` is used
5533 ``default`` will be used for pull; otherwise ``default`` is used
5526 as the fallback for both. When cloning a repository, the clone
5534 as the fallback for both. When cloning a repository, the clone
5527 source is written as ``default`` in ``.hg/hgrc``.
5535 source is written as ``default`` in ``.hg/hgrc``.
5528
5536
5529 .. note::
5537 .. note::
5530
5538
5531 ``default`` and ``default-push`` apply to all inbound (e.g.
5539 ``default`` and ``default-push`` apply to all inbound (e.g.
5532 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5540 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5533 and :hg:`bundle`) operations.
5541 and :hg:`bundle`) operations.
5534
5542
5535 See :hg:`help urls` for more information.
5543 See :hg:`help urls` for more information.
5536
5544
5537 Returns 0 on success.
5545 Returns 0 on success.
5538 """
5546 """
5539 if search:
5547 if search:
5540 pathitems = [(name, path) for name, path in ui.paths.iteritems()
5548 pathitems = [(name, path) for name, path in ui.paths.iteritems()
5541 if name == search]
5549 if name == search]
5542 else:
5550 else:
5543 pathitems = sorted(ui.paths.iteritems())
5551 pathitems = sorted(ui.paths.iteritems())
5544
5552
5545 fm = ui.formatter('paths', opts)
5553 fm = ui.formatter('paths', opts)
5546 if fm:
5554 if fm:
5547 hidepassword = str
5555 hidepassword = str
5548 else:
5556 else:
5549 hidepassword = util.hidepassword
5557 hidepassword = util.hidepassword
5550 if ui.quiet:
5558 if ui.quiet:
5551 namefmt = '%s\n'
5559 namefmt = '%s\n'
5552 else:
5560 else:
5553 namefmt = '%s = '
5561 namefmt = '%s = '
5554 showsubopts = not search and not ui.quiet
5562 showsubopts = not search and not ui.quiet
5555
5563
5556 for name, path in pathitems:
5564 for name, path in pathitems:
5557 fm.startitem()
5565 fm.startitem()
5558 fm.condwrite(not search, 'name', namefmt, name)
5566 fm.condwrite(not search, 'name', namefmt, name)
5559 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
5567 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
5560 for subopt, value in sorted(path.suboptions.items()):
5568 for subopt, value in sorted(path.suboptions.items()):
5561 assert subopt not in ('name', 'url')
5569 assert subopt not in ('name', 'url')
5562 if showsubopts:
5570 if showsubopts:
5563 fm.plain('%s:%s = ' % (name, subopt))
5571 fm.plain('%s:%s = ' % (name, subopt))
5564 fm.condwrite(showsubopts, subopt, '%s\n', value)
5572 fm.condwrite(showsubopts, subopt, '%s\n', value)
5565
5573
5566 fm.end()
5574 fm.end()
5567
5575
5568 if search and not pathitems:
5576 if search and not pathitems:
5569 if not ui.quiet:
5577 if not ui.quiet:
5570 ui.warn(_("not found!\n"))
5578 ui.warn(_("not found!\n"))
5571 return 1
5579 return 1
5572 else:
5580 else:
5573 return 0
5581 return 0
5574
5582
5575 @command('phase',
5583 @command('phase',
5576 [('p', 'public', False, _('set changeset phase to public')),
5584 [('p', 'public', False, _('set changeset phase to public')),
5577 ('d', 'draft', False, _('set changeset phase to draft')),
5585 ('d', 'draft', False, _('set changeset phase to draft')),
5578 ('s', 'secret', False, _('set changeset phase to secret')),
5586 ('s', 'secret', False, _('set changeset phase to secret')),
5579 ('f', 'force', False, _('allow to move boundary backward')),
5587 ('f', 'force', False, _('allow to move boundary backward')),
5580 ('r', 'rev', [], _('target revision'), _('REV')),
5588 ('r', 'rev', [], _('target revision'), _('REV')),
5581 ],
5589 ],
5582 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5590 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5583 def phase(ui, repo, *revs, **opts):
5591 def phase(ui, repo, *revs, **opts):
5584 """set or show the current phase name
5592 """set or show the current phase name
5585
5593
5586 With no argument, show the phase name of the current revision(s).
5594 With no argument, show the phase name of the current revision(s).
5587
5595
5588 With one of -p/--public, -d/--draft or -s/--secret, change the
5596 With one of -p/--public, -d/--draft or -s/--secret, change the
5589 phase value of the specified revisions.
5597 phase value of the specified revisions.
5590
5598
5591 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
5599 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
5592 lower phase to an higher phase. Phases are ordered as follows::
5600 lower phase to an higher phase. Phases are ordered as follows::
5593
5601
5594 public < draft < secret
5602 public < draft < secret
5595
5603
5596 Returns 0 on success, 1 if some phases could not be changed.
5604 Returns 0 on success, 1 if some phases could not be changed.
5597
5605
5598 (For more information about the phases concept, see :hg:`help phases`.)
5606 (For more information about the phases concept, see :hg:`help phases`.)
5599 """
5607 """
5600 # search for a unique phase argument
5608 # search for a unique phase argument
5601 targetphase = None
5609 targetphase = None
5602 for idx, name in enumerate(phases.phasenames):
5610 for idx, name in enumerate(phases.phasenames):
5603 if opts[name]:
5611 if opts[name]:
5604 if targetphase is not None:
5612 if targetphase is not None:
5605 raise error.Abort(_('only one phase can be specified'))
5613 raise error.Abort(_('only one phase can be specified'))
5606 targetphase = idx
5614 targetphase = idx
5607
5615
5608 # look for specified revision
5616 # look for specified revision
5609 revs = list(revs)
5617 revs = list(revs)
5610 revs.extend(opts['rev'])
5618 revs.extend(opts['rev'])
5611 if not revs:
5619 if not revs:
5612 # display both parents as the second parent phase can influence
5620 # display both parents as the second parent phase can influence
5613 # the phase of a merge commit
5621 # the phase of a merge commit
5614 revs = [c.rev() for c in repo[None].parents()]
5622 revs = [c.rev() for c in repo[None].parents()]
5615
5623
5616 revs = scmutil.revrange(repo, revs)
5624 revs = scmutil.revrange(repo, revs)
5617
5625
5618 lock = None
5626 lock = None
5619 ret = 0
5627 ret = 0
5620 if targetphase is None:
5628 if targetphase is None:
5621 # display
5629 # display
5622 for r in revs:
5630 for r in revs:
5623 ctx = repo[r]
5631 ctx = repo[r]
5624 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5632 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5625 else:
5633 else:
5626 tr = None
5634 tr = None
5627 lock = repo.lock()
5635 lock = repo.lock()
5628 try:
5636 try:
5629 tr = repo.transaction("phase")
5637 tr = repo.transaction("phase")
5630 # set phase
5638 # set phase
5631 if not revs:
5639 if not revs:
5632 raise error.Abort(_('empty revision set'))
5640 raise error.Abort(_('empty revision set'))
5633 nodes = [repo[r].node() for r in revs]
5641 nodes = [repo[r].node() for r in revs]
5634 # moving revision from public to draft may hide them
5642 # moving revision from public to draft may hide them
5635 # We have to check result on an unfiltered repository
5643 # We have to check result on an unfiltered repository
5636 unfi = repo.unfiltered()
5644 unfi = repo.unfiltered()
5637 getphase = unfi._phasecache.phase
5645 getphase = unfi._phasecache.phase
5638 olddata = [getphase(unfi, r) for r in unfi]
5646 olddata = [getphase(unfi, r) for r in unfi]
5639 phases.advanceboundary(repo, tr, targetphase, nodes)
5647 phases.advanceboundary(repo, tr, targetphase, nodes)
5640 if opts['force']:
5648 if opts['force']:
5641 phases.retractboundary(repo, tr, targetphase, nodes)
5649 phases.retractboundary(repo, tr, targetphase, nodes)
5642 tr.close()
5650 tr.close()
5643 finally:
5651 finally:
5644 if tr is not None:
5652 if tr is not None:
5645 tr.release()
5653 tr.release()
5646 lock.release()
5654 lock.release()
5647 getphase = unfi._phasecache.phase
5655 getphase = unfi._phasecache.phase
5648 newdata = [getphase(unfi, r) for r in unfi]
5656 newdata = [getphase(unfi, r) for r in unfi]
5649 changes = sum(newdata[r] != olddata[r] for r in unfi)
5657 changes = sum(newdata[r] != olddata[r] for r in unfi)
5650 cl = unfi.changelog
5658 cl = unfi.changelog
5651 rejected = [n for n in nodes
5659 rejected = [n for n in nodes
5652 if newdata[cl.rev(n)] < targetphase]
5660 if newdata[cl.rev(n)] < targetphase]
5653 if rejected:
5661 if rejected:
5654 ui.warn(_('cannot move %i changesets to a higher '
5662 ui.warn(_('cannot move %i changesets to a higher '
5655 'phase, use --force\n') % len(rejected))
5663 'phase, use --force\n') % len(rejected))
5656 ret = 1
5664 ret = 1
5657 if changes:
5665 if changes:
5658 msg = _('phase changed for %i changesets\n') % changes
5666 msg = _('phase changed for %i changesets\n') % changes
5659 if ret:
5667 if ret:
5660 ui.status(msg)
5668 ui.status(msg)
5661 else:
5669 else:
5662 ui.note(msg)
5670 ui.note(msg)
5663 else:
5671 else:
5664 ui.warn(_('no phases changed\n'))
5672 ui.warn(_('no phases changed\n'))
5665 return ret
5673 return ret
5666
5674
5667 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5675 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5668 """Run after a changegroup has been added via pull/unbundle
5676 """Run after a changegroup has been added via pull/unbundle
5669
5677
5670 This takes arguments below:
5678 This takes arguments below:
5671
5679
5672 :modheads: change of heads by pull/unbundle
5680 :modheads: change of heads by pull/unbundle
5673 :optupdate: updating working directory is needed or not
5681 :optupdate: updating working directory is needed or not
5674 :checkout: update destination revision (or None to default destination)
5682 :checkout: update destination revision (or None to default destination)
5675 :brev: a name, which might be a bookmark to be activated after updating
5683 :brev: a name, which might be a bookmark to be activated after updating
5676 """
5684 """
5677 if modheads == 0:
5685 if modheads == 0:
5678 return
5686 return
5679 if optupdate:
5687 if optupdate:
5680 try:
5688 try:
5681 return hg.updatetotally(ui, repo, checkout, brev)
5689 return hg.updatetotally(ui, repo, checkout, brev)
5682 except error.UpdateAbort as inst:
5690 except error.UpdateAbort as inst:
5683 msg = _("not updating: %s") % str(inst)
5691 msg = _("not updating: %s") % str(inst)
5684 hint = inst.hint
5692 hint = inst.hint
5685 raise error.UpdateAbort(msg, hint=hint)
5693 raise error.UpdateAbort(msg, hint=hint)
5686 if modheads > 1:
5694 if modheads > 1:
5687 currentbranchheads = len(repo.branchheads())
5695 currentbranchheads = len(repo.branchheads())
5688 if currentbranchheads == modheads:
5696 if currentbranchheads == modheads:
5689 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5697 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5690 elif currentbranchheads > 1:
5698 elif currentbranchheads > 1:
5691 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5699 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5692 "merge)\n"))
5700 "merge)\n"))
5693 else:
5701 else:
5694 ui.status(_("(run 'hg heads' to see heads)\n"))
5702 ui.status(_("(run 'hg heads' to see heads)\n"))
5695 else:
5703 else:
5696 ui.status(_("(run 'hg update' to get a working copy)\n"))
5704 ui.status(_("(run 'hg update' to get a working copy)\n"))
5697
5705
5698 @command('^pull',
5706 @command('^pull',
5699 [('u', 'update', None,
5707 [('u', 'update', None,
5700 _('update to new branch head if changesets were pulled')),
5708 _('update to new branch head if changesets were pulled')),
5701 ('f', 'force', None, _('run even when remote repository is unrelated')),
5709 ('f', 'force', None, _('run even when remote repository is unrelated')),
5702 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5710 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5703 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5711 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5704 ('b', 'branch', [], _('a specific branch you would like to pull'),
5712 ('b', 'branch', [], _('a specific branch you would like to pull'),
5705 _('BRANCH')),
5713 _('BRANCH')),
5706 ] + remoteopts,
5714 ] + remoteopts,
5707 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5715 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5708 def pull(ui, repo, source="default", **opts):
5716 def pull(ui, repo, source="default", **opts):
5709 """pull changes from the specified source
5717 """pull changes from the specified source
5710
5718
5711 Pull changes from a remote repository to a local one.
5719 Pull changes from a remote repository to a local one.
5712
5720
5713 This finds all changes from the repository at the specified path
5721 This finds all changes from the repository at the specified path
5714 or URL and adds them to a local repository (the current one unless
5722 or URL and adds them to a local repository (the current one unless
5715 -R is specified). By default, this does not update the copy of the
5723 -R is specified). By default, this does not update the copy of the
5716 project in the working directory.
5724 project in the working directory.
5717
5725
5718 Use :hg:`incoming` if you want to see what would have been added
5726 Use :hg:`incoming` if you want to see what would have been added
5719 by a pull at the time you issued this command. If you then decide
5727 by a pull at the time you issued this command. If you then decide
5720 to add those changes to the repository, you should use :hg:`pull
5728 to add those changes to the repository, you should use :hg:`pull
5721 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5729 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5722
5730
5723 If SOURCE is omitted, the 'default' path will be used.
5731 If SOURCE is omitted, the 'default' path will be used.
5724 See :hg:`help urls` for more information.
5732 See :hg:`help urls` for more information.
5725
5733
5726 Returns 0 on success, 1 if an update had unresolved files.
5734 Returns 0 on success, 1 if an update had unresolved files.
5727 """
5735 """
5728 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5736 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5729 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5737 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5730 other = hg.peer(repo, opts, source)
5738 other = hg.peer(repo, opts, source)
5731 try:
5739 try:
5732 revs, checkout = hg.addbranchrevs(repo, other, branches,
5740 revs, checkout = hg.addbranchrevs(repo, other, branches,
5733 opts.get('rev'))
5741 opts.get('rev'))
5734
5742
5735
5743
5736 pullopargs = {}
5744 pullopargs = {}
5737 if opts.get('bookmark'):
5745 if opts.get('bookmark'):
5738 if not revs:
5746 if not revs:
5739 revs = []
5747 revs = []
5740 # The list of bookmark used here is not the one used to actually
5748 # The list of bookmark used here is not the one used to actually
5741 # update the bookmark name. This can result in the revision pulled
5749 # update the bookmark name. This can result in the revision pulled
5742 # not ending up with the name of the bookmark because of a race
5750 # not ending up with the name of the bookmark because of a race
5743 # condition on the server. (See issue 4689 for details)
5751 # condition on the server. (See issue 4689 for details)
5744 remotebookmarks = other.listkeys('bookmarks')
5752 remotebookmarks = other.listkeys('bookmarks')
5745 pullopargs['remotebookmarks'] = remotebookmarks
5753 pullopargs['remotebookmarks'] = remotebookmarks
5746 for b in opts['bookmark']:
5754 for b in opts['bookmark']:
5747 if b not in remotebookmarks:
5755 if b not in remotebookmarks:
5748 raise error.Abort(_('remote bookmark %s not found!') % b)
5756 raise error.Abort(_('remote bookmark %s not found!') % b)
5749 revs.append(remotebookmarks[b])
5757 revs.append(remotebookmarks[b])
5750
5758
5751 if revs:
5759 if revs:
5752 try:
5760 try:
5753 # When 'rev' is a bookmark name, we cannot guarantee that it
5761 # When 'rev' is a bookmark name, we cannot guarantee that it
5754 # will be updated with that name because of a race condition
5762 # will be updated with that name because of a race condition
5755 # server side. (See issue 4689 for details)
5763 # server side. (See issue 4689 for details)
5756 oldrevs = revs
5764 oldrevs = revs
5757 revs = [] # actually, nodes
5765 revs = [] # actually, nodes
5758 for r in oldrevs:
5766 for r in oldrevs:
5759 node = other.lookup(r)
5767 node = other.lookup(r)
5760 revs.append(node)
5768 revs.append(node)
5761 if r == checkout:
5769 if r == checkout:
5762 checkout = node
5770 checkout = node
5763 except error.CapabilityError:
5771 except error.CapabilityError:
5764 err = _("other repository doesn't support revision lookup, "
5772 err = _("other repository doesn't support revision lookup, "
5765 "so a rev cannot be specified.")
5773 "so a rev cannot be specified.")
5766 raise error.Abort(err)
5774 raise error.Abort(err)
5767
5775
5768 pullopargs.update(opts.get('opargs', {}))
5776 pullopargs.update(opts.get('opargs', {}))
5769 modheads = exchange.pull(repo, other, heads=revs,
5777 modheads = exchange.pull(repo, other, heads=revs,
5770 force=opts.get('force'),
5778 force=opts.get('force'),
5771 bookmarks=opts.get('bookmark', ()),
5779 bookmarks=opts.get('bookmark', ()),
5772 opargs=pullopargs).cgresult
5780 opargs=pullopargs).cgresult
5773
5781
5774 # brev is a name, which might be a bookmark to be activated at
5782 # brev is a name, which might be a bookmark to be activated at
5775 # the end of the update. In other words, it is an explicit
5783 # the end of the update. In other words, it is an explicit
5776 # destination of the update
5784 # destination of the update
5777 brev = None
5785 brev = None
5778
5786
5779 if checkout:
5787 if checkout:
5780 checkout = str(repo.changelog.rev(checkout))
5788 checkout = str(repo.changelog.rev(checkout))
5781
5789
5782 # order below depends on implementation of
5790 # order below depends on implementation of
5783 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5791 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5784 # because 'checkout' is determined without it.
5792 # because 'checkout' is determined without it.
5785 if opts.get('rev'):
5793 if opts.get('rev'):
5786 brev = opts['rev'][0]
5794 brev = opts['rev'][0]
5787 elif opts.get('branch'):
5795 elif opts.get('branch'):
5788 brev = opts['branch'][0]
5796 brev = opts['branch'][0]
5789 else:
5797 else:
5790 brev = branches[0]
5798 brev = branches[0]
5791 repo._subtoppath = source
5799 repo._subtoppath = source
5792 try:
5800 try:
5793 ret = postincoming(ui, repo, modheads, opts.get('update'),
5801 ret = postincoming(ui, repo, modheads, opts.get('update'),
5794 checkout, brev)
5802 checkout, brev)
5795
5803
5796 finally:
5804 finally:
5797 del repo._subtoppath
5805 del repo._subtoppath
5798
5806
5799 finally:
5807 finally:
5800 other.close()
5808 other.close()
5801 return ret
5809 return ret
5802
5810
5803 @command('^push',
5811 @command('^push',
5804 [('f', 'force', None, _('force push')),
5812 [('f', 'force', None, _('force push')),
5805 ('r', 'rev', [],
5813 ('r', 'rev', [],
5806 _('a changeset intended to be included in the destination'),
5814 _('a changeset intended to be included in the destination'),
5807 _('REV')),
5815 _('REV')),
5808 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5816 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5809 ('b', 'branch', [],
5817 ('b', 'branch', [],
5810 _('a specific branch you would like to push'), _('BRANCH')),
5818 _('a specific branch you would like to push'), _('BRANCH')),
5811 ('', 'new-branch', False, _('allow pushing a new branch')),
5819 ('', 'new-branch', False, _('allow pushing a new branch')),
5812 ] + remoteopts,
5820 ] + remoteopts,
5813 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5821 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5814 def push(ui, repo, dest=None, **opts):
5822 def push(ui, repo, dest=None, **opts):
5815 """push changes to the specified destination
5823 """push changes to the specified destination
5816
5824
5817 Push changesets from the local repository to the specified
5825 Push changesets from the local repository to the specified
5818 destination.
5826 destination.
5819
5827
5820 This operation is symmetrical to pull: it is identical to a pull
5828 This operation is symmetrical to pull: it is identical to a pull
5821 in the destination repository from the current one.
5829 in the destination repository from the current one.
5822
5830
5823 By default, push will not allow creation of new heads at the
5831 By default, push will not allow creation of new heads at the
5824 destination, since multiple heads would make it unclear which head
5832 destination, since multiple heads would make it unclear which head
5825 to use. In this situation, it is recommended to pull and merge
5833 to use. In this situation, it is recommended to pull and merge
5826 before pushing.
5834 before pushing.
5827
5835
5828 Use --new-branch if you want to allow push to create a new named
5836 Use --new-branch if you want to allow push to create a new named
5829 branch that is not present at the destination. This allows you to
5837 branch that is not present at the destination. This allows you to
5830 only create a new branch without forcing other changes.
5838 only create a new branch without forcing other changes.
5831
5839
5832 .. note::
5840 .. note::
5833
5841
5834 Extra care should be taken with the -f/--force option,
5842 Extra care should be taken with the -f/--force option,
5835 which will push all new heads on all branches, an action which will
5843 which will push all new heads on all branches, an action which will
5836 almost always cause confusion for collaborators.
5844 almost always cause confusion for collaborators.
5837
5845
5838 If -r/--rev is used, the specified revision and all its ancestors
5846 If -r/--rev is used, the specified revision and all its ancestors
5839 will be pushed to the remote repository.
5847 will be pushed to the remote repository.
5840
5848
5841 If -B/--bookmark is used, the specified bookmarked revision, its
5849 If -B/--bookmark is used, the specified bookmarked revision, its
5842 ancestors, and the bookmark will be pushed to the remote
5850 ancestors, and the bookmark will be pushed to the remote
5843 repository. Specifying ``.`` is equivalent to specifying the active
5851 repository. Specifying ``.`` is equivalent to specifying the active
5844 bookmark's name.
5852 bookmark's name.
5845
5853
5846 Please see :hg:`help urls` for important details about ``ssh://``
5854 Please see :hg:`help urls` for important details about ``ssh://``
5847 URLs. If DESTINATION is omitted, a default path will be used.
5855 URLs. If DESTINATION is omitted, a default path will be used.
5848
5856
5849 Returns 0 if push was successful, 1 if nothing to push.
5857 Returns 0 if push was successful, 1 if nothing to push.
5850 """
5858 """
5851
5859
5852 if opts.get('bookmark'):
5860 if opts.get('bookmark'):
5853 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5861 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5854 for b in opts['bookmark']:
5862 for b in opts['bookmark']:
5855 # translate -B options to -r so changesets get pushed
5863 # translate -B options to -r so changesets get pushed
5856 b = repo._bookmarks.expandname(b)
5864 b = repo._bookmarks.expandname(b)
5857 if b in repo._bookmarks:
5865 if b in repo._bookmarks:
5858 opts.setdefault('rev', []).append(b)
5866 opts.setdefault('rev', []).append(b)
5859 else:
5867 else:
5860 # if we try to push a deleted bookmark, translate it to null
5868 # if we try to push a deleted bookmark, translate it to null
5861 # this lets simultaneous -r, -b options continue working
5869 # this lets simultaneous -r, -b options continue working
5862 opts.setdefault('rev', []).append("null")
5870 opts.setdefault('rev', []).append("null")
5863
5871
5864 path = ui.paths.getpath(dest, default=('default-push', 'default'))
5872 path = ui.paths.getpath(dest, default=('default-push', 'default'))
5865 if not path:
5873 if not path:
5866 raise error.Abort(_('default repository not configured!'),
5874 raise error.Abort(_('default repository not configured!'),
5867 hint=_('see the "path" section in "hg help config"'))
5875 hint=_('see the "path" section in "hg help config"'))
5868 dest = path.pushloc or path.loc
5876 dest = path.pushloc or path.loc
5869 branches = (path.branch, opts.get('branch') or [])
5877 branches = (path.branch, opts.get('branch') or [])
5870 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5878 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5871 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5879 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5872 other = hg.peer(repo, opts, dest)
5880 other = hg.peer(repo, opts, dest)
5873
5881
5874 if revs:
5882 if revs:
5875 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5883 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5876 if not revs:
5884 if not revs:
5877 raise error.Abort(_("specified revisions evaluate to an empty set"),
5885 raise error.Abort(_("specified revisions evaluate to an empty set"),
5878 hint=_("use different revision arguments"))
5886 hint=_("use different revision arguments"))
5879
5887
5880 repo._subtoppath = dest
5888 repo._subtoppath = dest
5881 try:
5889 try:
5882 # push subrepos depth-first for coherent ordering
5890 # push subrepos depth-first for coherent ordering
5883 c = repo['']
5891 c = repo['']
5884 subs = c.substate # only repos that are committed
5892 subs = c.substate # only repos that are committed
5885 for s in sorted(subs):
5893 for s in sorted(subs):
5886 result = c.sub(s).push(opts)
5894 result = c.sub(s).push(opts)
5887 if result == 0:
5895 if result == 0:
5888 return not result
5896 return not result
5889 finally:
5897 finally:
5890 del repo._subtoppath
5898 del repo._subtoppath
5891 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5899 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5892 newbranch=opts.get('new_branch'),
5900 newbranch=opts.get('new_branch'),
5893 bookmarks=opts.get('bookmark', ()),
5901 bookmarks=opts.get('bookmark', ()),
5894 opargs=opts.get('opargs'))
5902 opargs=opts.get('opargs'))
5895
5903
5896 result = not pushop.cgresult
5904 result = not pushop.cgresult
5897
5905
5898 if pushop.bkresult is not None:
5906 if pushop.bkresult is not None:
5899 if pushop.bkresult == 2:
5907 if pushop.bkresult == 2:
5900 result = 2
5908 result = 2
5901 elif not result and pushop.bkresult:
5909 elif not result and pushop.bkresult:
5902 result = 2
5910 result = 2
5903
5911
5904 return result
5912 return result
5905
5913
5906 @command('recover', [])
5914 @command('recover', [])
5907 def recover(ui, repo):
5915 def recover(ui, repo):
5908 """roll back an interrupted transaction
5916 """roll back an interrupted transaction
5909
5917
5910 Recover from an interrupted commit or pull.
5918 Recover from an interrupted commit or pull.
5911
5919
5912 This command tries to fix the repository status after an
5920 This command tries to fix the repository status after an
5913 interrupted operation. It should only be necessary when Mercurial
5921 interrupted operation. It should only be necessary when Mercurial
5914 suggests it.
5922 suggests it.
5915
5923
5916 Returns 0 if successful, 1 if nothing to recover or verify fails.
5924 Returns 0 if successful, 1 if nothing to recover or verify fails.
5917 """
5925 """
5918 if repo.recover():
5926 if repo.recover():
5919 return hg.verify(repo)
5927 return hg.verify(repo)
5920 return 1
5928 return 1
5921
5929
5922 @command('^remove|rm',
5930 @command('^remove|rm',
5923 [('A', 'after', None, _('record delete for missing files')),
5931 [('A', 'after', None, _('record delete for missing files')),
5924 ('f', 'force', None,
5932 ('f', 'force', None,
5925 _('remove (and delete) file even if added or modified')),
5933 _('remove (and delete) file even if added or modified')),
5926 ] + subrepoopts + walkopts,
5934 ] + subrepoopts + walkopts,
5927 _('[OPTION]... FILE...'),
5935 _('[OPTION]... FILE...'),
5928 inferrepo=True)
5936 inferrepo=True)
5929 def remove(ui, repo, *pats, **opts):
5937 def remove(ui, repo, *pats, **opts):
5930 """remove the specified files on the next commit
5938 """remove the specified files on the next commit
5931
5939
5932 Schedule the indicated files for removal from the current branch.
5940 Schedule the indicated files for removal from the current branch.
5933
5941
5934 This command schedules the files to be removed at the next commit.
5942 This command schedules the files to be removed at the next commit.
5935 To undo a remove before that, see :hg:`revert`. To undo added
5943 To undo a remove before that, see :hg:`revert`. To undo added
5936 files, see :hg:`forget`.
5944 files, see :hg:`forget`.
5937
5945
5938 .. container:: verbose
5946 .. container:: verbose
5939
5947
5940 -A/--after can be used to remove only files that have already
5948 -A/--after can be used to remove only files that have already
5941 been deleted, -f/--force can be used to force deletion, and -Af
5949 been deleted, -f/--force can be used to force deletion, and -Af
5942 can be used to remove files from the next revision without
5950 can be used to remove files from the next revision without
5943 deleting them from the working directory.
5951 deleting them from the working directory.
5944
5952
5945 The following table details the behavior of remove for different
5953 The following table details the behavior of remove for different
5946 file states (columns) and option combinations (rows). The file
5954 file states (columns) and option combinations (rows). The file
5947 states are Added [A], Clean [C], Modified [M] and Missing [!]
5955 states are Added [A], Clean [C], Modified [M] and Missing [!]
5948 (as reported by :hg:`status`). The actions are Warn, Remove
5956 (as reported by :hg:`status`). The actions are Warn, Remove
5949 (from branch) and Delete (from disk):
5957 (from branch) and Delete (from disk):
5950
5958
5951 ========= == == == ==
5959 ========= == == == ==
5952 opt/state A C M !
5960 opt/state A C M !
5953 ========= == == == ==
5961 ========= == == == ==
5954 none W RD W R
5962 none W RD W R
5955 -f R RD RD R
5963 -f R RD RD R
5956 -A W W W R
5964 -A W W W R
5957 -Af R R R R
5965 -Af R R R R
5958 ========= == == == ==
5966 ========= == == == ==
5959
5967
5960 .. note::
5968 .. note::
5961
5969
5962 :hg:`remove` never deletes files in Added [A] state from the
5970 :hg:`remove` never deletes files in Added [A] state from the
5963 working directory, not even if ``--force`` is specified.
5971 working directory, not even if ``--force`` is specified.
5964
5972
5965 Returns 0 on success, 1 if any warnings encountered.
5973 Returns 0 on success, 1 if any warnings encountered.
5966 """
5974 """
5967
5975
5968 after, force = opts.get('after'), opts.get('force')
5976 after, force = opts.get('after'), opts.get('force')
5969 if not pats and not after:
5977 if not pats and not after:
5970 raise error.Abort(_('no files specified'))
5978 raise error.Abort(_('no files specified'))
5971
5979
5972 m = scmutil.match(repo[None], pats, opts)
5980 m = scmutil.match(repo[None], pats, opts)
5973 subrepos = opts.get('subrepos')
5981 subrepos = opts.get('subrepos')
5974 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5982 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5975
5983
5976 @command('rename|move|mv',
5984 @command('rename|move|mv',
5977 [('A', 'after', None, _('record a rename that has already occurred')),
5985 [('A', 'after', None, _('record a rename that has already occurred')),
5978 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5986 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5979 ] + walkopts + dryrunopts,
5987 ] + walkopts + dryrunopts,
5980 _('[OPTION]... SOURCE... DEST'))
5988 _('[OPTION]... SOURCE... DEST'))
5981 def rename(ui, repo, *pats, **opts):
5989 def rename(ui, repo, *pats, **opts):
5982 """rename files; equivalent of copy + remove
5990 """rename files; equivalent of copy + remove
5983
5991
5984 Mark dest as copies of sources; mark sources for deletion. If dest
5992 Mark dest as copies of sources; mark sources for deletion. If dest
5985 is a directory, copies are put in that directory. If dest is a
5993 is a directory, copies are put in that directory. If dest is a
5986 file, there can only be one source.
5994 file, there can only be one source.
5987
5995
5988 By default, this command copies the contents of files as they
5996 By default, this command copies the contents of files as they
5989 exist in the working directory. If invoked with -A/--after, the
5997 exist in the working directory. If invoked with -A/--after, the
5990 operation is recorded, but no copying is performed.
5998 operation is recorded, but no copying is performed.
5991
5999
5992 This command takes effect at the next commit. To undo a rename
6000 This command takes effect at the next commit. To undo a rename
5993 before that, see :hg:`revert`.
6001 before that, see :hg:`revert`.
5994
6002
5995 Returns 0 on success, 1 if errors are encountered.
6003 Returns 0 on success, 1 if errors are encountered.
5996 """
6004 """
5997 with repo.wlock(False):
6005 with repo.wlock(False):
5998 return cmdutil.copy(ui, repo, pats, opts, rename=True)
6006 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5999
6007
6000 @command('resolve',
6008 @command('resolve',
6001 [('a', 'all', None, _('select all unresolved files')),
6009 [('a', 'all', None, _('select all unresolved files')),
6002 ('l', 'list', None, _('list state of files needing merge')),
6010 ('l', 'list', None, _('list state of files needing merge')),
6003 ('m', 'mark', None, _('mark files as resolved')),
6011 ('m', 'mark', None, _('mark files as resolved')),
6004 ('u', 'unmark', None, _('mark files as unresolved')),
6012 ('u', 'unmark', None, _('mark files as unresolved')),
6005 ('n', 'no-status', None, _('hide status prefix'))]
6013 ('n', 'no-status', None, _('hide status prefix'))]
6006 + mergetoolopts + walkopts + formatteropts,
6014 + mergetoolopts + walkopts + formatteropts,
6007 _('[OPTION]... [FILE]...'),
6015 _('[OPTION]... [FILE]...'),
6008 inferrepo=True)
6016 inferrepo=True)
6009 def resolve(ui, repo, *pats, **opts):
6017 def resolve(ui, repo, *pats, **opts):
6010 """redo merges or set/view the merge status of files
6018 """redo merges or set/view the merge status of files
6011
6019
6012 Merges with unresolved conflicts are often the result of
6020 Merges with unresolved conflicts are often the result of
6013 non-interactive merging using the ``internal:merge`` configuration
6021 non-interactive merging using the ``internal:merge`` configuration
6014 setting, or a command-line merge tool like ``diff3``. The resolve
6022 setting, or a command-line merge tool like ``diff3``. The resolve
6015 command is used to manage the files involved in a merge, after
6023 command is used to manage the files involved in a merge, after
6016 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
6024 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
6017 working directory must have two parents). See :hg:`help
6025 working directory must have two parents). See :hg:`help
6018 merge-tools` for information on configuring merge tools.
6026 merge-tools` for information on configuring merge tools.
6019
6027
6020 The resolve command can be used in the following ways:
6028 The resolve command can be used in the following ways:
6021
6029
6022 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
6030 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
6023 files, discarding any previous merge attempts. Re-merging is not
6031 files, discarding any previous merge attempts. Re-merging is not
6024 performed for files already marked as resolved. Use ``--all/-a``
6032 performed for files already marked as resolved. Use ``--all/-a``
6025 to select all unresolved files. ``--tool`` can be used to specify
6033 to select all unresolved files. ``--tool`` can be used to specify
6026 the merge tool used for the given files. It overrides the HGMERGE
6034 the merge tool used for the given files. It overrides the HGMERGE
6027 environment variable and your configuration files. Previous file
6035 environment variable and your configuration files. Previous file
6028 contents are saved with a ``.orig`` suffix.
6036 contents are saved with a ``.orig`` suffix.
6029
6037
6030 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
6038 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
6031 (e.g. after having manually fixed-up the files). The default is
6039 (e.g. after having manually fixed-up the files). The default is
6032 to mark all unresolved files.
6040 to mark all unresolved files.
6033
6041
6034 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
6042 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
6035 default is to mark all resolved files.
6043 default is to mark all resolved files.
6036
6044
6037 - :hg:`resolve -l`: list files which had or still have conflicts.
6045 - :hg:`resolve -l`: list files which had or still have conflicts.
6038 In the printed list, ``U`` = unresolved and ``R`` = resolved.
6046 In the printed list, ``U`` = unresolved and ``R`` = resolved.
6039
6047
6040 .. note::
6048 .. note::
6041
6049
6042 Mercurial will not let you commit files with unresolved merge
6050 Mercurial will not let you commit files with unresolved merge
6043 conflicts. You must use :hg:`resolve -m ...` before you can
6051 conflicts. You must use :hg:`resolve -m ...` before you can
6044 commit after a conflicting merge.
6052 commit after a conflicting merge.
6045
6053
6046 Returns 0 on success, 1 if any files fail a resolve attempt.
6054 Returns 0 on success, 1 if any files fail a resolve attempt.
6047 """
6055 """
6048
6056
6049 flaglist = 'all mark unmark list no_status'.split()
6057 flaglist = 'all mark unmark list no_status'.split()
6050 all, mark, unmark, show, nostatus = \
6058 all, mark, unmark, show, nostatus = \
6051 [opts.get(o) for o in flaglist]
6059 [opts.get(o) for o in flaglist]
6052
6060
6053 if (show and (mark or unmark)) or (mark and unmark):
6061 if (show and (mark or unmark)) or (mark and unmark):
6054 raise error.Abort(_("too many options specified"))
6062 raise error.Abort(_("too many options specified"))
6055 if pats and all:
6063 if pats and all:
6056 raise error.Abort(_("can't specify --all and patterns"))
6064 raise error.Abort(_("can't specify --all and patterns"))
6057 if not (all or pats or show or mark or unmark):
6065 if not (all or pats or show or mark or unmark):
6058 raise error.Abort(_('no files or directories specified'),
6066 raise error.Abort(_('no files or directories specified'),
6059 hint=('use --all to re-merge all unresolved files'))
6067 hint=('use --all to re-merge all unresolved files'))
6060
6068
6061 if show:
6069 if show:
6062 fm = ui.formatter('resolve', opts)
6070 fm = ui.formatter('resolve', opts)
6063 ms = mergemod.mergestate.read(repo)
6071 ms = mergemod.mergestate.read(repo)
6064 m = scmutil.match(repo[None], pats, opts)
6072 m = scmutil.match(repo[None], pats, opts)
6065 for f in ms:
6073 for f in ms:
6066 if not m(f):
6074 if not m(f):
6067 continue
6075 continue
6068 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
6076 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
6069 'd': 'driverresolved'}[ms[f]]
6077 'd': 'driverresolved'}[ms[f]]
6070 fm.startitem()
6078 fm.startitem()
6071 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
6079 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
6072 fm.write('path', '%s\n', f, label=l)
6080 fm.write('path', '%s\n', f, label=l)
6073 fm.end()
6081 fm.end()
6074 return 0
6082 return 0
6075
6083
6076 with repo.wlock():
6084 with repo.wlock():
6077 ms = mergemod.mergestate.read(repo)
6085 ms = mergemod.mergestate.read(repo)
6078
6086
6079 if not (ms.active() or repo.dirstate.p2() != nullid):
6087 if not (ms.active() or repo.dirstate.p2() != nullid):
6080 raise error.Abort(
6088 raise error.Abort(
6081 _('resolve command not applicable when not merging'))
6089 _('resolve command not applicable when not merging'))
6082
6090
6083 wctx = repo[None]
6091 wctx = repo[None]
6084
6092
6085 if ms.mergedriver and ms.mdstate() == 'u':
6093 if ms.mergedriver and ms.mdstate() == 'u':
6086 proceed = mergemod.driverpreprocess(repo, ms, wctx)
6094 proceed = mergemod.driverpreprocess(repo, ms, wctx)
6087 ms.commit()
6095 ms.commit()
6088 # allow mark and unmark to go through
6096 # allow mark and unmark to go through
6089 if not mark and not unmark and not proceed:
6097 if not mark and not unmark and not proceed:
6090 return 1
6098 return 1
6091
6099
6092 m = scmutil.match(wctx, pats, opts)
6100 m = scmutil.match(wctx, pats, opts)
6093 ret = 0
6101 ret = 0
6094 didwork = False
6102 didwork = False
6095 runconclude = False
6103 runconclude = False
6096
6104
6097 tocomplete = []
6105 tocomplete = []
6098 for f in ms:
6106 for f in ms:
6099 if not m(f):
6107 if not m(f):
6100 continue
6108 continue
6101
6109
6102 didwork = True
6110 didwork = True
6103
6111
6104 # don't let driver-resolved files be marked, and run the conclude
6112 # don't let driver-resolved files be marked, and run the conclude
6105 # step if asked to resolve
6113 # step if asked to resolve
6106 if ms[f] == "d":
6114 if ms[f] == "d":
6107 exact = m.exact(f)
6115 exact = m.exact(f)
6108 if mark:
6116 if mark:
6109 if exact:
6117 if exact:
6110 ui.warn(_('not marking %s as it is driver-resolved\n')
6118 ui.warn(_('not marking %s as it is driver-resolved\n')
6111 % f)
6119 % f)
6112 elif unmark:
6120 elif unmark:
6113 if exact:
6121 if exact:
6114 ui.warn(_('not unmarking %s as it is driver-resolved\n')
6122 ui.warn(_('not unmarking %s as it is driver-resolved\n')
6115 % f)
6123 % f)
6116 else:
6124 else:
6117 runconclude = True
6125 runconclude = True
6118 continue
6126 continue
6119
6127
6120 if mark:
6128 if mark:
6121 ms.mark(f, "r")
6129 ms.mark(f, "r")
6122 elif unmark:
6130 elif unmark:
6123 ms.mark(f, "u")
6131 ms.mark(f, "u")
6124 else:
6132 else:
6125 # backup pre-resolve (merge uses .orig for its own purposes)
6133 # backup pre-resolve (merge uses .orig for its own purposes)
6126 a = repo.wjoin(f)
6134 a = repo.wjoin(f)
6127 try:
6135 try:
6128 util.copyfile(a, a + ".resolve")
6136 util.copyfile(a, a + ".resolve")
6129 except (IOError, OSError) as inst:
6137 except (IOError, OSError) as inst:
6130 if inst.errno != errno.ENOENT:
6138 if inst.errno != errno.ENOENT:
6131 raise
6139 raise
6132
6140
6133 try:
6141 try:
6134 # preresolve file
6142 # preresolve file
6135 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6143 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6136 'resolve')
6144 'resolve')
6137 complete, r = ms.preresolve(f, wctx)
6145 complete, r = ms.preresolve(f, wctx)
6138 if not complete:
6146 if not complete:
6139 tocomplete.append(f)
6147 tocomplete.append(f)
6140 elif r:
6148 elif r:
6141 ret = 1
6149 ret = 1
6142 finally:
6150 finally:
6143 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6151 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6144 ms.commit()
6152 ms.commit()
6145
6153
6146 # replace filemerge's .orig file with our resolve file, but only
6154 # replace filemerge's .orig file with our resolve file, but only
6147 # for merges that are complete
6155 # for merges that are complete
6148 if complete:
6156 if complete:
6149 try:
6157 try:
6150 util.rename(a + ".resolve",
6158 util.rename(a + ".resolve",
6151 scmutil.origpath(ui, repo, a))
6159 scmutil.origpath(ui, repo, a))
6152 except OSError as inst:
6160 except OSError as inst:
6153 if inst.errno != errno.ENOENT:
6161 if inst.errno != errno.ENOENT:
6154 raise
6162 raise
6155
6163
6156 for f in tocomplete:
6164 for f in tocomplete:
6157 try:
6165 try:
6158 # resolve file
6166 # resolve file
6159 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6167 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6160 'resolve')
6168 'resolve')
6161 r = ms.resolve(f, wctx)
6169 r = ms.resolve(f, wctx)
6162 if r:
6170 if r:
6163 ret = 1
6171 ret = 1
6164 finally:
6172 finally:
6165 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6173 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6166 ms.commit()
6174 ms.commit()
6167
6175
6168 # replace filemerge's .orig file with our resolve file
6176 # replace filemerge's .orig file with our resolve file
6169 a = repo.wjoin(f)
6177 a = repo.wjoin(f)
6170 try:
6178 try:
6171 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
6179 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
6172 except OSError as inst:
6180 except OSError as inst:
6173 if inst.errno != errno.ENOENT:
6181 if inst.errno != errno.ENOENT:
6174 raise
6182 raise
6175
6183
6176 ms.commit()
6184 ms.commit()
6177 ms.recordactions()
6185 ms.recordactions()
6178
6186
6179 if not didwork and pats:
6187 if not didwork and pats:
6180 hint = None
6188 hint = None
6181 if not any([p for p in pats if p.find(':') >= 0]):
6189 if not any([p for p in pats if p.find(':') >= 0]):
6182 pats = ['path:%s' % p for p in pats]
6190 pats = ['path:%s' % p for p in pats]
6183 m = scmutil.match(wctx, pats, opts)
6191 m = scmutil.match(wctx, pats, opts)
6184 for f in ms:
6192 for f in ms:
6185 if not m(f):
6193 if not m(f):
6186 continue
6194 continue
6187 flags = ''.join(['-%s ' % o[0] for o in flaglist
6195 flags = ''.join(['-%s ' % o[0] for o in flaglist
6188 if opts.get(o)])
6196 if opts.get(o)])
6189 hint = _("(try: hg resolve %s%s)\n") % (
6197 hint = _("(try: hg resolve %s%s)\n") % (
6190 flags,
6198 flags,
6191 ' '.join(pats))
6199 ' '.join(pats))
6192 break
6200 break
6193 ui.warn(_("arguments do not match paths that need resolving\n"))
6201 ui.warn(_("arguments do not match paths that need resolving\n"))
6194 if hint:
6202 if hint:
6195 ui.warn(hint)
6203 ui.warn(hint)
6196 elif ms.mergedriver and ms.mdstate() != 's':
6204 elif ms.mergedriver and ms.mdstate() != 's':
6197 # run conclude step when either a driver-resolved file is requested
6205 # run conclude step when either a driver-resolved file is requested
6198 # or there are no driver-resolved files
6206 # or there are no driver-resolved files
6199 # we can't use 'ret' to determine whether any files are unresolved
6207 # we can't use 'ret' to determine whether any files are unresolved
6200 # because we might not have tried to resolve some
6208 # because we might not have tried to resolve some
6201 if ((runconclude or not list(ms.driverresolved()))
6209 if ((runconclude or not list(ms.driverresolved()))
6202 and not list(ms.unresolved())):
6210 and not list(ms.unresolved())):
6203 proceed = mergemod.driverconclude(repo, ms, wctx)
6211 proceed = mergemod.driverconclude(repo, ms, wctx)
6204 ms.commit()
6212 ms.commit()
6205 if not proceed:
6213 if not proceed:
6206 return 1
6214 return 1
6207
6215
6208 # Nudge users into finishing an unfinished operation
6216 # Nudge users into finishing an unfinished operation
6209 unresolvedf = list(ms.unresolved())
6217 unresolvedf = list(ms.unresolved())
6210 driverresolvedf = list(ms.driverresolved())
6218 driverresolvedf = list(ms.driverresolved())
6211 if not unresolvedf and not driverresolvedf:
6219 if not unresolvedf and not driverresolvedf:
6212 ui.status(_('(no more unresolved files)\n'))
6220 ui.status(_('(no more unresolved files)\n'))
6213 cmdutil.checkafterresolved(repo)
6221 cmdutil.checkafterresolved(repo)
6214 elif not unresolvedf:
6222 elif not unresolvedf:
6215 ui.status(_('(no more unresolved files -- '
6223 ui.status(_('(no more unresolved files -- '
6216 'run "hg resolve --all" to conclude)\n'))
6224 'run "hg resolve --all" to conclude)\n'))
6217
6225
6218 return ret
6226 return ret
6219
6227
6220 @command('revert',
6228 @command('revert',
6221 [('a', 'all', None, _('revert all changes when no arguments given')),
6229 [('a', 'all', None, _('revert all changes when no arguments given')),
6222 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6230 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6223 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
6231 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
6224 ('C', 'no-backup', None, _('do not save backup copies of files')),
6232 ('C', 'no-backup', None, _('do not save backup copies of files')),
6225 ('i', 'interactive', None,
6233 ('i', 'interactive', None,
6226 _('interactively select the changes (EXPERIMENTAL)')),
6234 _('interactively select the changes (EXPERIMENTAL)')),
6227 ] + walkopts + dryrunopts,
6235 ] + walkopts + dryrunopts,
6228 _('[OPTION]... [-r REV] [NAME]...'))
6236 _('[OPTION]... [-r REV] [NAME]...'))
6229 def revert(ui, repo, *pats, **opts):
6237 def revert(ui, repo, *pats, **opts):
6230 """restore files to their checkout state
6238 """restore files to their checkout state
6231
6239
6232 .. note::
6240 .. note::
6233
6241
6234 To check out earlier revisions, you should use :hg:`update REV`.
6242 To check out earlier revisions, you should use :hg:`update REV`.
6235 To cancel an uncommitted merge (and lose your changes),
6243 To cancel an uncommitted merge (and lose your changes),
6236 use :hg:`update --clean .`.
6244 use :hg:`update --clean .`.
6237
6245
6238 With no revision specified, revert the specified files or directories
6246 With no revision specified, revert the specified files or directories
6239 to the contents they had in the parent of the working directory.
6247 to the contents they had in the parent of the working directory.
6240 This restores the contents of files to an unmodified
6248 This restores the contents of files to an unmodified
6241 state and unschedules adds, removes, copies, and renames. If the
6249 state and unschedules adds, removes, copies, and renames. If the
6242 working directory has two parents, you must explicitly specify a
6250 working directory has two parents, you must explicitly specify a
6243 revision.
6251 revision.
6244
6252
6245 Using the -r/--rev or -d/--date options, revert the given files or
6253 Using the -r/--rev or -d/--date options, revert the given files or
6246 directories to their states as of a specific revision. Because
6254 directories to their states as of a specific revision. Because
6247 revert does not change the working directory parents, this will
6255 revert does not change the working directory parents, this will
6248 cause these files to appear modified. This can be helpful to "back
6256 cause these files to appear modified. This can be helpful to "back
6249 out" some or all of an earlier change. See :hg:`backout` for a
6257 out" some or all of an earlier change. See :hg:`backout` for a
6250 related method.
6258 related method.
6251
6259
6252 Modified files are saved with a .orig suffix before reverting.
6260 Modified files are saved with a .orig suffix before reverting.
6253 To disable these backups, use --no-backup.
6261 To disable these backups, use --no-backup.
6254
6262
6255 See :hg:`help dates` for a list of formats valid for -d/--date.
6263 See :hg:`help dates` for a list of formats valid for -d/--date.
6256
6264
6257 See :hg:`help backout` for a way to reverse the effect of an
6265 See :hg:`help backout` for a way to reverse the effect of an
6258 earlier changeset.
6266 earlier changeset.
6259
6267
6260 Returns 0 on success.
6268 Returns 0 on success.
6261 """
6269 """
6262
6270
6263 if opts.get("date"):
6271 if opts.get("date"):
6264 if opts.get("rev"):
6272 if opts.get("rev"):
6265 raise error.Abort(_("you can't specify a revision and a date"))
6273 raise error.Abort(_("you can't specify a revision and a date"))
6266 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6274 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6267
6275
6268 parent, p2 = repo.dirstate.parents()
6276 parent, p2 = repo.dirstate.parents()
6269 if not opts.get('rev') and p2 != nullid:
6277 if not opts.get('rev') and p2 != nullid:
6270 # revert after merge is a trap for new users (issue2915)
6278 # revert after merge is a trap for new users (issue2915)
6271 raise error.Abort(_('uncommitted merge with no revision specified'),
6279 raise error.Abort(_('uncommitted merge with no revision specified'),
6272 hint=_('use "hg update" or see "hg help revert"'))
6280 hint=_('use "hg update" or see "hg help revert"'))
6273
6281
6274 ctx = scmutil.revsingle(repo, opts.get('rev'))
6282 ctx = scmutil.revsingle(repo, opts.get('rev'))
6275
6283
6276 if (not (pats or opts.get('include') or opts.get('exclude') or
6284 if (not (pats or opts.get('include') or opts.get('exclude') or
6277 opts.get('all') or opts.get('interactive'))):
6285 opts.get('all') or opts.get('interactive'))):
6278 msg = _("no files or directories specified")
6286 msg = _("no files or directories specified")
6279 if p2 != nullid:
6287 if p2 != nullid:
6280 hint = _("uncommitted merge, use --all to discard all changes,"
6288 hint = _("uncommitted merge, use --all to discard all changes,"
6281 " or 'hg update -C .' to abort the merge")
6289 " or 'hg update -C .' to abort the merge")
6282 raise error.Abort(msg, hint=hint)
6290 raise error.Abort(msg, hint=hint)
6283 dirty = any(repo.status())
6291 dirty = any(repo.status())
6284 node = ctx.node()
6292 node = ctx.node()
6285 if node != parent:
6293 if node != parent:
6286 if dirty:
6294 if dirty:
6287 hint = _("uncommitted changes, use --all to discard all"
6295 hint = _("uncommitted changes, use --all to discard all"
6288 " changes, or 'hg update %s' to update") % ctx.rev()
6296 " changes, or 'hg update %s' to update") % ctx.rev()
6289 else:
6297 else:
6290 hint = _("use --all to revert all files,"
6298 hint = _("use --all to revert all files,"
6291 " or 'hg update %s' to update") % ctx.rev()
6299 " or 'hg update %s' to update") % ctx.rev()
6292 elif dirty:
6300 elif dirty:
6293 hint = _("uncommitted changes, use --all to discard all changes")
6301 hint = _("uncommitted changes, use --all to discard all changes")
6294 else:
6302 else:
6295 hint = _("use --all to revert all files")
6303 hint = _("use --all to revert all files")
6296 raise error.Abort(msg, hint=hint)
6304 raise error.Abort(msg, hint=hint)
6297
6305
6298 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
6306 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
6299
6307
6300 @command('rollback', dryrunopts +
6308 @command('rollback', dryrunopts +
6301 [('f', 'force', False, _('ignore safety measures'))])
6309 [('f', 'force', False, _('ignore safety measures'))])
6302 def rollback(ui, repo, **opts):
6310 def rollback(ui, repo, **opts):
6303 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6311 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6304
6312
6305 Please use :hg:`commit --amend` instead of rollback to correct
6313 Please use :hg:`commit --amend` instead of rollback to correct
6306 mistakes in the last commit.
6314 mistakes in the last commit.
6307
6315
6308 This command should be used with care. There is only one level of
6316 This command should be used with care. There is only one level of
6309 rollback, and there is no way to undo a rollback. It will also
6317 rollback, and there is no way to undo a rollback. It will also
6310 restore the dirstate at the time of the last transaction, losing
6318 restore the dirstate at the time of the last transaction, losing
6311 any dirstate changes since that time. This command does not alter
6319 any dirstate changes since that time. This command does not alter
6312 the working directory.
6320 the working directory.
6313
6321
6314 Transactions are used to encapsulate the effects of all commands
6322 Transactions are used to encapsulate the effects of all commands
6315 that create new changesets or propagate existing changesets into a
6323 that create new changesets or propagate existing changesets into a
6316 repository.
6324 repository.
6317
6325
6318 .. container:: verbose
6326 .. container:: verbose
6319
6327
6320 For example, the following commands are transactional, and their
6328 For example, the following commands are transactional, and their
6321 effects can be rolled back:
6329 effects can be rolled back:
6322
6330
6323 - commit
6331 - commit
6324 - import
6332 - import
6325 - pull
6333 - pull
6326 - push (with this repository as the destination)
6334 - push (with this repository as the destination)
6327 - unbundle
6335 - unbundle
6328
6336
6329 To avoid permanent data loss, rollback will refuse to rollback a
6337 To avoid permanent data loss, rollback will refuse to rollback a
6330 commit transaction if it isn't checked out. Use --force to
6338 commit transaction if it isn't checked out. Use --force to
6331 override this protection.
6339 override this protection.
6332
6340
6333 This command is not intended for use on public repositories. Once
6341 This command is not intended for use on public repositories. Once
6334 changes are visible for pull by other users, rolling a transaction
6342 changes are visible for pull by other users, rolling a transaction
6335 back locally is ineffective (someone else may already have pulled
6343 back locally is ineffective (someone else may already have pulled
6336 the changes). Furthermore, a race is possible with readers of the
6344 the changes). Furthermore, a race is possible with readers of the
6337 repository; for example an in-progress pull from the repository
6345 repository; for example an in-progress pull from the repository
6338 may fail if a rollback is performed.
6346 may fail if a rollback is performed.
6339
6347
6340 Returns 0 on success, 1 if no rollback data is available.
6348 Returns 0 on success, 1 if no rollback data is available.
6341 """
6349 """
6342 return repo.rollback(dryrun=opts.get('dry_run'),
6350 return repo.rollback(dryrun=opts.get('dry_run'),
6343 force=opts.get('force'))
6351 force=opts.get('force'))
6344
6352
6345 @command('root', [])
6353 @command('root', [])
6346 def root(ui, repo):
6354 def root(ui, repo):
6347 """print the root (top) of the current working directory
6355 """print the root (top) of the current working directory
6348
6356
6349 Print the root directory of the current repository.
6357 Print the root directory of the current repository.
6350
6358
6351 Returns 0 on success.
6359 Returns 0 on success.
6352 """
6360 """
6353 ui.write(repo.root + "\n")
6361 ui.write(repo.root + "\n")
6354
6362
6355 @command('^serve',
6363 @command('^serve',
6356 [('A', 'accesslog', '', _('name of access log file to write to'),
6364 [('A', 'accesslog', '', _('name of access log file to write to'),
6357 _('FILE')),
6365 _('FILE')),
6358 ('d', 'daemon', None, _('run server in background')),
6366 ('d', 'daemon', None, _('run server in background')),
6359 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
6367 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
6360 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
6368 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
6361 # use string type, then we can check if something was passed
6369 # use string type, then we can check if something was passed
6362 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
6370 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
6363 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
6371 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
6364 _('ADDR')),
6372 _('ADDR')),
6365 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
6373 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
6366 _('PREFIX')),
6374 _('PREFIX')),
6367 ('n', 'name', '',
6375 ('n', 'name', '',
6368 _('name to show in web pages (default: working directory)'), _('NAME')),
6376 _('name to show in web pages (default: working directory)'), _('NAME')),
6369 ('', 'web-conf', '',
6377 ('', 'web-conf', '',
6370 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
6378 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
6371 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
6379 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
6372 _('FILE')),
6380 _('FILE')),
6373 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
6381 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
6374 ('', 'stdio', None, _('for remote clients')),
6382 ('', 'stdio', None, _('for remote clients')),
6375 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
6383 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
6376 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
6384 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
6377 ('', 'style', '', _('template style to use'), _('STYLE')),
6385 ('', 'style', '', _('template style to use'), _('STYLE')),
6378 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
6386 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
6379 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
6387 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
6380 _('[OPTION]...'),
6388 _('[OPTION]...'),
6381 optionalrepo=True)
6389 optionalrepo=True)
6382 def serve(ui, repo, **opts):
6390 def serve(ui, repo, **opts):
6383 """start stand-alone webserver
6391 """start stand-alone webserver
6384
6392
6385 Start a local HTTP repository browser and pull server. You can use
6393 Start a local HTTP repository browser and pull server. You can use
6386 this for ad-hoc sharing and browsing of repositories. It is
6394 this for ad-hoc sharing and browsing of repositories. It is
6387 recommended to use a real web server to serve a repository for
6395 recommended to use a real web server to serve a repository for
6388 longer periods of time.
6396 longer periods of time.
6389
6397
6390 Please note that the server does not implement access control.
6398 Please note that the server does not implement access control.
6391 This means that, by default, anybody can read from the server and
6399 This means that, by default, anybody can read from the server and
6392 nobody can write to it by default. Set the ``web.allow_push``
6400 nobody can write to it by default. Set the ``web.allow_push``
6393 option to ``*`` to allow everybody to push to the server. You
6401 option to ``*`` to allow everybody to push to the server. You
6394 should use a real web server if you need to authenticate users.
6402 should use a real web server if you need to authenticate users.
6395
6403
6396 By default, the server logs accesses to stdout and errors to
6404 By default, the server logs accesses to stdout and errors to
6397 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6405 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6398 files.
6406 files.
6399
6407
6400 To have the server choose a free port number to listen on, specify
6408 To have the server choose a free port number to listen on, specify
6401 a port number of 0; in this case, the server will print the port
6409 a port number of 0; in this case, the server will print the port
6402 number it uses.
6410 number it uses.
6403
6411
6404 Returns 0 on success.
6412 Returns 0 on success.
6405 """
6413 """
6406
6414
6407 if opts["stdio"] and opts["cmdserver"]:
6415 if opts["stdio"] and opts["cmdserver"]:
6408 raise error.Abort(_("cannot use --stdio with --cmdserver"))
6416 raise error.Abort(_("cannot use --stdio with --cmdserver"))
6409
6417
6410 if opts["stdio"]:
6418 if opts["stdio"]:
6411 if repo is None:
6419 if repo is None:
6412 raise error.RepoError(_("there is no Mercurial repository here"
6420 raise error.RepoError(_("there is no Mercurial repository here"
6413 " (.hg not found)"))
6421 " (.hg not found)"))
6414 s = sshserver.sshserver(ui, repo)
6422 s = sshserver.sshserver(ui, repo)
6415 s.serve_forever()
6423 s.serve_forever()
6416
6424
6417 if opts["cmdserver"]:
6425 if opts["cmdserver"]:
6418 service = commandserver.createservice(ui, repo, opts)
6426 service = commandserver.createservice(ui, repo, opts)
6419 else:
6427 else:
6420 service = hgweb.createservice(ui, repo, opts)
6428 service = hgweb.createservice(ui, repo, opts)
6421 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
6429 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
6422
6430
6423 @command('^status|st',
6431 @command('^status|st',
6424 [('A', 'all', None, _('show status of all files')),
6432 [('A', 'all', None, _('show status of all files')),
6425 ('m', 'modified', None, _('show only modified files')),
6433 ('m', 'modified', None, _('show only modified files')),
6426 ('a', 'added', None, _('show only added files')),
6434 ('a', 'added', None, _('show only added files')),
6427 ('r', 'removed', None, _('show only removed files')),
6435 ('r', 'removed', None, _('show only removed files')),
6428 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
6436 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
6429 ('c', 'clean', None, _('show only files without changes')),
6437 ('c', 'clean', None, _('show only files without changes')),
6430 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
6438 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
6431 ('i', 'ignored', None, _('show only ignored files')),
6439 ('i', 'ignored', None, _('show only ignored files')),
6432 ('n', 'no-status', None, _('hide status prefix')),
6440 ('n', 'no-status', None, _('hide status prefix')),
6433 ('C', 'copies', None, _('show source of copied files')),
6441 ('C', 'copies', None, _('show source of copied files')),
6434 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
6442 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
6435 ('', 'rev', [], _('show difference from revision'), _('REV')),
6443 ('', 'rev', [], _('show difference from revision'), _('REV')),
6436 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
6444 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
6437 ] + walkopts + subrepoopts + formatteropts,
6445 ] + walkopts + subrepoopts + formatteropts,
6438 _('[OPTION]... [FILE]...'),
6446 _('[OPTION]... [FILE]...'),
6439 inferrepo=True)
6447 inferrepo=True)
6440 def status(ui, repo, *pats, **opts):
6448 def status(ui, repo, *pats, **opts):
6441 """show changed files in the working directory
6449 """show changed files in the working directory
6442
6450
6443 Show status of files in the repository. If names are given, only
6451 Show status of files in the repository. If names are given, only
6444 files that match are shown. Files that are clean or ignored or
6452 files that match are shown. Files that are clean or ignored or
6445 the source of a copy/move operation, are not listed unless
6453 the source of a copy/move operation, are not listed unless
6446 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6454 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6447 Unless options described with "show only ..." are given, the
6455 Unless options described with "show only ..." are given, the
6448 options -mardu are used.
6456 options -mardu are used.
6449
6457
6450 Option -q/--quiet hides untracked (unknown and ignored) files
6458 Option -q/--quiet hides untracked (unknown and ignored) files
6451 unless explicitly requested with -u/--unknown or -i/--ignored.
6459 unless explicitly requested with -u/--unknown or -i/--ignored.
6452
6460
6453 .. note::
6461 .. note::
6454
6462
6455 :hg:`status` may appear to disagree with diff if permissions have
6463 :hg:`status` may appear to disagree with diff if permissions have
6456 changed or a merge has occurred. The standard diff format does
6464 changed or a merge has occurred. The standard diff format does
6457 not report permission changes and diff only reports changes
6465 not report permission changes and diff only reports changes
6458 relative to one merge parent.
6466 relative to one merge parent.
6459
6467
6460 If one revision is given, it is used as the base revision.
6468 If one revision is given, it is used as the base revision.
6461 If two revisions are given, the differences between them are
6469 If two revisions are given, the differences between them are
6462 shown. The --change option can also be used as a shortcut to list
6470 shown. The --change option can also be used as a shortcut to list
6463 the changed files of a revision from its first parent.
6471 the changed files of a revision from its first parent.
6464
6472
6465 The codes used to show the status of files are::
6473 The codes used to show the status of files are::
6466
6474
6467 M = modified
6475 M = modified
6468 A = added
6476 A = added
6469 R = removed
6477 R = removed
6470 C = clean
6478 C = clean
6471 ! = missing (deleted by non-hg command, but still tracked)
6479 ! = missing (deleted by non-hg command, but still tracked)
6472 ? = not tracked
6480 ? = not tracked
6473 I = ignored
6481 I = ignored
6474 = origin of the previous file (with --copies)
6482 = origin of the previous file (with --copies)
6475
6483
6476 .. container:: verbose
6484 .. container:: verbose
6477
6485
6478 Examples:
6486 Examples:
6479
6487
6480 - show changes in the working directory relative to a
6488 - show changes in the working directory relative to a
6481 changeset::
6489 changeset::
6482
6490
6483 hg status --rev 9353
6491 hg status --rev 9353
6484
6492
6485 - show changes in the working directory relative to the
6493 - show changes in the working directory relative to the
6486 current directory (see :hg:`help patterns` for more information)::
6494 current directory (see :hg:`help patterns` for more information)::
6487
6495
6488 hg status re:
6496 hg status re:
6489
6497
6490 - show all changes including copies in an existing changeset::
6498 - show all changes including copies in an existing changeset::
6491
6499
6492 hg status --copies --change 9353
6500 hg status --copies --change 9353
6493
6501
6494 - get a NUL separated list of added files, suitable for xargs::
6502 - get a NUL separated list of added files, suitable for xargs::
6495
6503
6496 hg status -an0
6504 hg status -an0
6497
6505
6498 Returns 0 on success.
6506 Returns 0 on success.
6499 """
6507 """
6500
6508
6501 revs = opts.get('rev')
6509 revs = opts.get('rev')
6502 change = opts.get('change')
6510 change = opts.get('change')
6503
6511
6504 if revs and change:
6512 if revs and change:
6505 msg = _('cannot specify --rev and --change at the same time')
6513 msg = _('cannot specify --rev and --change at the same time')
6506 raise error.Abort(msg)
6514 raise error.Abort(msg)
6507 elif change:
6515 elif change:
6508 node2 = scmutil.revsingle(repo, change, None).node()
6516 node2 = scmutil.revsingle(repo, change, None).node()
6509 node1 = repo[node2].p1().node()
6517 node1 = repo[node2].p1().node()
6510 else:
6518 else:
6511 node1, node2 = scmutil.revpair(repo, revs)
6519 node1, node2 = scmutil.revpair(repo, revs)
6512
6520
6513 if pats:
6521 if pats:
6514 cwd = repo.getcwd()
6522 cwd = repo.getcwd()
6515 else:
6523 else:
6516 cwd = ''
6524 cwd = ''
6517
6525
6518 if opts.get('print0'):
6526 if opts.get('print0'):
6519 end = '\0'
6527 end = '\0'
6520 else:
6528 else:
6521 end = '\n'
6529 end = '\n'
6522 copy = {}
6530 copy = {}
6523 states = 'modified added removed deleted unknown ignored clean'.split()
6531 states = 'modified added removed deleted unknown ignored clean'.split()
6524 show = [k for k in states if opts.get(k)]
6532 show = [k for k in states if opts.get(k)]
6525 if opts.get('all'):
6533 if opts.get('all'):
6526 show += ui.quiet and (states[:4] + ['clean']) or states
6534 show += ui.quiet and (states[:4] + ['clean']) or states
6527 if not show:
6535 if not show:
6528 if ui.quiet:
6536 if ui.quiet:
6529 show = states[:4]
6537 show = states[:4]
6530 else:
6538 else:
6531 show = states[:5]
6539 show = states[:5]
6532
6540
6533 m = scmutil.match(repo[node2], pats, opts)
6541 m = scmutil.match(repo[node2], pats, opts)
6534 stat = repo.status(node1, node2, m,
6542 stat = repo.status(node1, node2, m,
6535 'ignored' in show, 'clean' in show, 'unknown' in show,
6543 'ignored' in show, 'clean' in show, 'unknown' in show,
6536 opts.get('subrepos'))
6544 opts.get('subrepos'))
6537 changestates = zip(states, 'MAR!?IC', stat)
6545 changestates = zip(states, 'MAR!?IC', stat)
6538
6546
6539 if (opts.get('all') or opts.get('copies')
6547 if (opts.get('all') or opts.get('copies')
6540 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6548 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6541 copy = copies.pathcopies(repo[node1], repo[node2], m)
6549 copy = copies.pathcopies(repo[node1], repo[node2], m)
6542
6550
6543 fm = ui.formatter('status', opts)
6551 fm = ui.formatter('status', opts)
6544 fmt = '%s' + end
6552 fmt = '%s' + end
6545 showchar = not opts.get('no_status')
6553 showchar = not opts.get('no_status')
6546
6554
6547 for state, char, files in changestates:
6555 for state, char, files in changestates:
6548 if state in show:
6556 if state in show:
6549 label = 'status.' + state
6557 label = 'status.' + state
6550 for f in files:
6558 for f in files:
6551 fm.startitem()
6559 fm.startitem()
6552 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6560 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6553 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6561 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6554 if f in copy:
6562 if f in copy:
6555 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6563 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6556 label='status.copied')
6564 label='status.copied')
6557 fm.end()
6565 fm.end()
6558
6566
6559 @command('^summary|sum',
6567 @command('^summary|sum',
6560 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6568 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6561 def summary(ui, repo, **opts):
6569 def summary(ui, repo, **opts):
6562 """summarize working directory state
6570 """summarize working directory state
6563
6571
6564 This generates a brief summary of the working directory state,
6572 This generates a brief summary of the working directory state,
6565 including parents, branch, commit status, phase and available updates.
6573 including parents, branch, commit status, phase and available updates.
6566
6574
6567 With the --remote option, this will check the default paths for
6575 With the --remote option, this will check the default paths for
6568 incoming and outgoing changes. This can be time-consuming.
6576 incoming and outgoing changes. This can be time-consuming.
6569
6577
6570 Returns 0 on success.
6578 Returns 0 on success.
6571 """
6579 """
6572
6580
6573 ctx = repo[None]
6581 ctx = repo[None]
6574 parents = ctx.parents()
6582 parents = ctx.parents()
6575 pnode = parents[0].node()
6583 pnode = parents[0].node()
6576 marks = []
6584 marks = []
6577
6585
6578 for p in parents:
6586 for p in parents:
6579 # label with log.changeset (instead of log.parent) since this
6587 # label with log.changeset (instead of log.parent) since this
6580 # shows a working directory parent *changeset*:
6588 # shows a working directory parent *changeset*:
6581 # i18n: column positioning for "hg summary"
6589 # i18n: column positioning for "hg summary"
6582 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6590 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6583 label='log.changeset changeset.%s' % p.phasestr())
6591 label='log.changeset changeset.%s' % p.phasestr())
6584 ui.write(' '.join(p.tags()), label='log.tag')
6592 ui.write(' '.join(p.tags()), label='log.tag')
6585 if p.bookmarks():
6593 if p.bookmarks():
6586 marks.extend(p.bookmarks())
6594 marks.extend(p.bookmarks())
6587 if p.rev() == -1:
6595 if p.rev() == -1:
6588 if not len(repo):
6596 if not len(repo):
6589 ui.write(_(' (empty repository)'))
6597 ui.write(_(' (empty repository)'))
6590 else:
6598 else:
6591 ui.write(_(' (no revision checked out)'))
6599 ui.write(_(' (no revision checked out)'))
6592 ui.write('\n')
6600 ui.write('\n')
6593 if p.description():
6601 if p.description():
6594 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6602 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6595 label='log.summary')
6603 label='log.summary')
6596
6604
6597 branch = ctx.branch()
6605 branch = ctx.branch()
6598 bheads = repo.branchheads(branch)
6606 bheads = repo.branchheads(branch)
6599 # i18n: column positioning for "hg summary"
6607 # i18n: column positioning for "hg summary"
6600 m = _('branch: %s\n') % branch
6608 m = _('branch: %s\n') % branch
6601 if branch != 'default':
6609 if branch != 'default':
6602 ui.write(m, label='log.branch')
6610 ui.write(m, label='log.branch')
6603 else:
6611 else:
6604 ui.status(m, label='log.branch')
6612 ui.status(m, label='log.branch')
6605
6613
6606 if marks:
6614 if marks:
6607 active = repo._activebookmark
6615 active = repo._activebookmark
6608 # i18n: column positioning for "hg summary"
6616 # i18n: column positioning for "hg summary"
6609 ui.write(_('bookmarks:'), label='log.bookmark')
6617 ui.write(_('bookmarks:'), label='log.bookmark')
6610 if active is not None:
6618 if active is not None:
6611 if active in marks:
6619 if active in marks:
6612 ui.write(' *' + active, label=activebookmarklabel)
6620 ui.write(' *' + active, label=activebookmarklabel)
6613 marks.remove(active)
6621 marks.remove(active)
6614 else:
6622 else:
6615 ui.write(' [%s]' % active, label=activebookmarklabel)
6623 ui.write(' [%s]' % active, label=activebookmarklabel)
6616 for m in marks:
6624 for m in marks:
6617 ui.write(' ' + m, label='log.bookmark')
6625 ui.write(' ' + m, label='log.bookmark')
6618 ui.write('\n', label='log.bookmark')
6626 ui.write('\n', label='log.bookmark')
6619
6627
6620 status = repo.status(unknown=True)
6628 status = repo.status(unknown=True)
6621
6629
6622 c = repo.dirstate.copies()
6630 c = repo.dirstate.copies()
6623 copied, renamed = [], []
6631 copied, renamed = [], []
6624 for d, s in c.iteritems():
6632 for d, s in c.iteritems():
6625 if s in status.removed:
6633 if s in status.removed:
6626 status.removed.remove(s)
6634 status.removed.remove(s)
6627 renamed.append(d)
6635 renamed.append(d)
6628 else:
6636 else:
6629 copied.append(d)
6637 copied.append(d)
6630 if d in status.added:
6638 if d in status.added:
6631 status.added.remove(d)
6639 status.added.remove(d)
6632
6640
6633 try:
6641 try:
6634 ms = mergemod.mergestate.read(repo)
6642 ms = mergemod.mergestate.read(repo)
6635 except error.UnsupportedMergeRecords as e:
6643 except error.UnsupportedMergeRecords as e:
6636 s = ' '.join(e.recordtypes)
6644 s = ' '.join(e.recordtypes)
6637 ui.warn(
6645 ui.warn(
6638 _('warning: merge state has unsupported record types: %s\n') % s)
6646 _('warning: merge state has unsupported record types: %s\n') % s)
6639 unresolved = 0
6647 unresolved = 0
6640 else:
6648 else:
6641 unresolved = [f for f in ms if ms[f] == 'u']
6649 unresolved = [f for f in ms if ms[f] == 'u']
6642
6650
6643 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6651 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6644
6652
6645 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6653 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6646 (ui.label(_('%d added'), 'status.added'), status.added),
6654 (ui.label(_('%d added'), 'status.added'), status.added),
6647 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6655 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6648 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6656 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6649 (ui.label(_('%d copied'), 'status.copied'), copied),
6657 (ui.label(_('%d copied'), 'status.copied'), copied),
6650 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6658 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6651 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6659 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6652 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6660 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6653 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6661 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6654 t = []
6662 t = []
6655 for l, s in labels:
6663 for l, s in labels:
6656 if s:
6664 if s:
6657 t.append(l % len(s))
6665 t.append(l % len(s))
6658
6666
6659 t = ', '.join(t)
6667 t = ', '.join(t)
6660 cleanworkdir = False
6668 cleanworkdir = False
6661
6669
6662 if repo.vfs.exists('graftstate'):
6670 if repo.vfs.exists('graftstate'):
6663 t += _(' (graft in progress)')
6671 t += _(' (graft in progress)')
6664 if repo.vfs.exists('updatestate'):
6672 if repo.vfs.exists('updatestate'):
6665 t += _(' (interrupted update)')
6673 t += _(' (interrupted update)')
6666 elif len(parents) > 1:
6674 elif len(parents) > 1:
6667 t += _(' (merge)')
6675 t += _(' (merge)')
6668 elif branch != parents[0].branch():
6676 elif branch != parents[0].branch():
6669 t += _(' (new branch)')
6677 t += _(' (new branch)')
6670 elif (parents[0].closesbranch() and
6678 elif (parents[0].closesbranch() and
6671 pnode in repo.branchheads(branch, closed=True)):
6679 pnode in repo.branchheads(branch, closed=True)):
6672 t += _(' (head closed)')
6680 t += _(' (head closed)')
6673 elif not (status.modified or status.added or status.removed or renamed or
6681 elif not (status.modified or status.added or status.removed or renamed or
6674 copied or subs):
6682 copied or subs):
6675 t += _(' (clean)')
6683 t += _(' (clean)')
6676 cleanworkdir = True
6684 cleanworkdir = True
6677 elif pnode not in bheads:
6685 elif pnode not in bheads:
6678 t += _(' (new branch head)')
6686 t += _(' (new branch head)')
6679
6687
6680 if parents:
6688 if parents:
6681 pendingphase = max(p.phase() for p in parents)
6689 pendingphase = max(p.phase() for p in parents)
6682 else:
6690 else:
6683 pendingphase = phases.public
6691 pendingphase = phases.public
6684
6692
6685 if pendingphase > phases.newcommitphase(ui):
6693 if pendingphase > phases.newcommitphase(ui):
6686 t += ' (%s)' % phases.phasenames[pendingphase]
6694 t += ' (%s)' % phases.phasenames[pendingphase]
6687
6695
6688 if cleanworkdir:
6696 if cleanworkdir:
6689 # i18n: column positioning for "hg summary"
6697 # i18n: column positioning for "hg summary"
6690 ui.status(_('commit: %s\n') % t.strip())
6698 ui.status(_('commit: %s\n') % t.strip())
6691 else:
6699 else:
6692 # i18n: column positioning for "hg summary"
6700 # i18n: column positioning for "hg summary"
6693 ui.write(_('commit: %s\n') % t.strip())
6701 ui.write(_('commit: %s\n') % t.strip())
6694
6702
6695 # all ancestors of branch heads - all ancestors of parent = new csets
6703 # all ancestors of branch heads - all ancestors of parent = new csets
6696 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6704 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6697 bheads))
6705 bheads))
6698
6706
6699 if new == 0:
6707 if new == 0:
6700 # i18n: column positioning for "hg summary"
6708 # i18n: column positioning for "hg summary"
6701 ui.status(_('update: (current)\n'))
6709 ui.status(_('update: (current)\n'))
6702 elif pnode not in bheads:
6710 elif pnode not in bheads:
6703 # i18n: column positioning for "hg summary"
6711 # i18n: column positioning for "hg summary"
6704 ui.write(_('update: %d new changesets (update)\n') % new)
6712 ui.write(_('update: %d new changesets (update)\n') % new)
6705 else:
6713 else:
6706 # i18n: column positioning for "hg summary"
6714 # i18n: column positioning for "hg summary"
6707 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6715 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6708 (new, len(bheads)))
6716 (new, len(bheads)))
6709
6717
6710 t = []
6718 t = []
6711 draft = len(repo.revs('draft()'))
6719 draft = len(repo.revs('draft()'))
6712 if draft:
6720 if draft:
6713 t.append(_('%d draft') % draft)
6721 t.append(_('%d draft') % draft)
6714 secret = len(repo.revs('secret()'))
6722 secret = len(repo.revs('secret()'))
6715 if secret:
6723 if secret:
6716 t.append(_('%d secret') % secret)
6724 t.append(_('%d secret') % secret)
6717
6725
6718 if draft or secret:
6726 if draft or secret:
6719 ui.status(_('phases: %s\n') % ', '.join(t))
6727 ui.status(_('phases: %s\n') % ', '.join(t))
6720
6728
6721 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6729 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6722 for trouble in ("unstable", "divergent", "bumped"):
6730 for trouble in ("unstable", "divergent", "bumped"):
6723 numtrouble = len(repo.revs(trouble + "()"))
6731 numtrouble = len(repo.revs(trouble + "()"))
6724 # We write all the possibilities to ease translation
6732 # We write all the possibilities to ease translation
6725 troublemsg = {
6733 troublemsg = {
6726 "unstable": _("unstable: %d changesets"),
6734 "unstable": _("unstable: %d changesets"),
6727 "divergent": _("divergent: %d changesets"),
6735 "divergent": _("divergent: %d changesets"),
6728 "bumped": _("bumped: %d changesets"),
6736 "bumped": _("bumped: %d changesets"),
6729 }
6737 }
6730 if numtrouble > 0:
6738 if numtrouble > 0:
6731 ui.status(troublemsg[trouble] % numtrouble + "\n")
6739 ui.status(troublemsg[trouble] % numtrouble + "\n")
6732
6740
6733 cmdutil.summaryhooks(ui, repo)
6741 cmdutil.summaryhooks(ui, repo)
6734
6742
6735 if opts.get('remote'):
6743 if opts.get('remote'):
6736 needsincoming, needsoutgoing = True, True
6744 needsincoming, needsoutgoing = True, True
6737 else:
6745 else:
6738 needsincoming, needsoutgoing = False, False
6746 needsincoming, needsoutgoing = False, False
6739 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6747 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6740 if i:
6748 if i:
6741 needsincoming = True
6749 needsincoming = True
6742 if o:
6750 if o:
6743 needsoutgoing = True
6751 needsoutgoing = True
6744 if not needsincoming and not needsoutgoing:
6752 if not needsincoming and not needsoutgoing:
6745 return
6753 return
6746
6754
6747 def getincoming():
6755 def getincoming():
6748 source, branches = hg.parseurl(ui.expandpath('default'))
6756 source, branches = hg.parseurl(ui.expandpath('default'))
6749 sbranch = branches[0]
6757 sbranch = branches[0]
6750 try:
6758 try:
6751 other = hg.peer(repo, {}, source)
6759 other = hg.peer(repo, {}, source)
6752 except error.RepoError:
6760 except error.RepoError:
6753 if opts.get('remote'):
6761 if opts.get('remote'):
6754 raise
6762 raise
6755 return source, sbranch, None, None, None
6763 return source, sbranch, None, None, None
6756 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6764 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6757 if revs:
6765 if revs:
6758 revs = [other.lookup(rev) for rev in revs]
6766 revs = [other.lookup(rev) for rev in revs]
6759 ui.debug('comparing with %s\n' % util.hidepassword(source))
6767 ui.debug('comparing with %s\n' % util.hidepassword(source))
6760 repo.ui.pushbuffer()
6768 repo.ui.pushbuffer()
6761 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6769 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6762 repo.ui.popbuffer()
6770 repo.ui.popbuffer()
6763 return source, sbranch, other, commoninc, commoninc[1]
6771 return source, sbranch, other, commoninc, commoninc[1]
6764
6772
6765 if needsincoming:
6773 if needsincoming:
6766 source, sbranch, sother, commoninc, incoming = getincoming()
6774 source, sbranch, sother, commoninc, incoming = getincoming()
6767 else:
6775 else:
6768 source = sbranch = sother = commoninc = incoming = None
6776 source = sbranch = sother = commoninc = incoming = None
6769
6777
6770 def getoutgoing():
6778 def getoutgoing():
6771 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6779 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6772 dbranch = branches[0]
6780 dbranch = branches[0]
6773 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6781 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6774 if source != dest:
6782 if source != dest:
6775 try:
6783 try:
6776 dother = hg.peer(repo, {}, dest)
6784 dother = hg.peer(repo, {}, dest)
6777 except error.RepoError:
6785 except error.RepoError:
6778 if opts.get('remote'):
6786 if opts.get('remote'):
6779 raise
6787 raise
6780 return dest, dbranch, None, None
6788 return dest, dbranch, None, None
6781 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6789 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6782 elif sother is None:
6790 elif sother is None:
6783 # there is no explicit destination peer, but source one is invalid
6791 # there is no explicit destination peer, but source one is invalid
6784 return dest, dbranch, None, None
6792 return dest, dbranch, None, None
6785 else:
6793 else:
6786 dother = sother
6794 dother = sother
6787 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6795 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6788 common = None
6796 common = None
6789 else:
6797 else:
6790 common = commoninc
6798 common = commoninc
6791 if revs:
6799 if revs:
6792 revs = [repo.lookup(rev) for rev in revs]
6800 revs = [repo.lookup(rev) for rev in revs]
6793 repo.ui.pushbuffer()
6801 repo.ui.pushbuffer()
6794 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6802 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6795 commoninc=common)
6803 commoninc=common)
6796 repo.ui.popbuffer()
6804 repo.ui.popbuffer()
6797 return dest, dbranch, dother, outgoing
6805 return dest, dbranch, dother, outgoing
6798
6806
6799 if needsoutgoing:
6807 if needsoutgoing:
6800 dest, dbranch, dother, outgoing = getoutgoing()
6808 dest, dbranch, dother, outgoing = getoutgoing()
6801 else:
6809 else:
6802 dest = dbranch = dother = outgoing = None
6810 dest = dbranch = dother = outgoing = None
6803
6811
6804 if opts.get('remote'):
6812 if opts.get('remote'):
6805 t = []
6813 t = []
6806 if incoming:
6814 if incoming:
6807 t.append(_('1 or more incoming'))
6815 t.append(_('1 or more incoming'))
6808 o = outgoing.missing
6816 o = outgoing.missing
6809 if o:
6817 if o:
6810 t.append(_('%d outgoing') % len(o))
6818 t.append(_('%d outgoing') % len(o))
6811 other = dother or sother
6819 other = dother or sother
6812 if 'bookmarks' in other.listkeys('namespaces'):
6820 if 'bookmarks' in other.listkeys('namespaces'):
6813 counts = bookmarks.summary(repo, other)
6821 counts = bookmarks.summary(repo, other)
6814 if counts[0] > 0:
6822 if counts[0] > 0:
6815 t.append(_('%d incoming bookmarks') % counts[0])
6823 t.append(_('%d incoming bookmarks') % counts[0])
6816 if counts[1] > 0:
6824 if counts[1] > 0:
6817 t.append(_('%d outgoing bookmarks') % counts[1])
6825 t.append(_('%d outgoing bookmarks') % counts[1])
6818
6826
6819 if t:
6827 if t:
6820 # i18n: column positioning for "hg summary"
6828 # i18n: column positioning for "hg summary"
6821 ui.write(_('remote: %s\n') % (', '.join(t)))
6829 ui.write(_('remote: %s\n') % (', '.join(t)))
6822 else:
6830 else:
6823 # i18n: column positioning for "hg summary"
6831 # i18n: column positioning for "hg summary"
6824 ui.status(_('remote: (synced)\n'))
6832 ui.status(_('remote: (synced)\n'))
6825
6833
6826 cmdutil.summaryremotehooks(ui, repo, opts,
6834 cmdutil.summaryremotehooks(ui, repo, opts,
6827 ((source, sbranch, sother, commoninc),
6835 ((source, sbranch, sother, commoninc),
6828 (dest, dbranch, dother, outgoing)))
6836 (dest, dbranch, dother, outgoing)))
6829
6837
6830 @command('tag',
6838 @command('tag',
6831 [('f', 'force', None, _('force tag')),
6839 [('f', 'force', None, _('force tag')),
6832 ('l', 'local', None, _('make the tag local')),
6840 ('l', 'local', None, _('make the tag local')),
6833 ('r', 'rev', '', _('revision to tag'), _('REV')),
6841 ('r', 'rev', '', _('revision to tag'), _('REV')),
6834 ('', 'remove', None, _('remove a tag')),
6842 ('', 'remove', None, _('remove a tag')),
6835 # -l/--local is already there, commitopts cannot be used
6843 # -l/--local is already there, commitopts cannot be used
6836 ('e', 'edit', None, _('invoke editor on commit messages')),
6844 ('e', 'edit', None, _('invoke editor on commit messages')),
6837 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6845 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6838 ] + commitopts2,
6846 ] + commitopts2,
6839 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6847 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6840 def tag(ui, repo, name1, *names, **opts):
6848 def tag(ui, repo, name1, *names, **opts):
6841 """add one or more tags for the current or given revision
6849 """add one or more tags for the current or given revision
6842
6850
6843 Name a particular revision using <name>.
6851 Name a particular revision using <name>.
6844
6852
6845 Tags are used to name particular revisions of the repository and are
6853 Tags are used to name particular revisions of the repository and are
6846 very useful to compare different revisions, to go back to significant
6854 very useful to compare different revisions, to go back to significant
6847 earlier versions or to mark branch points as releases, etc. Changing
6855 earlier versions or to mark branch points as releases, etc. Changing
6848 an existing tag is normally disallowed; use -f/--force to override.
6856 an existing tag is normally disallowed; use -f/--force to override.
6849
6857
6850 If no revision is given, the parent of the working directory is
6858 If no revision is given, the parent of the working directory is
6851 used.
6859 used.
6852
6860
6853 To facilitate version control, distribution, and merging of tags,
6861 To facilitate version control, distribution, and merging of tags,
6854 they are stored as a file named ".hgtags" which is managed similarly
6862 they are stored as a file named ".hgtags" which is managed similarly
6855 to other project files and can be hand-edited if necessary. This
6863 to other project files and can be hand-edited if necessary. This
6856 also means that tagging creates a new commit. The file
6864 also means that tagging creates a new commit. The file
6857 ".hg/localtags" is used for local tags (not shared among
6865 ".hg/localtags" is used for local tags (not shared among
6858 repositories).
6866 repositories).
6859
6867
6860 Tag commits are usually made at the head of a branch. If the parent
6868 Tag commits are usually made at the head of a branch. If the parent
6861 of the working directory is not a branch head, :hg:`tag` aborts; use
6869 of the working directory is not a branch head, :hg:`tag` aborts; use
6862 -f/--force to force the tag commit to be based on a non-head
6870 -f/--force to force the tag commit to be based on a non-head
6863 changeset.
6871 changeset.
6864
6872
6865 See :hg:`help dates` for a list of formats valid for -d/--date.
6873 See :hg:`help dates` for a list of formats valid for -d/--date.
6866
6874
6867 Since tag names have priority over branch names during revision
6875 Since tag names have priority over branch names during revision
6868 lookup, using an existing branch name as a tag name is discouraged.
6876 lookup, using an existing branch name as a tag name is discouraged.
6869
6877
6870 Returns 0 on success.
6878 Returns 0 on success.
6871 """
6879 """
6872 wlock = lock = None
6880 wlock = lock = None
6873 try:
6881 try:
6874 wlock = repo.wlock()
6882 wlock = repo.wlock()
6875 lock = repo.lock()
6883 lock = repo.lock()
6876 rev_ = "."
6884 rev_ = "."
6877 names = [t.strip() for t in (name1,) + names]
6885 names = [t.strip() for t in (name1,) + names]
6878 if len(names) != len(set(names)):
6886 if len(names) != len(set(names)):
6879 raise error.Abort(_('tag names must be unique'))
6887 raise error.Abort(_('tag names must be unique'))
6880 for n in names:
6888 for n in names:
6881 scmutil.checknewlabel(repo, n, 'tag')
6889 scmutil.checknewlabel(repo, n, 'tag')
6882 if not n:
6890 if not n:
6883 raise error.Abort(_('tag names cannot consist entirely of '
6891 raise error.Abort(_('tag names cannot consist entirely of '
6884 'whitespace'))
6892 'whitespace'))
6885 if opts.get('rev') and opts.get('remove'):
6893 if opts.get('rev') and opts.get('remove'):
6886 raise error.Abort(_("--rev and --remove are incompatible"))
6894 raise error.Abort(_("--rev and --remove are incompatible"))
6887 if opts.get('rev'):
6895 if opts.get('rev'):
6888 rev_ = opts['rev']
6896 rev_ = opts['rev']
6889 message = opts.get('message')
6897 message = opts.get('message')
6890 if opts.get('remove'):
6898 if opts.get('remove'):
6891 if opts.get('local'):
6899 if opts.get('local'):
6892 expectedtype = 'local'
6900 expectedtype = 'local'
6893 else:
6901 else:
6894 expectedtype = 'global'
6902 expectedtype = 'global'
6895
6903
6896 for n in names:
6904 for n in names:
6897 if not repo.tagtype(n):
6905 if not repo.tagtype(n):
6898 raise error.Abort(_("tag '%s' does not exist") % n)
6906 raise error.Abort(_("tag '%s' does not exist") % n)
6899 if repo.tagtype(n) != expectedtype:
6907 if repo.tagtype(n) != expectedtype:
6900 if expectedtype == 'global':
6908 if expectedtype == 'global':
6901 raise error.Abort(_("tag '%s' is not a global tag") % n)
6909 raise error.Abort(_("tag '%s' is not a global tag") % n)
6902 else:
6910 else:
6903 raise error.Abort(_("tag '%s' is not a local tag") % n)
6911 raise error.Abort(_("tag '%s' is not a local tag") % n)
6904 rev_ = 'null'
6912 rev_ = 'null'
6905 if not message:
6913 if not message:
6906 # we don't translate commit messages
6914 # we don't translate commit messages
6907 message = 'Removed tag %s' % ', '.join(names)
6915 message = 'Removed tag %s' % ', '.join(names)
6908 elif not opts.get('force'):
6916 elif not opts.get('force'):
6909 for n in names:
6917 for n in names:
6910 if n in repo.tags():
6918 if n in repo.tags():
6911 raise error.Abort(_("tag '%s' already exists "
6919 raise error.Abort(_("tag '%s' already exists "
6912 "(use -f to force)") % n)
6920 "(use -f to force)") % n)
6913 if not opts.get('local'):
6921 if not opts.get('local'):
6914 p1, p2 = repo.dirstate.parents()
6922 p1, p2 = repo.dirstate.parents()
6915 if p2 != nullid:
6923 if p2 != nullid:
6916 raise error.Abort(_('uncommitted merge'))
6924 raise error.Abort(_('uncommitted merge'))
6917 bheads = repo.branchheads()
6925 bheads = repo.branchheads()
6918 if not opts.get('force') and bheads and p1 not in bheads:
6926 if not opts.get('force') and bheads and p1 not in bheads:
6919 raise error.Abort(_('not at a branch head (use -f to force)'))
6927 raise error.Abort(_('not at a branch head (use -f to force)'))
6920 r = scmutil.revsingle(repo, rev_).node()
6928 r = scmutil.revsingle(repo, rev_).node()
6921
6929
6922 if not message:
6930 if not message:
6923 # we don't translate commit messages
6931 # we don't translate commit messages
6924 message = ('Added tag %s for changeset %s' %
6932 message = ('Added tag %s for changeset %s' %
6925 (', '.join(names), short(r)))
6933 (', '.join(names), short(r)))
6926
6934
6927 date = opts.get('date')
6935 date = opts.get('date')
6928 if date:
6936 if date:
6929 date = util.parsedate(date)
6937 date = util.parsedate(date)
6930
6938
6931 if opts.get('remove'):
6939 if opts.get('remove'):
6932 editform = 'tag.remove'
6940 editform = 'tag.remove'
6933 else:
6941 else:
6934 editform = 'tag.add'
6942 editform = 'tag.add'
6935 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6943 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6936
6944
6937 # don't allow tagging the null rev
6945 # don't allow tagging the null rev
6938 if (not opts.get('remove') and
6946 if (not opts.get('remove') and
6939 scmutil.revsingle(repo, rev_).rev() == nullrev):
6947 scmutil.revsingle(repo, rev_).rev() == nullrev):
6940 raise error.Abort(_("cannot tag null revision"))
6948 raise error.Abort(_("cannot tag null revision"))
6941
6949
6942 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6950 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6943 editor=editor)
6951 editor=editor)
6944 finally:
6952 finally:
6945 release(lock, wlock)
6953 release(lock, wlock)
6946
6954
6947 @command('tags', formatteropts, '')
6955 @command('tags', formatteropts, '')
6948 def tags(ui, repo, **opts):
6956 def tags(ui, repo, **opts):
6949 """list repository tags
6957 """list repository tags
6950
6958
6951 This lists both regular and local tags. When the -v/--verbose
6959 This lists both regular and local tags. When the -v/--verbose
6952 switch is used, a third column "local" is printed for local tags.
6960 switch is used, a third column "local" is printed for local tags.
6953 When the -q/--quiet switch is used, only the tag name is printed.
6961 When the -q/--quiet switch is used, only the tag name is printed.
6954
6962
6955 Returns 0 on success.
6963 Returns 0 on success.
6956 """
6964 """
6957
6965
6958 fm = ui.formatter('tags', opts)
6966 fm = ui.formatter('tags', opts)
6959 hexfunc = fm.hexfunc
6967 hexfunc = fm.hexfunc
6960 tagtype = ""
6968 tagtype = ""
6961
6969
6962 for t, n in reversed(repo.tagslist()):
6970 for t, n in reversed(repo.tagslist()):
6963 hn = hexfunc(n)
6971 hn = hexfunc(n)
6964 label = 'tags.normal'
6972 label = 'tags.normal'
6965 tagtype = ''
6973 tagtype = ''
6966 if repo.tagtype(t) == 'local':
6974 if repo.tagtype(t) == 'local':
6967 label = 'tags.local'
6975 label = 'tags.local'
6968 tagtype = 'local'
6976 tagtype = 'local'
6969
6977
6970 fm.startitem()
6978 fm.startitem()
6971 fm.write('tag', '%s', t, label=label)
6979 fm.write('tag', '%s', t, label=label)
6972 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6980 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6973 fm.condwrite(not ui.quiet, 'rev node', fmt,
6981 fm.condwrite(not ui.quiet, 'rev node', fmt,
6974 repo.changelog.rev(n), hn, label=label)
6982 repo.changelog.rev(n), hn, label=label)
6975 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6983 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6976 tagtype, label=label)
6984 tagtype, label=label)
6977 fm.plain('\n')
6985 fm.plain('\n')
6978 fm.end()
6986 fm.end()
6979
6987
6980 @command('tip',
6988 @command('tip',
6981 [('p', 'patch', None, _('show patch')),
6989 [('p', 'patch', None, _('show patch')),
6982 ('g', 'git', None, _('use git extended diff format')),
6990 ('g', 'git', None, _('use git extended diff format')),
6983 ] + templateopts,
6991 ] + templateopts,
6984 _('[-p] [-g]'))
6992 _('[-p] [-g]'))
6985 def tip(ui, repo, **opts):
6993 def tip(ui, repo, **opts):
6986 """show the tip revision (DEPRECATED)
6994 """show the tip revision (DEPRECATED)
6987
6995
6988 The tip revision (usually just called the tip) is the changeset
6996 The tip revision (usually just called the tip) is the changeset
6989 most recently added to the repository (and therefore the most
6997 most recently added to the repository (and therefore the most
6990 recently changed head).
6998 recently changed head).
6991
6999
6992 If you have just made a commit, that commit will be the tip. If
7000 If you have just made a commit, that commit will be the tip. If
6993 you have just pulled changes from another repository, the tip of
7001 you have just pulled changes from another repository, the tip of
6994 that repository becomes the current tip. The "tip" tag is special
7002 that repository becomes the current tip. The "tip" tag is special
6995 and cannot be renamed or assigned to a different changeset.
7003 and cannot be renamed or assigned to a different changeset.
6996
7004
6997 This command is deprecated, please use :hg:`heads` instead.
7005 This command is deprecated, please use :hg:`heads` instead.
6998
7006
6999 Returns 0 on success.
7007 Returns 0 on success.
7000 """
7008 """
7001 displayer = cmdutil.show_changeset(ui, repo, opts)
7009 displayer = cmdutil.show_changeset(ui, repo, opts)
7002 displayer.show(repo['tip'])
7010 displayer.show(repo['tip'])
7003 displayer.close()
7011 displayer.close()
7004
7012
7005 @command('unbundle',
7013 @command('unbundle',
7006 [('u', 'update', None,
7014 [('u', 'update', None,
7007 _('update to new branch head if changesets were unbundled'))],
7015 _('update to new branch head if changesets were unbundled'))],
7008 _('[-u] FILE...'))
7016 _('[-u] FILE...'))
7009 def unbundle(ui, repo, fname1, *fnames, **opts):
7017 def unbundle(ui, repo, fname1, *fnames, **opts):
7010 """apply one or more changegroup files
7018 """apply one or more changegroup files
7011
7019
7012 Apply one or more compressed changegroup files generated by the
7020 Apply one or more compressed changegroup files generated by the
7013 bundle command.
7021 bundle command.
7014
7022
7015 Returns 0 on success, 1 if an update has unresolved files.
7023 Returns 0 on success, 1 if an update has unresolved files.
7016 """
7024 """
7017 fnames = (fname1,) + fnames
7025 fnames = (fname1,) + fnames
7018
7026
7019 with repo.lock():
7027 with repo.lock():
7020 for fname in fnames:
7028 for fname in fnames:
7021 f = hg.openpath(ui, fname)
7029 f = hg.openpath(ui, fname)
7022 gen = exchange.readbundle(ui, f, fname)
7030 gen = exchange.readbundle(ui, f, fname)
7023 if isinstance(gen, bundle2.unbundle20):
7031 if isinstance(gen, bundle2.unbundle20):
7024 tr = repo.transaction('unbundle')
7032 tr = repo.transaction('unbundle')
7025 try:
7033 try:
7026 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
7034 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
7027 url='bundle:' + fname)
7035 url='bundle:' + fname)
7028 tr.close()
7036 tr.close()
7029 except error.BundleUnknownFeatureError as exc:
7037 except error.BundleUnknownFeatureError as exc:
7030 raise error.Abort(_('%s: unknown bundle feature, %s')
7038 raise error.Abort(_('%s: unknown bundle feature, %s')
7031 % (fname, exc),
7039 % (fname, exc),
7032 hint=_("see https://mercurial-scm.org/"
7040 hint=_("see https://mercurial-scm.org/"
7033 "wiki/BundleFeature for more "
7041 "wiki/BundleFeature for more "
7034 "information"))
7042 "information"))
7035 finally:
7043 finally:
7036 if tr:
7044 if tr:
7037 tr.release()
7045 tr.release()
7038 changes = [r.get('return', 0)
7046 changes = [r.get('return', 0)
7039 for r in op.records['changegroup']]
7047 for r in op.records['changegroup']]
7040 modheads = changegroup.combineresults(changes)
7048 modheads = changegroup.combineresults(changes)
7041 elif isinstance(gen, streamclone.streamcloneapplier):
7049 elif isinstance(gen, streamclone.streamcloneapplier):
7042 raise error.Abort(
7050 raise error.Abort(
7043 _('packed bundles cannot be applied with '
7051 _('packed bundles cannot be applied with '
7044 '"hg unbundle"'),
7052 '"hg unbundle"'),
7045 hint=_('use "hg debugapplystreamclonebundle"'))
7053 hint=_('use "hg debugapplystreamclonebundle"'))
7046 else:
7054 else:
7047 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
7055 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
7048
7056
7049 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7057 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7050
7058
7051 @command('^update|up|checkout|co',
7059 @command('^update|up|checkout|co',
7052 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
7060 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
7053 ('c', 'check', None,
7061 ('c', 'check', None,
7054 _('update across branches if no uncommitted changes')),
7062 _('update across branches if no uncommitted changes')),
7055 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
7063 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
7056 ('r', 'rev', '', _('revision'), _('REV'))
7064 ('r', 'rev', '', _('revision'), _('REV'))
7057 ] + mergetoolopts,
7065 ] + mergetoolopts,
7058 _('[-c] [-C] [-d DATE] [[-r] REV]'))
7066 _('[-c] [-C] [-d DATE] [[-r] REV]'))
7059 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
7067 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
7060 tool=None):
7068 tool=None):
7061 """update working directory (or switch revisions)
7069 """update working directory (or switch revisions)
7062
7070
7063 Update the repository's working directory to the specified
7071 Update the repository's working directory to the specified
7064 changeset. If no changeset is specified, update to the tip of the
7072 changeset. If no changeset is specified, update to the tip of the
7065 current named branch and move the active bookmark (see :hg:`help
7073 current named branch and move the active bookmark (see :hg:`help
7066 bookmarks`).
7074 bookmarks`).
7067
7075
7068 Update sets the working directory's parent revision to the specified
7076 Update sets the working directory's parent revision to the specified
7069 changeset (see :hg:`help parents`).
7077 changeset (see :hg:`help parents`).
7070
7078
7071 If the changeset is not a descendant or ancestor of the working
7079 If the changeset is not a descendant or ancestor of the working
7072 directory's parent, the update is aborted. With the -c/--check
7080 directory's parent, the update is aborted. With the -c/--check
7073 option, the working directory is checked for uncommitted changes; if
7081 option, the working directory is checked for uncommitted changes; if
7074 none are found, the working directory is updated to the specified
7082 none are found, the working directory is updated to the specified
7075 changeset.
7083 changeset.
7076
7084
7077 .. container:: verbose
7085 .. container:: verbose
7078
7086
7079 The following rules apply when the working directory contains
7087 The following rules apply when the working directory contains
7080 uncommitted changes:
7088 uncommitted changes:
7081
7089
7082 1. If neither -c/--check nor -C/--clean is specified, and if
7090 1. If neither -c/--check nor -C/--clean is specified, and if
7083 the requested changeset is an ancestor or descendant of
7091 the requested changeset is an ancestor or descendant of
7084 the working directory's parent, the uncommitted changes
7092 the working directory's parent, the uncommitted changes
7085 are merged into the requested changeset and the merged
7093 are merged into the requested changeset and the merged
7086 result is left uncommitted. If the requested changeset is
7094 result is left uncommitted. If the requested changeset is
7087 not an ancestor or descendant (that is, it is on another
7095 not an ancestor or descendant (that is, it is on another
7088 branch), the update is aborted and the uncommitted changes
7096 branch), the update is aborted and the uncommitted changes
7089 are preserved.
7097 are preserved.
7090
7098
7091 2. With the -c/--check option, the update is aborted and the
7099 2. With the -c/--check option, the update is aborted and the
7092 uncommitted changes are preserved.
7100 uncommitted changes are preserved.
7093
7101
7094 3. With the -C/--clean option, uncommitted changes are discarded and
7102 3. With the -C/--clean option, uncommitted changes are discarded and
7095 the working directory is updated to the requested changeset.
7103 the working directory is updated to the requested changeset.
7096
7104
7097 To cancel an uncommitted merge (and lose your changes), use
7105 To cancel an uncommitted merge (and lose your changes), use
7098 :hg:`update --clean .`.
7106 :hg:`update --clean .`.
7099
7107
7100 Use null as the changeset to remove the working directory (like
7108 Use null as the changeset to remove the working directory (like
7101 :hg:`clone -U`).
7109 :hg:`clone -U`).
7102
7110
7103 If you want to revert just one file to an older revision, use
7111 If you want to revert just one file to an older revision, use
7104 :hg:`revert [-r REV] NAME`.
7112 :hg:`revert [-r REV] NAME`.
7105
7113
7106 See :hg:`help dates` for a list of formats valid for -d/--date.
7114 See :hg:`help dates` for a list of formats valid for -d/--date.
7107
7115
7108 Returns 0 on success, 1 if there are unresolved files.
7116 Returns 0 on success, 1 if there are unresolved files.
7109 """
7117 """
7110 if rev and node:
7118 if rev and node:
7111 raise error.Abort(_("please specify just one revision"))
7119 raise error.Abort(_("please specify just one revision"))
7112
7120
7113 if rev is None or rev == '':
7121 if rev is None or rev == '':
7114 rev = node
7122 rev = node
7115
7123
7116 if date and rev is not None:
7124 if date and rev is not None:
7117 raise error.Abort(_("you can't specify a revision and a date"))
7125 raise error.Abort(_("you can't specify a revision and a date"))
7118
7126
7119 if check and clean:
7127 if check and clean:
7120 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
7128 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
7121
7129
7122 with repo.wlock():
7130 with repo.wlock():
7123 cmdutil.clearunfinished(repo)
7131 cmdutil.clearunfinished(repo)
7124
7132
7125 if date:
7133 if date:
7126 rev = cmdutil.finddate(ui, repo, date)
7134 rev = cmdutil.finddate(ui, repo, date)
7127
7135
7128 # if we defined a bookmark, we have to remember the original name
7136 # if we defined a bookmark, we have to remember the original name
7129 brev = rev
7137 brev = rev
7130 rev = scmutil.revsingle(repo, rev, rev).rev()
7138 rev = scmutil.revsingle(repo, rev, rev).rev()
7131
7139
7132 if check:
7140 if check:
7133 cmdutil.bailifchanged(repo, merge=False)
7141 cmdutil.bailifchanged(repo, merge=False)
7134
7142
7135 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
7143 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
7136
7144
7137 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
7145 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
7138
7146
7139 @command('verify', [])
7147 @command('verify', [])
7140 def verify(ui, repo):
7148 def verify(ui, repo):
7141 """verify the integrity of the repository
7149 """verify the integrity of the repository
7142
7150
7143 Verify the integrity of the current repository.
7151 Verify the integrity of the current repository.
7144
7152
7145 This will perform an extensive check of the repository's
7153 This will perform an extensive check of the repository's
7146 integrity, validating the hashes and checksums of each entry in
7154 integrity, validating the hashes and checksums of each entry in
7147 the changelog, manifest, and tracked files, as well as the
7155 the changelog, manifest, and tracked files, as well as the
7148 integrity of their crosslinks and indices.
7156 integrity of their crosslinks and indices.
7149
7157
7150 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7158 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7151 for more information about recovery from corruption of the
7159 for more information about recovery from corruption of the
7152 repository.
7160 repository.
7153
7161
7154 Returns 0 on success, 1 if errors are encountered.
7162 Returns 0 on success, 1 if errors are encountered.
7155 """
7163 """
7156 return hg.verify(repo)
7164 return hg.verify(repo)
7157
7165
7158 @command('version', [], norepo=True)
7166 @command('version', [], norepo=True)
7159 def version_(ui):
7167 def version_(ui):
7160 """output version and copyright information"""
7168 """output version and copyright information"""
7161 ui.write(_("Mercurial Distributed SCM (version %s)\n")
7169 ui.write(_("Mercurial Distributed SCM (version %s)\n")
7162 % util.version())
7170 % util.version())
7163 ui.status(_(
7171 ui.status(_(
7164 "(see https://mercurial-scm.org for more information)\n"
7172 "(see https://mercurial-scm.org for more information)\n"
7165 "\nCopyright (C) 2005-2016 Matt Mackall and others\n"
7173 "\nCopyright (C) 2005-2016 Matt Mackall and others\n"
7166 "This is free software; see the source for copying conditions. "
7174 "This is free software; see the source for copying conditions. "
7167 "There is NO\nwarranty; "
7175 "There is NO\nwarranty; "
7168 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7176 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7169 ))
7177 ))
7170
7178
7171 ui.note(_("\nEnabled extensions:\n\n"))
7179 ui.note(_("\nEnabled extensions:\n\n"))
7172 if ui.verbose:
7180 if ui.verbose:
7173 # format names and versions into columns
7181 # format names and versions into columns
7174 names = []
7182 names = []
7175 vers = []
7183 vers = []
7176 place = []
7184 place = []
7177 for name, module in extensions.extensions():
7185 for name, module in extensions.extensions():
7178 names.append(name)
7186 names.append(name)
7179 vers.append(extensions.moduleversion(module))
7187 vers.append(extensions.moduleversion(module))
7180 if extensions.ismoduleinternal(module):
7188 if extensions.ismoduleinternal(module):
7181 place.append(_("internal"))
7189 place.append(_("internal"))
7182 else:
7190 else:
7183 place.append(_("external"))
7191 place.append(_("external"))
7184 if names:
7192 if names:
7185 maxnamelen = max(len(n) for n in names)
7193 maxnamelen = max(len(n) for n in names)
7186 for i, name in enumerate(names):
7194 for i, name in enumerate(names):
7187 ui.write(" %-*s %s %s\n" %
7195 ui.write(" %-*s %s %s\n" %
7188 (maxnamelen, name, place[i], vers[i]))
7196 (maxnamelen, name, place[i], vers[i]))
7189
7197
7190 def loadcmdtable(ui, name, cmdtable):
7198 def loadcmdtable(ui, name, cmdtable):
7191 """Load command functions from specified cmdtable
7199 """Load command functions from specified cmdtable
7192 """
7200 """
7193 overrides = [cmd for cmd in cmdtable if cmd in table]
7201 overrides = [cmd for cmd in cmdtable if cmd in table]
7194 if overrides:
7202 if overrides:
7195 ui.warn(_("extension '%s' overrides commands: %s\n")
7203 ui.warn(_("extension '%s' overrides commands: %s\n")
7196 % (name, " ".join(overrides)))
7204 % (name, " ".join(overrides)))
7197 table.update(cmdtable)
7205 table.update(cmdtable)
@@ -1,1644 +1,1653 b''
1 # merge.py - directory-level update/merge handling for Mercurial
1 # merge.py - directory-level update/merge handling for Mercurial
2 #
2 #
3 # Copyright 2006, 2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2006, 2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import errno
10 import errno
11 import os
11 import os
12 import shutil
12 import shutil
13 import struct
13 import struct
14
14
15 from .i18n import _
15 from .i18n import _
16 from .node import (
16 from .node import (
17 bin,
17 bin,
18 hex,
18 hex,
19 nullhex,
19 nullhex,
20 nullid,
20 nullid,
21 nullrev,
21 nullrev,
22 )
22 )
23 from . import (
23 from . import (
24 copies,
24 copies,
25 destutil,
25 destutil,
26 error,
26 error,
27 filemerge,
27 filemerge,
28 obsolete,
28 obsolete,
29 scmutil,
29 scmutil,
30 subrepo,
30 subrepo,
31 util,
31 util,
32 worker,
32 worker,
33 )
33 )
34
34
35 _pack = struct.pack
35 _pack = struct.pack
36 _unpack = struct.unpack
36 _unpack = struct.unpack
37
37
38 def _droponode(data):
38 def _droponode(data):
39 # used for compatibility for v1
39 # used for compatibility for v1
40 bits = data.split('\0')
40 bits = data.split('\0')
41 bits = bits[:-2] + bits[-1:]
41 bits = bits[:-2] + bits[-1:]
42 return '\0'.join(bits)
42 return '\0'.join(bits)
43
43
44 class mergestate(object):
44 class mergestate(object):
45 '''track 3-way merge state of individual files
45 '''track 3-way merge state of individual files
46
46
47 The merge state is stored on disk when needed. Two files are used: one with
47 The merge state is stored on disk when needed. Two files are used: one with
48 an old format (version 1), and one with a new format (version 2). Version 2
48 an old format (version 1), and one with a new format (version 2). Version 2
49 stores a superset of the data in version 1, including new kinds of records
49 stores a superset of the data in version 1, including new kinds of records
50 in the future. For more about the new format, see the documentation for
50 in the future. For more about the new format, see the documentation for
51 `_readrecordsv2`.
51 `_readrecordsv2`.
52
52
53 Each record can contain arbitrary content, and has an associated type. This
53 Each record can contain arbitrary content, and has an associated type. This
54 `type` should be a letter. If `type` is uppercase, the record is mandatory:
54 `type` should be a letter. If `type` is uppercase, the record is mandatory:
55 versions of Mercurial that don't support it should abort. If `type` is
55 versions of Mercurial that don't support it should abort. If `type` is
56 lowercase, the record can be safely ignored.
56 lowercase, the record can be safely ignored.
57
57
58 Currently known records:
58 Currently known records:
59
59
60 L: the node of the "local" part of the merge (hexified version)
60 L: the node of the "local" part of the merge (hexified version)
61 O: the node of the "other" part of the merge (hexified version)
61 O: the node of the "other" part of the merge (hexified version)
62 F: a file to be merged entry
62 F: a file to be merged entry
63 C: a change/delete or delete/change conflict
63 C: a change/delete or delete/change conflict
64 D: a file that the external merge driver will merge internally
64 D: a file that the external merge driver will merge internally
65 (experimental)
65 (experimental)
66 m: the external merge driver defined for this merge plus its run state
66 m: the external merge driver defined for this merge plus its run state
67 (experimental)
67 (experimental)
68 f: a (filename, dictonary) tuple of optional values for a given file
68 f: a (filename, dictonary) tuple of optional values for a given file
69 X: unsupported mandatory record type (used in tests)
69 X: unsupported mandatory record type (used in tests)
70 x: unsupported advisory record type (used in tests)
70 x: unsupported advisory record type (used in tests)
71 l: the labels for the parts of the merge.
71
72
72 Merge driver run states (experimental):
73 Merge driver run states (experimental):
73 u: driver-resolved files unmarked -- needs to be run next time we're about
74 u: driver-resolved files unmarked -- needs to be run next time we're about
74 to resolve or commit
75 to resolve or commit
75 m: driver-resolved files marked -- only needs to be run before commit
76 m: driver-resolved files marked -- only needs to be run before commit
76 s: success/skipped -- does not need to be run any more
77 s: success/skipped -- does not need to be run any more
77
78
78 '''
79 '''
79 statepathv1 = 'merge/state'
80 statepathv1 = 'merge/state'
80 statepathv2 = 'merge/state2'
81 statepathv2 = 'merge/state2'
81
82
82 @staticmethod
83 @staticmethod
83 def clean(repo, node=None, other=None):
84 def clean(repo, node=None, other=None, labels=None):
84 """Initialize a brand new merge state, removing any existing state on
85 """Initialize a brand new merge state, removing any existing state on
85 disk."""
86 disk."""
86 ms = mergestate(repo)
87 ms = mergestate(repo)
87 ms.reset(node, other)
88 ms.reset(node, other, labels)
88 return ms
89 return ms
89
90
90 @staticmethod
91 @staticmethod
91 def read(repo):
92 def read(repo):
92 """Initialize the merge state, reading it from disk."""
93 """Initialize the merge state, reading it from disk."""
93 ms = mergestate(repo)
94 ms = mergestate(repo)
94 ms._read()
95 ms._read()
95 return ms
96 return ms
96
97
97 def __init__(self, repo):
98 def __init__(self, repo):
98 """Initialize the merge state.
99 """Initialize the merge state.
99
100
100 Do not use this directly! Instead call read() or clean()."""
101 Do not use this directly! Instead call read() or clean()."""
101 self._repo = repo
102 self._repo = repo
102 self._dirty = False
103 self._dirty = False
104 self._labels = None
103
105
104 def reset(self, node=None, other=None):
106 def reset(self, node=None, other=None, labels=None):
105 self._state = {}
107 self._state = {}
106 self._stateextras = {}
108 self._stateextras = {}
107 self._local = None
109 self._local = None
108 self._other = None
110 self._other = None
111 self._labels = labels
109 for var in ('localctx', 'otherctx'):
112 for var in ('localctx', 'otherctx'):
110 if var in vars(self):
113 if var in vars(self):
111 delattr(self, var)
114 delattr(self, var)
112 if node:
115 if node:
113 self._local = node
116 self._local = node
114 self._other = other
117 self._other = other
115 self._readmergedriver = None
118 self._readmergedriver = None
116 if self.mergedriver:
119 if self.mergedriver:
117 self._mdstate = 's'
120 self._mdstate = 's'
118 else:
121 else:
119 self._mdstate = 'u'
122 self._mdstate = 'u'
120 shutil.rmtree(self._repo.join('merge'), True)
123 shutil.rmtree(self._repo.join('merge'), True)
121 self._results = {}
124 self._results = {}
122 self._dirty = False
125 self._dirty = False
123
126
124 def _read(self):
127 def _read(self):
125 """Analyse each record content to restore a serialized state from disk
128 """Analyse each record content to restore a serialized state from disk
126
129
127 This function process "record" entry produced by the de-serialization
130 This function process "record" entry produced by the de-serialization
128 of on disk file.
131 of on disk file.
129 """
132 """
130 self._state = {}
133 self._state = {}
131 self._stateextras = {}
134 self._stateextras = {}
132 self._local = None
135 self._local = None
133 self._other = None
136 self._other = None
134 for var in ('localctx', 'otherctx'):
137 for var in ('localctx', 'otherctx'):
135 if var in vars(self):
138 if var in vars(self):
136 delattr(self, var)
139 delattr(self, var)
137 self._readmergedriver = None
140 self._readmergedriver = None
138 self._mdstate = 's'
141 self._mdstate = 's'
139 unsupported = set()
142 unsupported = set()
140 records = self._readrecords()
143 records = self._readrecords()
141 for rtype, record in records:
144 for rtype, record in records:
142 if rtype == 'L':
145 if rtype == 'L':
143 self._local = bin(record)
146 self._local = bin(record)
144 elif rtype == 'O':
147 elif rtype == 'O':
145 self._other = bin(record)
148 self._other = bin(record)
146 elif rtype == 'm':
149 elif rtype == 'm':
147 bits = record.split('\0', 1)
150 bits = record.split('\0', 1)
148 mdstate = bits[1]
151 mdstate = bits[1]
149 if len(mdstate) != 1 or mdstate not in 'ums':
152 if len(mdstate) != 1 or mdstate not in 'ums':
150 # the merge driver should be idempotent, so just rerun it
153 # the merge driver should be idempotent, so just rerun it
151 mdstate = 'u'
154 mdstate = 'u'
152
155
153 self._readmergedriver = bits[0]
156 self._readmergedriver = bits[0]
154 self._mdstate = mdstate
157 self._mdstate = mdstate
155 elif rtype in 'FDC':
158 elif rtype in 'FDC':
156 bits = record.split('\0')
159 bits = record.split('\0')
157 self._state[bits[0]] = bits[1:]
160 self._state[bits[0]] = bits[1:]
158 elif rtype == 'f':
161 elif rtype == 'f':
159 filename, rawextras = record.split('\0', 1)
162 filename, rawextras = record.split('\0', 1)
160 extraparts = rawextras.split('\0')
163 extraparts = rawextras.split('\0')
161 extras = {}
164 extras = {}
162 i = 0
165 i = 0
163 while i < len(extraparts):
166 while i < len(extraparts):
164 extras[extraparts[i]] = extraparts[i + 1]
167 extras[extraparts[i]] = extraparts[i + 1]
165 i += 2
168 i += 2
166
169
167 self._stateextras[filename] = extras
170 self._stateextras[filename] = extras
171 elif rtype == 'l':
172 labels = record.split('\0', 2)
173 self._labels = [l for l in labels if len(l) > 0]
168 elif not rtype.islower():
174 elif not rtype.islower():
169 unsupported.add(rtype)
175 unsupported.add(rtype)
170 self._results = {}
176 self._results = {}
171 self._dirty = False
177 self._dirty = False
172
178
173 if unsupported:
179 if unsupported:
174 raise error.UnsupportedMergeRecords(unsupported)
180 raise error.UnsupportedMergeRecords(unsupported)
175
181
176 def _readrecords(self):
182 def _readrecords(self):
177 """Read merge state from disk and return a list of record (TYPE, data)
183 """Read merge state from disk and return a list of record (TYPE, data)
178
184
179 We read data from both v1 and v2 files and decide which one to use.
185 We read data from both v1 and v2 files and decide which one to use.
180
186
181 V1 has been used by version prior to 2.9.1 and contains less data than
187 V1 has been used by version prior to 2.9.1 and contains less data than
182 v2. We read both versions and check if no data in v2 contradicts
188 v2. We read both versions and check if no data in v2 contradicts
183 v1. If there is not contradiction we can safely assume that both v1
189 v1. If there is not contradiction we can safely assume that both v1
184 and v2 were written at the same time and use the extract data in v2. If
190 and v2 were written at the same time and use the extract data in v2. If
185 there is contradiction we ignore v2 content as we assume an old version
191 there is contradiction we ignore v2 content as we assume an old version
186 of Mercurial has overwritten the mergestate file and left an old v2
192 of Mercurial has overwritten the mergestate file and left an old v2
187 file around.
193 file around.
188
194
189 returns list of record [(TYPE, data), ...]"""
195 returns list of record [(TYPE, data), ...]"""
190 v1records = self._readrecordsv1()
196 v1records = self._readrecordsv1()
191 v2records = self._readrecordsv2()
197 v2records = self._readrecordsv2()
192 if self._v1v2match(v1records, v2records):
198 if self._v1v2match(v1records, v2records):
193 return v2records
199 return v2records
194 else:
200 else:
195 # v1 file is newer than v2 file, use it
201 # v1 file is newer than v2 file, use it
196 # we have to infer the "other" changeset of the merge
202 # we have to infer the "other" changeset of the merge
197 # we cannot do better than that with v1 of the format
203 # we cannot do better than that with v1 of the format
198 mctx = self._repo[None].parents()[-1]
204 mctx = self._repo[None].parents()[-1]
199 v1records.append(('O', mctx.hex()))
205 v1records.append(('O', mctx.hex()))
200 # add place holder "other" file node information
206 # add place holder "other" file node information
201 # nobody is using it yet so we do no need to fetch the data
207 # nobody is using it yet so we do no need to fetch the data
202 # if mctx was wrong `mctx[bits[-2]]` may fails.
208 # if mctx was wrong `mctx[bits[-2]]` may fails.
203 for idx, r in enumerate(v1records):
209 for idx, r in enumerate(v1records):
204 if r[0] == 'F':
210 if r[0] == 'F':
205 bits = r[1].split('\0')
211 bits = r[1].split('\0')
206 bits.insert(-2, '')
212 bits.insert(-2, '')
207 v1records[idx] = (r[0], '\0'.join(bits))
213 v1records[idx] = (r[0], '\0'.join(bits))
208 return v1records
214 return v1records
209
215
210 def _v1v2match(self, v1records, v2records):
216 def _v1v2match(self, v1records, v2records):
211 oldv2 = set() # old format version of v2 record
217 oldv2 = set() # old format version of v2 record
212 for rec in v2records:
218 for rec in v2records:
213 if rec[0] == 'L':
219 if rec[0] == 'L':
214 oldv2.add(rec)
220 oldv2.add(rec)
215 elif rec[0] == 'F':
221 elif rec[0] == 'F':
216 # drop the onode data (not contained in v1)
222 # drop the onode data (not contained in v1)
217 oldv2.add(('F', _droponode(rec[1])))
223 oldv2.add(('F', _droponode(rec[1])))
218 for rec in v1records:
224 for rec in v1records:
219 if rec not in oldv2:
225 if rec not in oldv2:
220 return False
226 return False
221 else:
227 else:
222 return True
228 return True
223
229
224 def _readrecordsv1(self):
230 def _readrecordsv1(self):
225 """read on disk merge state for version 1 file
231 """read on disk merge state for version 1 file
226
232
227 returns list of record [(TYPE, data), ...]
233 returns list of record [(TYPE, data), ...]
228
234
229 Note: the "F" data from this file are one entry short
235 Note: the "F" data from this file are one entry short
230 (no "other file node" entry)
236 (no "other file node" entry)
231 """
237 """
232 records = []
238 records = []
233 try:
239 try:
234 f = self._repo.vfs(self.statepathv1)
240 f = self._repo.vfs(self.statepathv1)
235 for i, l in enumerate(f):
241 for i, l in enumerate(f):
236 if i == 0:
242 if i == 0:
237 records.append(('L', l[:-1]))
243 records.append(('L', l[:-1]))
238 else:
244 else:
239 records.append(('F', l[:-1]))
245 records.append(('F', l[:-1]))
240 f.close()
246 f.close()
241 except IOError as err:
247 except IOError as err:
242 if err.errno != errno.ENOENT:
248 if err.errno != errno.ENOENT:
243 raise
249 raise
244 return records
250 return records
245
251
246 def _readrecordsv2(self):
252 def _readrecordsv2(self):
247 """read on disk merge state for version 2 file
253 """read on disk merge state for version 2 file
248
254
249 This format is a list of arbitrary records of the form:
255 This format is a list of arbitrary records of the form:
250
256
251 [type][length][content]
257 [type][length][content]
252
258
253 `type` is a single character, `length` is a 4 byte integer, and
259 `type` is a single character, `length` is a 4 byte integer, and
254 `content` is an arbitrary byte sequence of length `length`.
260 `content` is an arbitrary byte sequence of length `length`.
255
261
256 Mercurial versions prior to 3.7 have a bug where if there are
262 Mercurial versions prior to 3.7 have a bug where if there are
257 unsupported mandatory merge records, attempting to clear out the merge
263 unsupported mandatory merge records, attempting to clear out the merge
258 state with hg update --clean or similar aborts. The 't' record type
264 state with hg update --clean or similar aborts. The 't' record type
259 works around that by writing out what those versions treat as an
265 works around that by writing out what those versions treat as an
260 advisory record, but later versions interpret as special: the first
266 advisory record, but later versions interpret as special: the first
261 character is the 'real' record type and everything onwards is the data.
267 character is the 'real' record type and everything onwards is the data.
262
268
263 Returns list of records [(TYPE, data), ...]."""
269 Returns list of records [(TYPE, data), ...]."""
264 records = []
270 records = []
265 try:
271 try:
266 f = self._repo.vfs(self.statepathv2)
272 f = self._repo.vfs(self.statepathv2)
267 data = f.read()
273 data = f.read()
268 off = 0
274 off = 0
269 end = len(data)
275 end = len(data)
270 while off < end:
276 while off < end:
271 rtype = data[off]
277 rtype = data[off]
272 off += 1
278 off += 1
273 length = _unpack('>I', data[off:(off + 4)])[0]
279 length = _unpack('>I', data[off:(off + 4)])[0]
274 off += 4
280 off += 4
275 record = data[off:(off + length)]
281 record = data[off:(off + length)]
276 off += length
282 off += length
277 if rtype == 't':
283 if rtype == 't':
278 rtype, record = record[0], record[1:]
284 rtype, record = record[0], record[1:]
279 records.append((rtype, record))
285 records.append((rtype, record))
280 f.close()
286 f.close()
281 except IOError as err:
287 except IOError as err:
282 if err.errno != errno.ENOENT:
288 if err.errno != errno.ENOENT:
283 raise
289 raise
284 return records
290 return records
285
291
286 @util.propertycache
292 @util.propertycache
287 def mergedriver(self):
293 def mergedriver(self):
288 # protect against the following:
294 # protect against the following:
289 # - A configures a malicious merge driver in their hgrc, then
295 # - A configures a malicious merge driver in their hgrc, then
290 # pauses the merge
296 # pauses the merge
291 # - A edits their hgrc to remove references to the merge driver
297 # - A edits their hgrc to remove references to the merge driver
292 # - A gives a copy of their entire repo, including .hg, to B
298 # - A gives a copy of their entire repo, including .hg, to B
293 # - B inspects .hgrc and finds it to be clean
299 # - B inspects .hgrc and finds it to be clean
294 # - B then continues the merge and the malicious merge driver
300 # - B then continues the merge and the malicious merge driver
295 # gets invoked
301 # gets invoked
296 configmergedriver = self._repo.ui.config('experimental', 'mergedriver')
302 configmergedriver = self._repo.ui.config('experimental', 'mergedriver')
297 if (self._readmergedriver is not None
303 if (self._readmergedriver is not None
298 and self._readmergedriver != configmergedriver):
304 and self._readmergedriver != configmergedriver):
299 raise error.ConfigError(
305 raise error.ConfigError(
300 _("merge driver changed since merge started"),
306 _("merge driver changed since merge started"),
301 hint=_("revert merge driver change or abort merge"))
307 hint=_("revert merge driver change or abort merge"))
302
308
303 return configmergedriver
309 return configmergedriver
304
310
305 @util.propertycache
311 @util.propertycache
306 def localctx(self):
312 def localctx(self):
307 if self._local is None:
313 if self._local is None:
308 raise RuntimeError("localctx accessed but self._local isn't set")
314 raise RuntimeError("localctx accessed but self._local isn't set")
309 return self._repo[self._local]
315 return self._repo[self._local]
310
316
311 @util.propertycache
317 @util.propertycache
312 def otherctx(self):
318 def otherctx(self):
313 if self._other is None:
319 if self._other is None:
314 raise RuntimeError("otherctx accessed but self._other isn't set")
320 raise RuntimeError("otherctx accessed but self._other isn't set")
315 return self._repo[self._other]
321 return self._repo[self._other]
316
322
317 def active(self):
323 def active(self):
318 """Whether mergestate is active.
324 """Whether mergestate is active.
319
325
320 Returns True if there appears to be mergestate. This is a rough proxy
326 Returns True if there appears to be mergestate. This is a rough proxy
321 for "is a merge in progress."
327 for "is a merge in progress."
322 """
328 """
323 # Check local variables before looking at filesystem for performance
329 # Check local variables before looking at filesystem for performance
324 # reasons.
330 # reasons.
325 return bool(self._local) or bool(self._state) or \
331 return bool(self._local) or bool(self._state) or \
326 self._repo.vfs.exists(self.statepathv1) or \
332 self._repo.vfs.exists(self.statepathv1) or \
327 self._repo.vfs.exists(self.statepathv2)
333 self._repo.vfs.exists(self.statepathv2)
328
334
329 def commit(self):
335 def commit(self):
330 """Write current state on disk (if necessary)"""
336 """Write current state on disk (if necessary)"""
331 if self._dirty:
337 if self._dirty:
332 records = self._makerecords()
338 records = self._makerecords()
333 self._writerecords(records)
339 self._writerecords(records)
334 self._dirty = False
340 self._dirty = False
335
341
336 def _makerecords(self):
342 def _makerecords(self):
337 records = []
343 records = []
338 records.append(('L', hex(self._local)))
344 records.append(('L', hex(self._local)))
339 records.append(('O', hex(self._other)))
345 records.append(('O', hex(self._other)))
340 if self.mergedriver:
346 if self.mergedriver:
341 records.append(('m', '\0'.join([
347 records.append(('m', '\0'.join([
342 self.mergedriver, self._mdstate])))
348 self.mergedriver, self._mdstate])))
343 for d, v in self._state.iteritems():
349 for d, v in self._state.iteritems():
344 if v[0] == 'd':
350 if v[0] == 'd':
345 records.append(('D', '\0'.join([d] + v)))
351 records.append(('D', '\0'.join([d] + v)))
346 # v[1] == local ('cd'), v[6] == other ('dc') -- not supported by
352 # v[1] == local ('cd'), v[6] == other ('dc') -- not supported by
347 # older versions of Mercurial
353 # older versions of Mercurial
348 elif v[1] == nullhex or v[6] == nullhex:
354 elif v[1] == nullhex or v[6] == nullhex:
349 records.append(('C', '\0'.join([d] + v)))
355 records.append(('C', '\0'.join([d] + v)))
350 else:
356 else:
351 records.append(('F', '\0'.join([d] + v)))
357 records.append(('F', '\0'.join([d] + v)))
352 for filename, extras in sorted(self._stateextras.iteritems()):
358 for filename, extras in sorted(self._stateextras.iteritems()):
353 rawextras = '\0'.join('%s\0%s' % (k, v) for k, v in
359 rawextras = '\0'.join('%s\0%s' % (k, v) for k, v in
354 extras.iteritems())
360 extras.iteritems())
355 records.append(('f', '%s\0%s' % (filename, rawextras)))
361 records.append(('f', '%s\0%s' % (filename, rawextras)))
362 if self._labels is not None:
363 labels = '\0'.join(self._labels)
364 records.append(('l', labels))
356 return records
365 return records
357
366
358 def _writerecords(self, records):
367 def _writerecords(self, records):
359 """Write current state on disk (both v1 and v2)"""
368 """Write current state on disk (both v1 and v2)"""
360 self._writerecordsv1(records)
369 self._writerecordsv1(records)
361 self._writerecordsv2(records)
370 self._writerecordsv2(records)
362
371
363 def _writerecordsv1(self, records):
372 def _writerecordsv1(self, records):
364 """Write current state on disk in a version 1 file"""
373 """Write current state on disk in a version 1 file"""
365 f = self._repo.vfs(self.statepathv1, 'w')
374 f = self._repo.vfs(self.statepathv1, 'w')
366 irecords = iter(records)
375 irecords = iter(records)
367 lrecords = irecords.next()
376 lrecords = irecords.next()
368 assert lrecords[0] == 'L'
377 assert lrecords[0] == 'L'
369 f.write(hex(self._local) + '\n')
378 f.write(hex(self._local) + '\n')
370 for rtype, data in irecords:
379 for rtype, data in irecords:
371 if rtype == 'F':
380 if rtype == 'F':
372 f.write('%s\n' % _droponode(data))
381 f.write('%s\n' % _droponode(data))
373 f.close()
382 f.close()
374
383
375 def _writerecordsv2(self, records):
384 def _writerecordsv2(self, records):
376 """Write current state on disk in a version 2 file
385 """Write current state on disk in a version 2 file
377
386
378 See the docstring for _readrecordsv2 for why we use 't'."""
387 See the docstring for _readrecordsv2 for why we use 't'."""
379 # these are the records that all version 2 clients can read
388 # these are the records that all version 2 clients can read
380 whitelist = 'LOF'
389 whitelist = 'LOF'
381 f = self._repo.vfs(self.statepathv2, 'w')
390 f = self._repo.vfs(self.statepathv2, 'w')
382 for key, data in records:
391 for key, data in records:
383 assert len(key) == 1
392 assert len(key) == 1
384 if key not in whitelist:
393 if key not in whitelist:
385 key, data = 't', '%s%s' % (key, data)
394 key, data = 't', '%s%s' % (key, data)
386 format = '>sI%is' % len(data)
395 format = '>sI%is' % len(data)
387 f.write(_pack(format, key, len(data), data))
396 f.write(_pack(format, key, len(data), data))
388 f.close()
397 f.close()
389
398
390 def add(self, fcl, fco, fca, fd):
399 def add(self, fcl, fco, fca, fd):
391 """add a new (potentially?) conflicting file the merge state
400 """add a new (potentially?) conflicting file the merge state
392 fcl: file context for local,
401 fcl: file context for local,
393 fco: file context for remote,
402 fco: file context for remote,
394 fca: file context for ancestors,
403 fca: file context for ancestors,
395 fd: file path of the resulting merge.
404 fd: file path of the resulting merge.
396
405
397 note: also write the local version to the `.hg/merge` directory.
406 note: also write the local version to the `.hg/merge` directory.
398 """
407 """
399 if fcl.isabsent():
408 if fcl.isabsent():
400 hash = nullhex
409 hash = nullhex
401 else:
410 else:
402 hash = util.sha1(fcl.path()).hexdigest()
411 hash = util.sha1(fcl.path()).hexdigest()
403 self._repo.vfs.write('merge/' + hash, fcl.data())
412 self._repo.vfs.write('merge/' + hash, fcl.data())
404 self._state[fd] = ['u', hash, fcl.path(),
413 self._state[fd] = ['u', hash, fcl.path(),
405 fca.path(), hex(fca.filenode()),
414 fca.path(), hex(fca.filenode()),
406 fco.path(), hex(fco.filenode()),
415 fco.path(), hex(fco.filenode()),
407 fcl.flags()]
416 fcl.flags()]
408 self._stateextras[fd] = { 'ancestorlinknode' : hex(fca.node()) }
417 self._stateextras[fd] = { 'ancestorlinknode' : hex(fca.node()) }
409 self._dirty = True
418 self._dirty = True
410
419
411 def __contains__(self, dfile):
420 def __contains__(self, dfile):
412 return dfile in self._state
421 return dfile in self._state
413
422
414 def __getitem__(self, dfile):
423 def __getitem__(self, dfile):
415 return self._state[dfile][0]
424 return self._state[dfile][0]
416
425
417 def __iter__(self):
426 def __iter__(self):
418 return iter(sorted(self._state))
427 return iter(sorted(self._state))
419
428
420 def files(self):
429 def files(self):
421 return self._state.keys()
430 return self._state.keys()
422
431
423 def mark(self, dfile, state):
432 def mark(self, dfile, state):
424 self._state[dfile][0] = state
433 self._state[dfile][0] = state
425 self._dirty = True
434 self._dirty = True
426
435
427 def mdstate(self):
436 def mdstate(self):
428 return self._mdstate
437 return self._mdstate
429
438
430 def unresolved(self):
439 def unresolved(self):
431 """Obtain the paths of unresolved files."""
440 """Obtain the paths of unresolved files."""
432
441
433 for f, entry in self._state.items():
442 for f, entry in self._state.items():
434 if entry[0] == 'u':
443 if entry[0] == 'u':
435 yield f
444 yield f
436
445
437 def driverresolved(self):
446 def driverresolved(self):
438 """Obtain the paths of driver-resolved files."""
447 """Obtain the paths of driver-resolved files."""
439
448
440 for f, entry in self._state.items():
449 for f, entry in self._state.items():
441 if entry[0] == 'd':
450 if entry[0] == 'd':
442 yield f
451 yield f
443
452
444 def extras(self, filename):
453 def extras(self, filename):
445 return self._stateextras.setdefault(filename, {})
454 return self._stateextras.setdefault(filename, {})
446
455
447 def _resolve(self, preresolve, dfile, wctx, labels=None):
456 def _resolve(self, preresolve, dfile, wctx):
448 """rerun merge process for file path `dfile`"""
457 """rerun merge process for file path `dfile`"""
449 if self[dfile] in 'rd':
458 if self[dfile] in 'rd':
450 return True, 0
459 return True, 0
451 stateentry = self._state[dfile]
460 stateentry = self._state[dfile]
452 state, hash, lfile, afile, anode, ofile, onode, flags = stateentry
461 state, hash, lfile, afile, anode, ofile, onode, flags = stateentry
453 octx = self._repo[self._other]
462 octx = self._repo[self._other]
454 extras = self.extras(dfile)
463 extras = self.extras(dfile)
455 anccommitnode = extras.get('ancestorlinknode')
464 anccommitnode = extras.get('ancestorlinknode')
456 if anccommitnode:
465 if anccommitnode:
457 actx = self._repo[anccommitnode]
466 actx = self._repo[anccommitnode]
458 else:
467 else:
459 actx = None
468 actx = None
460 fcd = self._filectxorabsent(hash, wctx, dfile)
469 fcd = self._filectxorabsent(hash, wctx, dfile)
461 fco = self._filectxorabsent(onode, octx, ofile)
470 fco = self._filectxorabsent(onode, octx, ofile)
462 # TODO: move this to filectxorabsent
471 # TODO: move this to filectxorabsent
463 fca = self._repo.filectx(afile, fileid=anode, changeid=actx)
472 fca = self._repo.filectx(afile, fileid=anode, changeid=actx)
464 # "premerge" x flags
473 # "premerge" x flags
465 flo = fco.flags()
474 flo = fco.flags()
466 fla = fca.flags()
475 fla = fca.flags()
467 if 'x' in flags + flo + fla and 'l' not in flags + flo + fla:
476 if 'x' in flags + flo + fla and 'l' not in flags + flo + fla:
468 if fca.node() == nullid:
477 if fca.node() == nullid:
469 if preresolve:
478 if preresolve:
470 self._repo.ui.warn(
479 self._repo.ui.warn(
471 _('warning: cannot merge flags for %s\n') % afile)
480 _('warning: cannot merge flags for %s\n') % afile)
472 elif flags == fla:
481 elif flags == fla:
473 flags = flo
482 flags = flo
474 if preresolve:
483 if preresolve:
475 # restore local
484 # restore local
476 if hash != nullhex:
485 if hash != nullhex:
477 f = self._repo.vfs('merge/' + hash)
486 f = self._repo.vfs('merge/' + hash)
478 self._repo.wwrite(dfile, f.read(), flags)
487 self._repo.wwrite(dfile, f.read(), flags)
479 f.close()
488 f.close()
480 else:
489 else:
481 self._repo.wvfs.unlinkpath(dfile, ignoremissing=True)
490 self._repo.wvfs.unlinkpath(dfile, ignoremissing=True)
482 complete, r, deleted = filemerge.premerge(self._repo, self._local,
491 complete, r, deleted = filemerge.premerge(self._repo, self._local,
483 lfile, fcd, fco, fca,
492 lfile, fcd, fco, fca,
484 labels=labels)
493 labels=self._labels)
485 else:
494 else:
486 complete, r, deleted = filemerge.filemerge(self._repo, self._local,
495 complete, r, deleted = filemerge.filemerge(self._repo, self._local,
487 lfile, fcd, fco, fca,
496 lfile, fcd, fco, fca,
488 labels=labels)
497 labels=self._labels)
489 if r is None:
498 if r is None:
490 # no real conflict
499 # no real conflict
491 del self._state[dfile]
500 del self._state[dfile]
492 self._stateextras.pop(dfile, None)
501 self._stateextras.pop(dfile, None)
493 self._dirty = True
502 self._dirty = True
494 elif not r:
503 elif not r:
495 self.mark(dfile, 'r')
504 self.mark(dfile, 'r')
496
505
497 if complete:
506 if complete:
498 action = None
507 action = None
499 if deleted:
508 if deleted:
500 if fcd.isabsent():
509 if fcd.isabsent():
501 # dc: local picked. Need to drop if present, which may
510 # dc: local picked. Need to drop if present, which may
502 # happen on re-resolves.
511 # happen on re-resolves.
503 action = 'f'
512 action = 'f'
504 else:
513 else:
505 # cd: remote picked (or otherwise deleted)
514 # cd: remote picked (or otherwise deleted)
506 action = 'r'
515 action = 'r'
507 else:
516 else:
508 if fcd.isabsent(): # dc: remote picked
517 if fcd.isabsent(): # dc: remote picked
509 action = 'g'
518 action = 'g'
510 elif fco.isabsent(): # cd: local picked
519 elif fco.isabsent(): # cd: local picked
511 if dfile in self.localctx:
520 if dfile in self.localctx:
512 action = 'am'
521 action = 'am'
513 else:
522 else:
514 action = 'a'
523 action = 'a'
515 # else: regular merges (no action necessary)
524 # else: regular merges (no action necessary)
516 self._results[dfile] = r, action
525 self._results[dfile] = r, action
517
526
518 return complete, r
527 return complete, r
519
528
520 def _filectxorabsent(self, hexnode, ctx, f):
529 def _filectxorabsent(self, hexnode, ctx, f):
521 if hexnode == nullhex:
530 if hexnode == nullhex:
522 return filemerge.absentfilectx(ctx, f)
531 return filemerge.absentfilectx(ctx, f)
523 else:
532 else:
524 return ctx[f]
533 return ctx[f]
525
534
526 def preresolve(self, dfile, wctx, labels=None):
535 def preresolve(self, dfile, wctx):
527 """run premerge process for dfile
536 """run premerge process for dfile
528
537
529 Returns whether the merge is complete, and the exit code."""
538 Returns whether the merge is complete, and the exit code."""
530 return self._resolve(True, dfile, wctx, labels=labels)
539 return self._resolve(True, dfile, wctx)
531
540
532 def resolve(self, dfile, wctx, labels=None):
541 def resolve(self, dfile, wctx):
533 """run merge process (assuming premerge was run) for dfile
542 """run merge process (assuming premerge was run) for dfile
534
543
535 Returns the exit code of the merge."""
544 Returns the exit code of the merge."""
536 return self._resolve(False, dfile, wctx, labels=labels)[1]
545 return self._resolve(False, dfile, wctx)[1]
537
546
538 def counts(self):
547 def counts(self):
539 """return counts for updated, merged and removed files in this
548 """return counts for updated, merged and removed files in this
540 session"""
549 session"""
541 updated, merged, removed = 0, 0, 0
550 updated, merged, removed = 0, 0, 0
542 for r, action in self._results.itervalues():
551 for r, action in self._results.itervalues():
543 if r is None:
552 if r is None:
544 updated += 1
553 updated += 1
545 elif r == 0:
554 elif r == 0:
546 if action == 'r':
555 if action == 'r':
547 removed += 1
556 removed += 1
548 else:
557 else:
549 merged += 1
558 merged += 1
550 return updated, merged, removed
559 return updated, merged, removed
551
560
552 def unresolvedcount(self):
561 def unresolvedcount(self):
553 """get unresolved count for this merge (persistent)"""
562 """get unresolved count for this merge (persistent)"""
554 return len([True for f, entry in self._state.iteritems()
563 return len([True for f, entry in self._state.iteritems()
555 if entry[0] == 'u'])
564 if entry[0] == 'u'])
556
565
557 def actions(self):
566 def actions(self):
558 """return lists of actions to perform on the dirstate"""
567 """return lists of actions to perform on the dirstate"""
559 actions = {'r': [], 'f': [], 'a': [], 'am': [], 'g': []}
568 actions = {'r': [], 'f': [], 'a': [], 'am': [], 'g': []}
560 for f, (r, action) in self._results.iteritems():
569 for f, (r, action) in self._results.iteritems():
561 if action is not None:
570 if action is not None:
562 actions[action].append((f, None, "merge result"))
571 actions[action].append((f, None, "merge result"))
563 return actions
572 return actions
564
573
565 def recordactions(self):
574 def recordactions(self):
566 """record remove/add/get actions in the dirstate"""
575 """record remove/add/get actions in the dirstate"""
567 branchmerge = self._repo.dirstate.p2() != nullid
576 branchmerge = self._repo.dirstate.p2() != nullid
568 recordupdates(self._repo, self.actions(), branchmerge)
577 recordupdates(self._repo, self.actions(), branchmerge)
569
578
570 def queueremove(self, f):
579 def queueremove(self, f):
571 """queues a file to be removed from the dirstate
580 """queues a file to be removed from the dirstate
572
581
573 Meant for use by custom merge drivers."""
582 Meant for use by custom merge drivers."""
574 self._results[f] = 0, 'r'
583 self._results[f] = 0, 'r'
575
584
576 def queueadd(self, f):
585 def queueadd(self, f):
577 """queues a file to be added to the dirstate
586 """queues a file to be added to the dirstate
578
587
579 Meant for use by custom merge drivers."""
588 Meant for use by custom merge drivers."""
580 self._results[f] = 0, 'a'
589 self._results[f] = 0, 'a'
581
590
582 def queueget(self, f):
591 def queueget(self, f):
583 """queues a file to be marked modified in the dirstate
592 """queues a file to be marked modified in the dirstate
584
593
585 Meant for use by custom merge drivers."""
594 Meant for use by custom merge drivers."""
586 self._results[f] = 0, 'g'
595 self._results[f] = 0, 'g'
587
596
588 def _getcheckunknownconfig(repo, section, name):
597 def _getcheckunknownconfig(repo, section, name):
589 config = repo.ui.config(section, name, default='abort')
598 config = repo.ui.config(section, name, default='abort')
590 valid = ['abort', 'ignore', 'warn']
599 valid = ['abort', 'ignore', 'warn']
591 if config not in valid:
600 if config not in valid:
592 validstr = ', '.join(["'" + v + "'" for v in valid])
601 validstr = ', '.join(["'" + v + "'" for v in valid])
593 raise error.ConfigError(_("%s.%s not valid "
602 raise error.ConfigError(_("%s.%s not valid "
594 "('%s' is none of %s)")
603 "('%s' is none of %s)")
595 % (section, name, config, validstr))
604 % (section, name, config, validstr))
596 return config
605 return config
597
606
598 def _checkunknownfile(repo, wctx, mctx, f, f2=None):
607 def _checkunknownfile(repo, wctx, mctx, f, f2=None):
599 if f2 is None:
608 if f2 is None:
600 f2 = f
609 f2 = f
601 return (repo.wvfs.audit.check(f)
610 return (repo.wvfs.audit.check(f)
602 and repo.wvfs.isfileorlink(f)
611 and repo.wvfs.isfileorlink(f)
603 and repo.dirstate.normalize(f) not in repo.dirstate
612 and repo.dirstate.normalize(f) not in repo.dirstate
604 and mctx[f2].cmp(wctx[f]))
613 and mctx[f2].cmp(wctx[f]))
605
614
606 def _checkunknownfiles(repo, wctx, mctx, force, actions, mergeforce):
615 def _checkunknownfiles(repo, wctx, mctx, force, actions, mergeforce):
607 """
616 """
608 Considers any actions that care about the presence of conflicting unknown
617 Considers any actions that care about the presence of conflicting unknown
609 files. For some actions, the result is to abort; for others, it is to
618 files. For some actions, the result is to abort; for others, it is to
610 choose a different action.
619 choose a different action.
611 """
620 """
612 conflicts = set()
621 conflicts = set()
613 warnconflicts = set()
622 warnconflicts = set()
614 abortconflicts = set()
623 abortconflicts = set()
615 unknownconfig = _getcheckunknownconfig(repo, 'merge', 'checkunknown')
624 unknownconfig = _getcheckunknownconfig(repo, 'merge', 'checkunknown')
616 ignoredconfig = _getcheckunknownconfig(repo, 'merge', 'checkignored')
625 ignoredconfig = _getcheckunknownconfig(repo, 'merge', 'checkignored')
617 if not force:
626 if not force:
618 def collectconflicts(conflicts, config):
627 def collectconflicts(conflicts, config):
619 if config == 'abort':
628 if config == 'abort':
620 abortconflicts.update(conflicts)
629 abortconflicts.update(conflicts)
621 elif config == 'warn':
630 elif config == 'warn':
622 warnconflicts.update(conflicts)
631 warnconflicts.update(conflicts)
623
632
624 for f, (m, args, msg) in actions.iteritems():
633 for f, (m, args, msg) in actions.iteritems():
625 if m in ('c', 'dc'):
634 if m in ('c', 'dc'):
626 if _checkunknownfile(repo, wctx, mctx, f):
635 if _checkunknownfile(repo, wctx, mctx, f):
627 conflicts.add(f)
636 conflicts.add(f)
628 elif m == 'dg':
637 elif m == 'dg':
629 if _checkunknownfile(repo, wctx, mctx, f, args[0]):
638 if _checkunknownfile(repo, wctx, mctx, f, args[0]):
630 conflicts.add(f)
639 conflicts.add(f)
631
640
632 ignoredconflicts = set([c for c in conflicts
641 ignoredconflicts = set([c for c in conflicts
633 if repo.dirstate._ignore(c)])
642 if repo.dirstate._ignore(c)])
634 unknownconflicts = conflicts - ignoredconflicts
643 unknownconflicts = conflicts - ignoredconflicts
635 collectconflicts(ignoredconflicts, ignoredconfig)
644 collectconflicts(ignoredconflicts, ignoredconfig)
636 collectconflicts(unknownconflicts, unknownconfig)
645 collectconflicts(unknownconflicts, unknownconfig)
637 else:
646 else:
638 for f, (m, args, msg) in actions.iteritems():
647 for f, (m, args, msg) in actions.iteritems():
639 if m == 'cm':
648 if m == 'cm':
640 fl2, anc = args
649 fl2, anc = args
641 different = _checkunknownfile(repo, wctx, mctx, f)
650 different = _checkunknownfile(repo, wctx, mctx, f)
642 if repo.dirstate._ignore(f):
651 if repo.dirstate._ignore(f):
643 config = ignoredconfig
652 config = ignoredconfig
644 else:
653 else:
645 config = unknownconfig
654 config = unknownconfig
646
655
647 # The behavior when force is True is described by this table:
656 # The behavior when force is True is described by this table:
648 # config different mergeforce | action backup
657 # config different mergeforce | action backup
649 # * n * | get n
658 # * n * | get n
650 # * y y | merge -
659 # * y y | merge -
651 # abort y n | merge - (1)
660 # abort y n | merge - (1)
652 # warn y n | warn + get y
661 # warn y n | warn + get y
653 # ignore y n | get y
662 # ignore y n | get y
654 #
663 #
655 # (1) this is probably the wrong behavior here -- we should
664 # (1) this is probably the wrong behavior here -- we should
656 # probably abort, but some actions like rebases currently
665 # probably abort, but some actions like rebases currently
657 # don't like an abort happening in the middle of
666 # don't like an abort happening in the middle of
658 # merge.update.
667 # merge.update.
659 if not different:
668 if not different:
660 actions[f] = ('g', (fl2, False), "remote created")
669 actions[f] = ('g', (fl2, False), "remote created")
661 elif mergeforce or config == 'abort':
670 elif mergeforce or config == 'abort':
662 actions[f] = ('m', (f, f, None, False, anc),
671 actions[f] = ('m', (f, f, None, False, anc),
663 "remote differs from untracked local")
672 "remote differs from untracked local")
664 elif config == 'abort':
673 elif config == 'abort':
665 abortconflicts.add(f)
674 abortconflicts.add(f)
666 else:
675 else:
667 if config == 'warn':
676 if config == 'warn':
668 warnconflicts.add(f)
677 warnconflicts.add(f)
669 actions[f] = ('g', (fl2, True), "remote created")
678 actions[f] = ('g', (fl2, True), "remote created")
670
679
671 for f in sorted(abortconflicts):
680 for f in sorted(abortconflicts):
672 repo.ui.warn(_("%s: untracked file differs\n") % f)
681 repo.ui.warn(_("%s: untracked file differs\n") % f)
673 if abortconflicts:
682 if abortconflicts:
674 raise error.Abort(_("untracked files in working directory "
683 raise error.Abort(_("untracked files in working directory "
675 "differ from files in requested revision"))
684 "differ from files in requested revision"))
676
685
677 for f in sorted(warnconflicts):
686 for f in sorted(warnconflicts):
678 repo.ui.warn(_("%s: replacing untracked file\n") % f)
687 repo.ui.warn(_("%s: replacing untracked file\n") % f)
679
688
680 for f, (m, args, msg) in actions.iteritems():
689 for f, (m, args, msg) in actions.iteritems():
681 backup = f in conflicts
690 backup = f in conflicts
682 if m == 'c':
691 if m == 'c':
683 flags, = args
692 flags, = args
684 actions[f] = ('g', (flags, backup), msg)
693 actions[f] = ('g', (flags, backup), msg)
685
694
686 def _forgetremoved(wctx, mctx, branchmerge):
695 def _forgetremoved(wctx, mctx, branchmerge):
687 """
696 """
688 Forget removed files
697 Forget removed files
689
698
690 If we're jumping between revisions (as opposed to merging), and if
699 If we're jumping between revisions (as opposed to merging), and if
691 neither the working directory nor the target rev has the file,
700 neither the working directory nor the target rev has the file,
692 then we need to remove it from the dirstate, to prevent the
701 then we need to remove it from the dirstate, to prevent the
693 dirstate from listing the file when it is no longer in the
702 dirstate from listing the file when it is no longer in the
694 manifest.
703 manifest.
695
704
696 If we're merging, and the other revision has removed a file
705 If we're merging, and the other revision has removed a file
697 that is not present in the working directory, we need to mark it
706 that is not present in the working directory, we need to mark it
698 as removed.
707 as removed.
699 """
708 """
700
709
701 actions = {}
710 actions = {}
702 m = 'f'
711 m = 'f'
703 if branchmerge:
712 if branchmerge:
704 m = 'r'
713 m = 'r'
705 for f in wctx.deleted():
714 for f in wctx.deleted():
706 if f not in mctx:
715 if f not in mctx:
707 actions[f] = m, None, "forget deleted"
716 actions[f] = m, None, "forget deleted"
708
717
709 if not branchmerge:
718 if not branchmerge:
710 for f in wctx.removed():
719 for f in wctx.removed():
711 if f not in mctx:
720 if f not in mctx:
712 actions[f] = 'f', None, "forget removed"
721 actions[f] = 'f', None, "forget removed"
713
722
714 return actions
723 return actions
715
724
716 def _checkcollision(repo, wmf, actions):
725 def _checkcollision(repo, wmf, actions):
717 # build provisional merged manifest up
726 # build provisional merged manifest up
718 pmmf = set(wmf)
727 pmmf = set(wmf)
719
728
720 if actions:
729 if actions:
721 # k, dr, e and rd are no-op
730 # k, dr, e and rd are no-op
722 for m in 'a', 'am', 'f', 'g', 'cd', 'dc':
731 for m in 'a', 'am', 'f', 'g', 'cd', 'dc':
723 for f, args, msg in actions[m]:
732 for f, args, msg in actions[m]:
724 pmmf.add(f)
733 pmmf.add(f)
725 for f, args, msg in actions['r']:
734 for f, args, msg in actions['r']:
726 pmmf.discard(f)
735 pmmf.discard(f)
727 for f, args, msg in actions['dm']:
736 for f, args, msg in actions['dm']:
728 f2, flags = args
737 f2, flags = args
729 pmmf.discard(f2)
738 pmmf.discard(f2)
730 pmmf.add(f)
739 pmmf.add(f)
731 for f, args, msg in actions['dg']:
740 for f, args, msg in actions['dg']:
732 pmmf.add(f)
741 pmmf.add(f)
733 for f, args, msg in actions['m']:
742 for f, args, msg in actions['m']:
734 f1, f2, fa, move, anc = args
743 f1, f2, fa, move, anc = args
735 if move:
744 if move:
736 pmmf.discard(f1)
745 pmmf.discard(f1)
737 pmmf.add(f)
746 pmmf.add(f)
738
747
739 # check case-folding collision in provisional merged manifest
748 # check case-folding collision in provisional merged manifest
740 foldmap = {}
749 foldmap = {}
741 for f in sorted(pmmf):
750 for f in sorted(pmmf):
742 fold = util.normcase(f)
751 fold = util.normcase(f)
743 if fold in foldmap:
752 if fold in foldmap:
744 raise error.Abort(_("case-folding collision between %s and %s")
753 raise error.Abort(_("case-folding collision between %s and %s")
745 % (f, foldmap[fold]))
754 % (f, foldmap[fold]))
746 foldmap[fold] = f
755 foldmap[fold] = f
747
756
748 # check case-folding of directories
757 # check case-folding of directories
749 foldprefix = unfoldprefix = lastfull = ''
758 foldprefix = unfoldprefix = lastfull = ''
750 for fold, f in sorted(foldmap.items()):
759 for fold, f in sorted(foldmap.items()):
751 if fold.startswith(foldprefix) and not f.startswith(unfoldprefix):
760 if fold.startswith(foldprefix) and not f.startswith(unfoldprefix):
752 # the folded prefix matches but actual casing is different
761 # the folded prefix matches but actual casing is different
753 raise error.Abort(_("case-folding collision between "
762 raise error.Abort(_("case-folding collision between "
754 "%s and directory of %s") % (lastfull, f))
763 "%s and directory of %s") % (lastfull, f))
755 foldprefix = fold + '/'
764 foldprefix = fold + '/'
756 unfoldprefix = f + '/'
765 unfoldprefix = f + '/'
757 lastfull = f
766 lastfull = f
758
767
759 def driverpreprocess(repo, ms, wctx, labels=None):
768 def driverpreprocess(repo, ms, wctx, labels=None):
760 """run the preprocess step of the merge driver, if any
769 """run the preprocess step of the merge driver, if any
761
770
762 This is currently not implemented -- it's an extension point."""
771 This is currently not implemented -- it's an extension point."""
763 return True
772 return True
764
773
765 def driverconclude(repo, ms, wctx, labels=None):
774 def driverconclude(repo, ms, wctx, labels=None):
766 """run the conclude step of the merge driver, if any
775 """run the conclude step of the merge driver, if any
767
776
768 This is currently not implemented -- it's an extension point."""
777 This is currently not implemented -- it's an extension point."""
769 return True
778 return True
770
779
771 def manifestmerge(repo, wctx, p2, pa, branchmerge, force, matcher,
780 def manifestmerge(repo, wctx, p2, pa, branchmerge, force, matcher,
772 acceptremote, followcopies):
781 acceptremote, followcopies):
773 """
782 """
774 Merge p1 and p2 with ancestor pa and generate merge action list
783 Merge p1 and p2 with ancestor pa and generate merge action list
775
784
776 branchmerge and force are as passed in to update
785 branchmerge and force are as passed in to update
777 matcher = matcher to filter file lists
786 matcher = matcher to filter file lists
778 acceptremote = accept the incoming changes without prompting
787 acceptremote = accept the incoming changes without prompting
779 """
788 """
780 if matcher is not None and matcher.always():
789 if matcher is not None and matcher.always():
781 matcher = None
790 matcher = None
782
791
783 copy, movewithdir, diverge, renamedelete = {}, {}, {}, {}
792 copy, movewithdir, diverge, renamedelete = {}, {}, {}, {}
784
793
785 # manifests fetched in order are going to be faster, so prime the caches
794 # manifests fetched in order are going to be faster, so prime the caches
786 [x.manifest() for x in
795 [x.manifest() for x in
787 sorted(wctx.parents() + [p2, pa], key=lambda x: x.rev())]
796 sorted(wctx.parents() + [p2, pa], key=lambda x: x.rev())]
788
797
789 if followcopies:
798 if followcopies:
790 ret = copies.mergecopies(repo, wctx, p2, pa)
799 ret = copies.mergecopies(repo, wctx, p2, pa)
791 copy, movewithdir, diverge, renamedelete = ret
800 copy, movewithdir, diverge, renamedelete = ret
792
801
793 repo.ui.note(_("resolving manifests\n"))
802 repo.ui.note(_("resolving manifests\n"))
794 repo.ui.debug(" branchmerge: %s, force: %s, partial: %s\n"
803 repo.ui.debug(" branchmerge: %s, force: %s, partial: %s\n"
795 % (bool(branchmerge), bool(force), bool(matcher)))
804 % (bool(branchmerge), bool(force), bool(matcher)))
796 repo.ui.debug(" ancestor: %s, local: %s, remote: %s\n" % (pa, wctx, p2))
805 repo.ui.debug(" ancestor: %s, local: %s, remote: %s\n" % (pa, wctx, p2))
797
806
798 m1, m2, ma = wctx.manifest(), p2.manifest(), pa.manifest()
807 m1, m2, ma = wctx.manifest(), p2.manifest(), pa.manifest()
799 copied = set(copy.values())
808 copied = set(copy.values())
800 copied.update(movewithdir.values())
809 copied.update(movewithdir.values())
801
810
802 if '.hgsubstate' in m1:
811 if '.hgsubstate' in m1:
803 # check whether sub state is modified
812 # check whether sub state is modified
804 if any(wctx.sub(s).dirty() for s in wctx.substate):
813 if any(wctx.sub(s).dirty() for s in wctx.substate):
805 m1['.hgsubstate'] += '+'
814 m1['.hgsubstate'] += '+'
806
815
807 # Compare manifests
816 # Compare manifests
808 if matcher is not None:
817 if matcher is not None:
809 m1 = m1.matches(matcher)
818 m1 = m1.matches(matcher)
810 m2 = m2.matches(matcher)
819 m2 = m2.matches(matcher)
811 diff = m1.diff(m2)
820 diff = m1.diff(m2)
812
821
813 actions = {}
822 actions = {}
814 for f, ((n1, fl1), (n2, fl2)) in diff.iteritems():
823 for f, ((n1, fl1), (n2, fl2)) in diff.iteritems():
815 if n1 and n2: # file exists on both local and remote side
824 if n1 and n2: # file exists on both local and remote side
816 if f not in ma:
825 if f not in ma:
817 fa = copy.get(f, None)
826 fa = copy.get(f, None)
818 if fa is not None:
827 if fa is not None:
819 actions[f] = ('m', (f, f, fa, False, pa.node()),
828 actions[f] = ('m', (f, f, fa, False, pa.node()),
820 "both renamed from " + fa)
829 "both renamed from " + fa)
821 else:
830 else:
822 actions[f] = ('m', (f, f, None, False, pa.node()),
831 actions[f] = ('m', (f, f, None, False, pa.node()),
823 "both created")
832 "both created")
824 else:
833 else:
825 a = ma[f]
834 a = ma[f]
826 fla = ma.flags(f)
835 fla = ma.flags(f)
827 nol = 'l' not in fl1 + fl2 + fla
836 nol = 'l' not in fl1 + fl2 + fla
828 if n2 == a and fl2 == fla:
837 if n2 == a and fl2 == fla:
829 actions[f] = ('k' , (), "remote unchanged")
838 actions[f] = ('k' , (), "remote unchanged")
830 elif n1 == a and fl1 == fla: # local unchanged - use remote
839 elif n1 == a and fl1 == fla: # local unchanged - use remote
831 if n1 == n2: # optimization: keep local content
840 if n1 == n2: # optimization: keep local content
832 actions[f] = ('e', (fl2,), "update permissions")
841 actions[f] = ('e', (fl2,), "update permissions")
833 else:
842 else:
834 actions[f] = ('g', (fl2, False), "remote is newer")
843 actions[f] = ('g', (fl2, False), "remote is newer")
835 elif nol and n2 == a: # remote only changed 'x'
844 elif nol and n2 == a: # remote only changed 'x'
836 actions[f] = ('e', (fl2,), "update permissions")
845 actions[f] = ('e', (fl2,), "update permissions")
837 elif nol and n1 == a: # local only changed 'x'
846 elif nol and n1 == a: # local only changed 'x'
838 actions[f] = ('g', (fl1, False), "remote is newer")
847 actions[f] = ('g', (fl1, False), "remote is newer")
839 else: # both changed something
848 else: # both changed something
840 actions[f] = ('m', (f, f, f, False, pa.node()),
849 actions[f] = ('m', (f, f, f, False, pa.node()),
841 "versions differ")
850 "versions differ")
842 elif n1: # file exists only on local side
851 elif n1: # file exists only on local side
843 if f in copied:
852 if f in copied:
844 pass # we'll deal with it on m2 side
853 pass # we'll deal with it on m2 side
845 elif f in movewithdir: # directory rename, move local
854 elif f in movewithdir: # directory rename, move local
846 f2 = movewithdir[f]
855 f2 = movewithdir[f]
847 if f2 in m2:
856 if f2 in m2:
848 actions[f2] = ('m', (f, f2, None, True, pa.node()),
857 actions[f2] = ('m', (f, f2, None, True, pa.node()),
849 "remote directory rename, both created")
858 "remote directory rename, both created")
850 else:
859 else:
851 actions[f2] = ('dm', (f, fl1),
860 actions[f2] = ('dm', (f, fl1),
852 "remote directory rename - move from " + f)
861 "remote directory rename - move from " + f)
853 elif f in copy:
862 elif f in copy:
854 f2 = copy[f]
863 f2 = copy[f]
855 actions[f] = ('m', (f, f2, f2, False, pa.node()),
864 actions[f] = ('m', (f, f2, f2, False, pa.node()),
856 "local copied/moved from " + f2)
865 "local copied/moved from " + f2)
857 elif f in ma: # clean, a different, no remote
866 elif f in ma: # clean, a different, no remote
858 if n1 != ma[f]:
867 if n1 != ma[f]:
859 if acceptremote:
868 if acceptremote:
860 actions[f] = ('r', None, "remote delete")
869 actions[f] = ('r', None, "remote delete")
861 else:
870 else:
862 actions[f] = ('cd', (f, None, f, False, pa.node()),
871 actions[f] = ('cd', (f, None, f, False, pa.node()),
863 "prompt changed/deleted")
872 "prompt changed/deleted")
864 elif n1[20:] == 'a':
873 elif n1[20:] == 'a':
865 # This extra 'a' is added by working copy manifest to mark
874 # This extra 'a' is added by working copy manifest to mark
866 # the file as locally added. We should forget it instead of
875 # the file as locally added. We should forget it instead of
867 # deleting it.
876 # deleting it.
868 actions[f] = ('f', None, "remote deleted")
877 actions[f] = ('f', None, "remote deleted")
869 else:
878 else:
870 actions[f] = ('r', None, "other deleted")
879 actions[f] = ('r', None, "other deleted")
871 elif n2: # file exists only on remote side
880 elif n2: # file exists only on remote side
872 if f in copied:
881 if f in copied:
873 pass # we'll deal with it on m1 side
882 pass # we'll deal with it on m1 side
874 elif f in movewithdir:
883 elif f in movewithdir:
875 f2 = movewithdir[f]
884 f2 = movewithdir[f]
876 if f2 in m1:
885 if f2 in m1:
877 actions[f2] = ('m', (f2, f, None, False, pa.node()),
886 actions[f2] = ('m', (f2, f, None, False, pa.node()),
878 "local directory rename, both created")
887 "local directory rename, both created")
879 else:
888 else:
880 actions[f2] = ('dg', (f, fl2),
889 actions[f2] = ('dg', (f, fl2),
881 "local directory rename - get from " + f)
890 "local directory rename - get from " + f)
882 elif f in copy:
891 elif f in copy:
883 f2 = copy[f]
892 f2 = copy[f]
884 if f2 in m2:
893 if f2 in m2:
885 actions[f] = ('m', (f2, f, f2, False, pa.node()),
894 actions[f] = ('m', (f2, f, f2, False, pa.node()),
886 "remote copied from " + f2)
895 "remote copied from " + f2)
887 else:
896 else:
888 actions[f] = ('m', (f2, f, f2, True, pa.node()),
897 actions[f] = ('m', (f2, f, f2, True, pa.node()),
889 "remote moved from " + f2)
898 "remote moved from " + f2)
890 elif f not in ma:
899 elif f not in ma:
891 # local unknown, remote created: the logic is described by the
900 # local unknown, remote created: the logic is described by the
892 # following table:
901 # following table:
893 #
902 #
894 # force branchmerge different | action
903 # force branchmerge different | action
895 # n * * | create
904 # n * * | create
896 # y n * | create
905 # y n * | create
897 # y y n | create
906 # y y n | create
898 # y y y | merge
907 # y y y | merge
899 #
908 #
900 # Checking whether the files are different is expensive, so we
909 # Checking whether the files are different is expensive, so we
901 # don't do that when we can avoid it.
910 # don't do that when we can avoid it.
902 if not force:
911 if not force:
903 actions[f] = ('c', (fl2,), "remote created")
912 actions[f] = ('c', (fl2,), "remote created")
904 elif not branchmerge:
913 elif not branchmerge:
905 actions[f] = ('c', (fl2,), "remote created")
914 actions[f] = ('c', (fl2,), "remote created")
906 else:
915 else:
907 actions[f] = ('cm', (fl2, pa.node()),
916 actions[f] = ('cm', (fl2, pa.node()),
908 "remote created, get or merge")
917 "remote created, get or merge")
909 elif n2 != ma[f]:
918 elif n2 != ma[f]:
910 if acceptremote:
919 if acceptremote:
911 actions[f] = ('c', (fl2,), "remote recreating")
920 actions[f] = ('c', (fl2,), "remote recreating")
912 else:
921 else:
913 actions[f] = ('dc', (None, f, f, False, pa.node()),
922 actions[f] = ('dc', (None, f, f, False, pa.node()),
914 "prompt deleted/changed")
923 "prompt deleted/changed")
915
924
916 return actions, diverge, renamedelete
925 return actions, diverge, renamedelete
917
926
918 def _resolvetrivial(repo, wctx, mctx, ancestor, actions):
927 def _resolvetrivial(repo, wctx, mctx, ancestor, actions):
919 """Resolves false conflicts where the nodeid changed but the content
928 """Resolves false conflicts where the nodeid changed but the content
920 remained the same."""
929 remained the same."""
921
930
922 for f, (m, args, msg) in actions.items():
931 for f, (m, args, msg) in actions.items():
923 if m == 'cd' and f in ancestor and not wctx[f].cmp(ancestor[f]):
932 if m == 'cd' and f in ancestor and not wctx[f].cmp(ancestor[f]):
924 # local did change but ended up with same content
933 # local did change but ended up with same content
925 actions[f] = 'r', None, "prompt same"
934 actions[f] = 'r', None, "prompt same"
926 elif m == 'dc' and f in ancestor and not mctx[f].cmp(ancestor[f]):
935 elif m == 'dc' and f in ancestor and not mctx[f].cmp(ancestor[f]):
927 # remote did change but ended up with same content
936 # remote did change but ended up with same content
928 del actions[f] # don't get = keep local deleted
937 del actions[f] # don't get = keep local deleted
929
938
930 def calculateupdates(repo, wctx, mctx, ancestors, branchmerge, force,
939 def calculateupdates(repo, wctx, mctx, ancestors, branchmerge, force,
931 acceptremote, followcopies, matcher=None,
940 acceptremote, followcopies, matcher=None,
932 mergeforce=False):
941 mergeforce=False):
933 "Calculate the actions needed to merge mctx into wctx using ancestors"
942 "Calculate the actions needed to merge mctx into wctx using ancestors"
934 if len(ancestors) == 1: # default
943 if len(ancestors) == 1: # default
935 actions, diverge, renamedelete = manifestmerge(
944 actions, diverge, renamedelete = manifestmerge(
936 repo, wctx, mctx, ancestors[0], branchmerge, force, matcher,
945 repo, wctx, mctx, ancestors[0], branchmerge, force, matcher,
937 acceptremote, followcopies)
946 acceptremote, followcopies)
938 _checkunknownfiles(repo, wctx, mctx, force, actions, mergeforce)
947 _checkunknownfiles(repo, wctx, mctx, force, actions, mergeforce)
939
948
940 else: # only when merge.preferancestor=* - the default
949 else: # only when merge.preferancestor=* - the default
941 repo.ui.note(
950 repo.ui.note(
942 _("note: merging %s and %s using bids from ancestors %s\n") %
951 _("note: merging %s and %s using bids from ancestors %s\n") %
943 (wctx, mctx, _(' and ').join(str(anc) for anc in ancestors)))
952 (wctx, mctx, _(' and ').join(str(anc) for anc in ancestors)))
944
953
945 # Call for bids
954 # Call for bids
946 fbids = {} # mapping filename to bids (action method to list af actions)
955 fbids = {} # mapping filename to bids (action method to list af actions)
947 diverge, renamedelete = None, None
956 diverge, renamedelete = None, None
948 for ancestor in ancestors:
957 for ancestor in ancestors:
949 repo.ui.note(_('\ncalculating bids for ancestor %s\n') % ancestor)
958 repo.ui.note(_('\ncalculating bids for ancestor %s\n') % ancestor)
950 actions, diverge1, renamedelete1 = manifestmerge(
959 actions, diverge1, renamedelete1 = manifestmerge(
951 repo, wctx, mctx, ancestor, branchmerge, force, matcher,
960 repo, wctx, mctx, ancestor, branchmerge, force, matcher,
952 acceptremote, followcopies)
961 acceptremote, followcopies)
953 _checkunknownfiles(repo, wctx, mctx, force, actions, mergeforce)
962 _checkunknownfiles(repo, wctx, mctx, force, actions, mergeforce)
954
963
955 # Track the shortest set of warning on the theory that bid
964 # Track the shortest set of warning on the theory that bid
956 # merge will correctly incorporate more information
965 # merge will correctly incorporate more information
957 if diverge is None or len(diverge1) < len(diverge):
966 if diverge is None or len(diverge1) < len(diverge):
958 diverge = diverge1
967 diverge = diverge1
959 if renamedelete is None or len(renamedelete) < len(renamedelete1):
968 if renamedelete is None or len(renamedelete) < len(renamedelete1):
960 renamedelete = renamedelete1
969 renamedelete = renamedelete1
961
970
962 for f, a in sorted(actions.iteritems()):
971 for f, a in sorted(actions.iteritems()):
963 m, args, msg = a
972 m, args, msg = a
964 repo.ui.debug(' %s: %s -> %s\n' % (f, msg, m))
973 repo.ui.debug(' %s: %s -> %s\n' % (f, msg, m))
965 if f in fbids:
974 if f in fbids:
966 d = fbids[f]
975 d = fbids[f]
967 if m in d:
976 if m in d:
968 d[m].append(a)
977 d[m].append(a)
969 else:
978 else:
970 d[m] = [a]
979 d[m] = [a]
971 else:
980 else:
972 fbids[f] = {m: [a]}
981 fbids[f] = {m: [a]}
973
982
974 # Pick the best bid for each file
983 # Pick the best bid for each file
975 repo.ui.note(_('\nauction for merging merge bids\n'))
984 repo.ui.note(_('\nauction for merging merge bids\n'))
976 actions = {}
985 actions = {}
977 for f, bids in sorted(fbids.items()):
986 for f, bids in sorted(fbids.items()):
978 # bids is a mapping from action method to list af actions
987 # bids is a mapping from action method to list af actions
979 # Consensus?
988 # Consensus?
980 if len(bids) == 1: # all bids are the same kind of method
989 if len(bids) == 1: # all bids are the same kind of method
981 m, l = bids.items()[0]
990 m, l = bids.items()[0]
982 if all(a == l[0] for a in l[1:]): # len(bids) is > 1
991 if all(a == l[0] for a in l[1:]): # len(bids) is > 1
983 repo.ui.note(" %s: consensus for %s\n" % (f, m))
992 repo.ui.note(" %s: consensus for %s\n" % (f, m))
984 actions[f] = l[0]
993 actions[f] = l[0]
985 continue
994 continue
986 # If keep is an option, just do it.
995 # If keep is an option, just do it.
987 if 'k' in bids:
996 if 'k' in bids:
988 repo.ui.note(" %s: picking 'keep' action\n" % f)
997 repo.ui.note(" %s: picking 'keep' action\n" % f)
989 actions[f] = bids['k'][0]
998 actions[f] = bids['k'][0]
990 continue
999 continue
991 # If there are gets and they all agree [how could they not?], do it.
1000 # If there are gets and they all agree [how could they not?], do it.
992 if 'g' in bids:
1001 if 'g' in bids:
993 ga0 = bids['g'][0]
1002 ga0 = bids['g'][0]
994 if all(a == ga0 for a in bids['g'][1:]):
1003 if all(a == ga0 for a in bids['g'][1:]):
995 repo.ui.note(" %s: picking 'get' action\n" % f)
1004 repo.ui.note(" %s: picking 'get' action\n" % f)
996 actions[f] = ga0
1005 actions[f] = ga0
997 continue
1006 continue
998 # TODO: Consider other simple actions such as mode changes
1007 # TODO: Consider other simple actions such as mode changes
999 # Handle inefficient democrazy.
1008 # Handle inefficient democrazy.
1000 repo.ui.note(_(' %s: multiple bids for merge action:\n') % f)
1009 repo.ui.note(_(' %s: multiple bids for merge action:\n') % f)
1001 for m, l in sorted(bids.items()):
1010 for m, l in sorted(bids.items()):
1002 for _f, args, msg in l:
1011 for _f, args, msg in l:
1003 repo.ui.note(' %s -> %s\n' % (msg, m))
1012 repo.ui.note(' %s -> %s\n' % (msg, m))
1004 # Pick random action. TODO: Instead, prompt user when resolving
1013 # Pick random action. TODO: Instead, prompt user when resolving
1005 m, l = bids.items()[0]
1014 m, l = bids.items()[0]
1006 repo.ui.warn(_(' %s: ambiguous merge - picked %s action\n') %
1015 repo.ui.warn(_(' %s: ambiguous merge - picked %s action\n') %
1007 (f, m))
1016 (f, m))
1008 actions[f] = l[0]
1017 actions[f] = l[0]
1009 continue
1018 continue
1010 repo.ui.note(_('end of auction\n\n'))
1019 repo.ui.note(_('end of auction\n\n'))
1011
1020
1012 _resolvetrivial(repo, wctx, mctx, ancestors[0], actions)
1021 _resolvetrivial(repo, wctx, mctx, ancestors[0], actions)
1013
1022
1014 if wctx.rev() is None:
1023 if wctx.rev() is None:
1015 fractions = _forgetremoved(wctx, mctx, branchmerge)
1024 fractions = _forgetremoved(wctx, mctx, branchmerge)
1016 actions.update(fractions)
1025 actions.update(fractions)
1017
1026
1018 return actions, diverge, renamedelete
1027 return actions, diverge, renamedelete
1019
1028
1020 def batchremove(repo, actions):
1029 def batchremove(repo, actions):
1021 """apply removes to the working directory
1030 """apply removes to the working directory
1022
1031
1023 yields tuples for progress updates
1032 yields tuples for progress updates
1024 """
1033 """
1025 verbose = repo.ui.verbose
1034 verbose = repo.ui.verbose
1026 unlink = util.unlinkpath
1035 unlink = util.unlinkpath
1027 wjoin = repo.wjoin
1036 wjoin = repo.wjoin
1028 audit = repo.wvfs.audit
1037 audit = repo.wvfs.audit
1029 i = 0
1038 i = 0
1030 for f, args, msg in actions:
1039 for f, args, msg in actions:
1031 repo.ui.debug(" %s: %s -> r\n" % (f, msg))
1040 repo.ui.debug(" %s: %s -> r\n" % (f, msg))
1032 if verbose:
1041 if verbose:
1033 repo.ui.note(_("removing %s\n") % f)
1042 repo.ui.note(_("removing %s\n") % f)
1034 audit(f)
1043 audit(f)
1035 try:
1044 try:
1036 unlink(wjoin(f), ignoremissing=True)
1045 unlink(wjoin(f), ignoremissing=True)
1037 except OSError as inst:
1046 except OSError as inst:
1038 repo.ui.warn(_("update failed to remove %s: %s!\n") %
1047 repo.ui.warn(_("update failed to remove %s: %s!\n") %
1039 (f, inst.strerror))
1048 (f, inst.strerror))
1040 if i == 100:
1049 if i == 100:
1041 yield i, f
1050 yield i, f
1042 i = 0
1051 i = 0
1043 i += 1
1052 i += 1
1044 if i > 0:
1053 if i > 0:
1045 yield i, f
1054 yield i, f
1046
1055
1047 def batchget(repo, mctx, actions):
1056 def batchget(repo, mctx, actions):
1048 """apply gets to the working directory
1057 """apply gets to the working directory
1049
1058
1050 mctx is the context to get from
1059 mctx is the context to get from
1051
1060
1052 yields tuples for progress updates
1061 yields tuples for progress updates
1053 """
1062 """
1054 verbose = repo.ui.verbose
1063 verbose = repo.ui.verbose
1055 fctx = mctx.filectx
1064 fctx = mctx.filectx
1056 wwrite = repo.wwrite
1065 wwrite = repo.wwrite
1057 ui = repo.ui
1066 ui = repo.ui
1058 i = 0
1067 i = 0
1059 with repo.wvfs.backgroundclosing(ui, expectedcount=len(actions)):
1068 with repo.wvfs.backgroundclosing(ui, expectedcount=len(actions)):
1060 for f, (flags, backup), msg in actions:
1069 for f, (flags, backup), msg in actions:
1061 repo.ui.debug(" %s: %s -> g\n" % (f, msg))
1070 repo.ui.debug(" %s: %s -> g\n" % (f, msg))
1062 if verbose:
1071 if verbose:
1063 repo.ui.note(_("getting %s\n") % f)
1072 repo.ui.note(_("getting %s\n") % f)
1064
1073
1065 if backup:
1074 if backup:
1066 absf = repo.wjoin(f)
1075 absf = repo.wjoin(f)
1067 orig = scmutil.origpath(ui, repo, absf)
1076 orig = scmutil.origpath(ui, repo, absf)
1068 try:
1077 try:
1069 # TODO Mercurial has always aborted if an untracked
1078 # TODO Mercurial has always aborted if an untracked
1070 # directory is replaced by a tracked file, or generally
1079 # directory is replaced by a tracked file, or generally
1071 # with file/directory merges. This needs to be sorted out.
1080 # with file/directory merges. This needs to be sorted out.
1072 if repo.wvfs.isfileorlink(f):
1081 if repo.wvfs.isfileorlink(f):
1073 util.rename(absf, orig)
1082 util.rename(absf, orig)
1074 except OSError as e:
1083 except OSError as e:
1075 if e.errno != errno.ENOENT:
1084 if e.errno != errno.ENOENT:
1076 raise
1085 raise
1077
1086
1078 wwrite(f, fctx(f).data(), flags, backgroundclose=True)
1087 wwrite(f, fctx(f).data(), flags, backgroundclose=True)
1079 if i == 100:
1088 if i == 100:
1080 yield i, f
1089 yield i, f
1081 i = 0
1090 i = 0
1082 i += 1
1091 i += 1
1083 if i > 0:
1092 if i > 0:
1084 yield i, f
1093 yield i, f
1085
1094
1086 def applyupdates(repo, actions, wctx, mctx, overwrite, labels=None):
1095 def applyupdates(repo, actions, wctx, mctx, overwrite, labels=None):
1087 """apply the merge action list to the working directory
1096 """apply the merge action list to the working directory
1088
1097
1089 wctx is the working copy context
1098 wctx is the working copy context
1090 mctx is the context to be merged into the working copy
1099 mctx is the context to be merged into the working copy
1091
1100
1092 Return a tuple of counts (updated, merged, removed, unresolved) that
1101 Return a tuple of counts (updated, merged, removed, unresolved) that
1093 describes how many files were affected by the update.
1102 describes how many files were affected by the update.
1094 """
1103 """
1095
1104
1096 updated, merged, removed = 0, 0, 0
1105 updated, merged, removed = 0, 0, 0
1097 ms = mergestate.clean(repo, wctx.p1().node(), mctx.node())
1106 ms = mergestate.clean(repo, wctx.p1().node(), mctx.node(), labels)
1098 moves = []
1107 moves = []
1099 for m, l in actions.items():
1108 for m, l in actions.items():
1100 l.sort()
1109 l.sort()
1101
1110
1102 # 'cd' and 'dc' actions are treated like other merge conflicts
1111 # 'cd' and 'dc' actions are treated like other merge conflicts
1103 mergeactions = sorted(actions['cd'])
1112 mergeactions = sorted(actions['cd'])
1104 mergeactions.extend(sorted(actions['dc']))
1113 mergeactions.extend(sorted(actions['dc']))
1105 mergeactions.extend(actions['m'])
1114 mergeactions.extend(actions['m'])
1106 for f, args, msg in mergeactions:
1115 for f, args, msg in mergeactions:
1107 f1, f2, fa, move, anc = args
1116 f1, f2, fa, move, anc = args
1108 if f == '.hgsubstate': # merged internally
1117 if f == '.hgsubstate': # merged internally
1109 continue
1118 continue
1110 if f1 is None:
1119 if f1 is None:
1111 fcl = filemerge.absentfilectx(wctx, fa)
1120 fcl = filemerge.absentfilectx(wctx, fa)
1112 else:
1121 else:
1113 repo.ui.debug(" preserving %s for resolve of %s\n" % (f1, f))
1122 repo.ui.debug(" preserving %s for resolve of %s\n" % (f1, f))
1114 fcl = wctx[f1]
1123 fcl = wctx[f1]
1115 if f2 is None:
1124 if f2 is None:
1116 fco = filemerge.absentfilectx(mctx, fa)
1125 fco = filemerge.absentfilectx(mctx, fa)
1117 else:
1126 else:
1118 fco = mctx[f2]
1127 fco = mctx[f2]
1119 actx = repo[anc]
1128 actx = repo[anc]
1120 if fa in actx:
1129 if fa in actx:
1121 fca = actx[fa]
1130 fca = actx[fa]
1122 else:
1131 else:
1123 # TODO: move to absentfilectx
1132 # TODO: move to absentfilectx
1124 fca = repo.filectx(f1, fileid=nullrev)
1133 fca = repo.filectx(f1, fileid=nullrev)
1125 ms.add(fcl, fco, fca, f)
1134 ms.add(fcl, fco, fca, f)
1126 if f1 != f and move:
1135 if f1 != f and move:
1127 moves.append(f1)
1136 moves.append(f1)
1128
1137
1129 audit = repo.wvfs.audit
1138 audit = repo.wvfs.audit
1130 _updating = _('updating')
1139 _updating = _('updating')
1131 _files = _('files')
1140 _files = _('files')
1132 progress = repo.ui.progress
1141 progress = repo.ui.progress
1133
1142
1134 # remove renamed files after safely stored
1143 # remove renamed files after safely stored
1135 for f in moves:
1144 for f in moves:
1136 if os.path.lexists(repo.wjoin(f)):
1145 if os.path.lexists(repo.wjoin(f)):
1137 repo.ui.debug("removing %s\n" % f)
1146 repo.ui.debug("removing %s\n" % f)
1138 audit(f)
1147 audit(f)
1139 util.unlinkpath(repo.wjoin(f))
1148 util.unlinkpath(repo.wjoin(f))
1140
1149
1141 numupdates = sum(len(l) for m, l in actions.items() if m != 'k')
1150 numupdates = sum(len(l) for m, l in actions.items() if m != 'k')
1142
1151
1143 if [a for a in actions['r'] if a[0] == '.hgsubstate']:
1152 if [a for a in actions['r'] if a[0] == '.hgsubstate']:
1144 subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
1153 subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
1145
1154
1146 # remove in parallel (must come first)
1155 # remove in parallel (must come first)
1147 z = 0
1156 z = 0
1148 prog = worker.worker(repo.ui, 0.001, batchremove, (repo,), actions['r'])
1157 prog = worker.worker(repo.ui, 0.001, batchremove, (repo,), actions['r'])
1149 for i, item in prog:
1158 for i, item in prog:
1150 z += i
1159 z += i
1151 progress(_updating, z, item=item, total=numupdates, unit=_files)
1160 progress(_updating, z, item=item, total=numupdates, unit=_files)
1152 removed = len(actions['r'])
1161 removed = len(actions['r'])
1153
1162
1154 # get in parallel
1163 # get in parallel
1155 prog = worker.worker(repo.ui, 0.001, batchget, (repo, mctx), actions['g'])
1164 prog = worker.worker(repo.ui, 0.001, batchget, (repo, mctx), actions['g'])
1156 for i, item in prog:
1165 for i, item in prog:
1157 z += i
1166 z += i
1158 progress(_updating, z, item=item, total=numupdates, unit=_files)
1167 progress(_updating, z, item=item, total=numupdates, unit=_files)
1159 updated = len(actions['g'])
1168 updated = len(actions['g'])
1160
1169
1161 if [a for a in actions['g'] if a[0] == '.hgsubstate']:
1170 if [a for a in actions['g'] if a[0] == '.hgsubstate']:
1162 subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
1171 subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
1163
1172
1164 # forget (manifest only, just log it) (must come first)
1173 # forget (manifest only, just log it) (must come first)
1165 for f, args, msg in actions['f']:
1174 for f, args, msg in actions['f']:
1166 repo.ui.debug(" %s: %s -> f\n" % (f, msg))
1175 repo.ui.debug(" %s: %s -> f\n" % (f, msg))
1167 z += 1
1176 z += 1
1168 progress(_updating, z, item=f, total=numupdates, unit=_files)
1177 progress(_updating, z, item=f, total=numupdates, unit=_files)
1169
1178
1170 # re-add (manifest only, just log it)
1179 # re-add (manifest only, just log it)
1171 for f, args, msg in actions['a']:
1180 for f, args, msg in actions['a']:
1172 repo.ui.debug(" %s: %s -> a\n" % (f, msg))
1181 repo.ui.debug(" %s: %s -> a\n" % (f, msg))
1173 z += 1
1182 z += 1
1174 progress(_updating, z, item=f, total=numupdates, unit=_files)
1183 progress(_updating, z, item=f, total=numupdates, unit=_files)
1175
1184
1176 # re-add/mark as modified (manifest only, just log it)
1185 # re-add/mark as modified (manifest only, just log it)
1177 for f, args, msg in actions['am']:
1186 for f, args, msg in actions['am']:
1178 repo.ui.debug(" %s: %s -> am\n" % (f, msg))
1187 repo.ui.debug(" %s: %s -> am\n" % (f, msg))
1179 z += 1
1188 z += 1
1180 progress(_updating, z, item=f, total=numupdates, unit=_files)
1189 progress(_updating, z, item=f, total=numupdates, unit=_files)
1181
1190
1182 # keep (noop, just log it)
1191 # keep (noop, just log it)
1183 for f, args, msg in actions['k']:
1192 for f, args, msg in actions['k']:
1184 repo.ui.debug(" %s: %s -> k\n" % (f, msg))
1193 repo.ui.debug(" %s: %s -> k\n" % (f, msg))
1185 # no progress
1194 # no progress
1186
1195
1187 # directory rename, move local
1196 # directory rename, move local
1188 for f, args, msg in actions['dm']:
1197 for f, args, msg in actions['dm']:
1189 repo.ui.debug(" %s: %s -> dm\n" % (f, msg))
1198 repo.ui.debug(" %s: %s -> dm\n" % (f, msg))
1190 z += 1
1199 z += 1
1191 progress(_updating, z, item=f, total=numupdates, unit=_files)
1200 progress(_updating, z, item=f, total=numupdates, unit=_files)
1192 f0, flags = args
1201 f0, flags = args
1193 repo.ui.note(_("moving %s to %s\n") % (f0, f))
1202 repo.ui.note(_("moving %s to %s\n") % (f0, f))
1194 audit(f)
1203 audit(f)
1195 repo.wwrite(f, wctx.filectx(f0).data(), flags)
1204 repo.wwrite(f, wctx.filectx(f0).data(), flags)
1196 util.unlinkpath(repo.wjoin(f0))
1205 util.unlinkpath(repo.wjoin(f0))
1197 updated += 1
1206 updated += 1
1198
1207
1199 # local directory rename, get
1208 # local directory rename, get
1200 for f, args, msg in actions['dg']:
1209 for f, args, msg in actions['dg']:
1201 repo.ui.debug(" %s: %s -> dg\n" % (f, msg))
1210 repo.ui.debug(" %s: %s -> dg\n" % (f, msg))
1202 z += 1
1211 z += 1
1203 progress(_updating, z, item=f, total=numupdates, unit=_files)
1212 progress(_updating, z, item=f, total=numupdates, unit=_files)
1204 f0, flags = args
1213 f0, flags = args
1205 repo.ui.note(_("getting %s to %s\n") % (f0, f))
1214 repo.ui.note(_("getting %s to %s\n") % (f0, f))
1206 repo.wwrite(f, mctx.filectx(f0).data(), flags)
1215 repo.wwrite(f, mctx.filectx(f0).data(), flags)
1207 updated += 1
1216 updated += 1
1208
1217
1209 # exec
1218 # exec
1210 for f, args, msg in actions['e']:
1219 for f, args, msg in actions['e']:
1211 repo.ui.debug(" %s: %s -> e\n" % (f, msg))
1220 repo.ui.debug(" %s: %s -> e\n" % (f, msg))
1212 z += 1
1221 z += 1
1213 progress(_updating, z, item=f, total=numupdates, unit=_files)
1222 progress(_updating, z, item=f, total=numupdates, unit=_files)
1214 flags, = args
1223 flags, = args
1215 audit(f)
1224 audit(f)
1216 util.setflags(repo.wjoin(f), 'l' in flags, 'x' in flags)
1225 util.setflags(repo.wjoin(f), 'l' in flags, 'x' in flags)
1217 updated += 1
1226 updated += 1
1218
1227
1219 # the ordering is important here -- ms.mergedriver will raise if the merge
1228 # the ordering is important here -- ms.mergedriver will raise if the merge
1220 # driver has changed, and we want to be able to bypass it when overwrite is
1229 # driver has changed, and we want to be able to bypass it when overwrite is
1221 # True
1230 # True
1222 usemergedriver = not overwrite and mergeactions and ms.mergedriver
1231 usemergedriver = not overwrite and mergeactions and ms.mergedriver
1223
1232
1224 if usemergedriver:
1233 if usemergedriver:
1225 ms.commit()
1234 ms.commit()
1226 proceed = driverpreprocess(repo, ms, wctx, labels=labels)
1235 proceed = driverpreprocess(repo, ms, wctx, labels=labels)
1227 # the driver might leave some files unresolved
1236 # the driver might leave some files unresolved
1228 unresolvedf = set(ms.unresolved())
1237 unresolvedf = set(ms.unresolved())
1229 if not proceed:
1238 if not proceed:
1230 # XXX setting unresolved to at least 1 is a hack to make sure we
1239 # XXX setting unresolved to at least 1 is a hack to make sure we
1231 # error out
1240 # error out
1232 return updated, merged, removed, max(len(unresolvedf), 1)
1241 return updated, merged, removed, max(len(unresolvedf), 1)
1233 newactions = []
1242 newactions = []
1234 for f, args, msg in mergeactions:
1243 for f, args, msg in mergeactions:
1235 if f in unresolvedf:
1244 if f in unresolvedf:
1236 newactions.append((f, args, msg))
1245 newactions.append((f, args, msg))
1237 mergeactions = newactions
1246 mergeactions = newactions
1238
1247
1239 # premerge
1248 # premerge
1240 tocomplete = []
1249 tocomplete = []
1241 for f, args, msg in mergeactions:
1250 for f, args, msg in mergeactions:
1242 repo.ui.debug(" %s: %s -> m (premerge)\n" % (f, msg))
1251 repo.ui.debug(" %s: %s -> m (premerge)\n" % (f, msg))
1243 z += 1
1252 z += 1
1244 progress(_updating, z, item=f, total=numupdates, unit=_files)
1253 progress(_updating, z, item=f, total=numupdates, unit=_files)
1245 if f == '.hgsubstate': # subrepo states need updating
1254 if f == '.hgsubstate': # subrepo states need updating
1246 subrepo.submerge(repo, wctx, mctx, wctx.ancestor(mctx),
1255 subrepo.submerge(repo, wctx, mctx, wctx.ancestor(mctx),
1247 overwrite)
1256 overwrite)
1248 continue
1257 continue
1249 audit(f)
1258 audit(f)
1250 complete, r = ms.preresolve(f, wctx, labels=labels)
1259 complete, r = ms.preresolve(f, wctx)
1251 if not complete:
1260 if not complete:
1252 numupdates += 1
1261 numupdates += 1
1253 tocomplete.append((f, args, msg))
1262 tocomplete.append((f, args, msg))
1254
1263
1255 # merge
1264 # merge
1256 for f, args, msg in tocomplete:
1265 for f, args, msg in tocomplete:
1257 repo.ui.debug(" %s: %s -> m (merge)\n" % (f, msg))
1266 repo.ui.debug(" %s: %s -> m (merge)\n" % (f, msg))
1258 z += 1
1267 z += 1
1259 progress(_updating, z, item=f, total=numupdates, unit=_files)
1268 progress(_updating, z, item=f, total=numupdates, unit=_files)
1260 ms.resolve(f, wctx, labels=labels)
1269 ms.resolve(f, wctx)
1261
1270
1262 ms.commit()
1271 ms.commit()
1263
1272
1264 unresolved = ms.unresolvedcount()
1273 unresolved = ms.unresolvedcount()
1265
1274
1266 if usemergedriver and not unresolved and ms.mdstate() != 's':
1275 if usemergedriver and not unresolved and ms.mdstate() != 's':
1267 if not driverconclude(repo, ms, wctx, labels=labels):
1276 if not driverconclude(repo, ms, wctx, labels=labels):
1268 # XXX setting unresolved to at least 1 is a hack to make sure we
1277 # XXX setting unresolved to at least 1 is a hack to make sure we
1269 # error out
1278 # error out
1270 unresolved = max(unresolved, 1)
1279 unresolved = max(unresolved, 1)
1271
1280
1272 ms.commit()
1281 ms.commit()
1273
1282
1274 msupdated, msmerged, msremoved = ms.counts()
1283 msupdated, msmerged, msremoved = ms.counts()
1275 updated += msupdated
1284 updated += msupdated
1276 merged += msmerged
1285 merged += msmerged
1277 removed += msremoved
1286 removed += msremoved
1278
1287
1279 extraactions = ms.actions()
1288 extraactions = ms.actions()
1280 for k, acts in extraactions.iteritems():
1289 for k, acts in extraactions.iteritems():
1281 actions[k].extend(acts)
1290 actions[k].extend(acts)
1282
1291
1283 progress(_updating, None, total=numupdates, unit=_files)
1292 progress(_updating, None, total=numupdates, unit=_files)
1284
1293
1285 return updated, merged, removed, unresolved
1294 return updated, merged, removed, unresolved
1286
1295
1287 def recordupdates(repo, actions, branchmerge):
1296 def recordupdates(repo, actions, branchmerge):
1288 "record merge actions to the dirstate"
1297 "record merge actions to the dirstate"
1289 # remove (must come first)
1298 # remove (must come first)
1290 for f, args, msg in actions.get('r', []):
1299 for f, args, msg in actions.get('r', []):
1291 if branchmerge:
1300 if branchmerge:
1292 repo.dirstate.remove(f)
1301 repo.dirstate.remove(f)
1293 else:
1302 else:
1294 repo.dirstate.drop(f)
1303 repo.dirstate.drop(f)
1295
1304
1296 # forget (must come first)
1305 # forget (must come first)
1297 for f, args, msg in actions.get('f', []):
1306 for f, args, msg in actions.get('f', []):
1298 repo.dirstate.drop(f)
1307 repo.dirstate.drop(f)
1299
1308
1300 # re-add
1309 # re-add
1301 for f, args, msg in actions.get('a', []):
1310 for f, args, msg in actions.get('a', []):
1302 repo.dirstate.add(f)
1311 repo.dirstate.add(f)
1303
1312
1304 # re-add/mark as modified
1313 # re-add/mark as modified
1305 for f, args, msg in actions.get('am', []):
1314 for f, args, msg in actions.get('am', []):
1306 if branchmerge:
1315 if branchmerge:
1307 repo.dirstate.normallookup(f)
1316 repo.dirstate.normallookup(f)
1308 else:
1317 else:
1309 repo.dirstate.add(f)
1318 repo.dirstate.add(f)
1310
1319
1311 # exec change
1320 # exec change
1312 for f, args, msg in actions.get('e', []):
1321 for f, args, msg in actions.get('e', []):
1313 repo.dirstate.normallookup(f)
1322 repo.dirstate.normallookup(f)
1314
1323
1315 # keep
1324 # keep
1316 for f, args, msg in actions.get('k', []):
1325 for f, args, msg in actions.get('k', []):
1317 pass
1326 pass
1318
1327
1319 # get
1328 # get
1320 for f, args, msg in actions.get('g', []):
1329 for f, args, msg in actions.get('g', []):
1321 if branchmerge:
1330 if branchmerge:
1322 repo.dirstate.otherparent(f)
1331 repo.dirstate.otherparent(f)
1323 else:
1332 else:
1324 repo.dirstate.normal(f)
1333 repo.dirstate.normal(f)
1325
1334
1326 # merge
1335 # merge
1327 for f, args, msg in actions.get('m', []):
1336 for f, args, msg in actions.get('m', []):
1328 f1, f2, fa, move, anc = args
1337 f1, f2, fa, move, anc = args
1329 if branchmerge:
1338 if branchmerge:
1330 # We've done a branch merge, mark this file as merged
1339 # We've done a branch merge, mark this file as merged
1331 # so that we properly record the merger later
1340 # so that we properly record the merger later
1332 repo.dirstate.merge(f)
1341 repo.dirstate.merge(f)
1333 if f1 != f2: # copy/rename
1342 if f1 != f2: # copy/rename
1334 if move:
1343 if move:
1335 repo.dirstate.remove(f1)
1344 repo.dirstate.remove(f1)
1336 if f1 != f:
1345 if f1 != f:
1337 repo.dirstate.copy(f1, f)
1346 repo.dirstate.copy(f1, f)
1338 else:
1347 else:
1339 repo.dirstate.copy(f2, f)
1348 repo.dirstate.copy(f2, f)
1340 else:
1349 else:
1341 # We've update-merged a locally modified file, so
1350 # We've update-merged a locally modified file, so
1342 # we set the dirstate to emulate a normal checkout
1351 # we set the dirstate to emulate a normal checkout
1343 # of that file some time in the past. Thus our
1352 # of that file some time in the past. Thus our
1344 # merge will appear as a normal local file
1353 # merge will appear as a normal local file
1345 # modification.
1354 # modification.
1346 if f2 == f: # file not locally copied/moved
1355 if f2 == f: # file not locally copied/moved
1347 repo.dirstate.normallookup(f)
1356 repo.dirstate.normallookup(f)
1348 if move:
1357 if move:
1349 repo.dirstate.drop(f1)
1358 repo.dirstate.drop(f1)
1350
1359
1351 # directory rename, move local
1360 # directory rename, move local
1352 for f, args, msg in actions.get('dm', []):
1361 for f, args, msg in actions.get('dm', []):
1353 f0, flag = args
1362 f0, flag = args
1354 if branchmerge:
1363 if branchmerge:
1355 repo.dirstate.add(f)
1364 repo.dirstate.add(f)
1356 repo.dirstate.remove(f0)
1365 repo.dirstate.remove(f0)
1357 repo.dirstate.copy(f0, f)
1366 repo.dirstate.copy(f0, f)
1358 else:
1367 else:
1359 repo.dirstate.normal(f)
1368 repo.dirstate.normal(f)
1360 repo.dirstate.drop(f0)
1369 repo.dirstate.drop(f0)
1361
1370
1362 # directory rename, get
1371 # directory rename, get
1363 for f, args, msg in actions.get('dg', []):
1372 for f, args, msg in actions.get('dg', []):
1364 f0, flag = args
1373 f0, flag = args
1365 if branchmerge:
1374 if branchmerge:
1366 repo.dirstate.add(f)
1375 repo.dirstate.add(f)
1367 repo.dirstate.copy(f0, f)
1376 repo.dirstate.copy(f0, f)
1368 else:
1377 else:
1369 repo.dirstate.normal(f)
1378 repo.dirstate.normal(f)
1370
1379
1371 def update(repo, node, branchmerge, force, ancestor=None,
1380 def update(repo, node, branchmerge, force, ancestor=None,
1372 mergeancestor=False, labels=None, matcher=None, mergeforce=False):
1381 mergeancestor=False, labels=None, matcher=None, mergeforce=False):
1373 """
1382 """
1374 Perform a merge between the working directory and the given node
1383 Perform a merge between the working directory and the given node
1375
1384
1376 node = the node to update to, or None if unspecified
1385 node = the node to update to, or None if unspecified
1377 branchmerge = whether to merge between branches
1386 branchmerge = whether to merge between branches
1378 force = whether to force branch merging or file overwriting
1387 force = whether to force branch merging or file overwriting
1379 matcher = a matcher to filter file lists (dirstate not updated)
1388 matcher = a matcher to filter file lists (dirstate not updated)
1380 mergeancestor = whether it is merging with an ancestor. If true,
1389 mergeancestor = whether it is merging with an ancestor. If true,
1381 we should accept the incoming changes for any prompts that occur.
1390 we should accept the incoming changes for any prompts that occur.
1382 If false, merging with an ancestor (fast-forward) is only allowed
1391 If false, merging with an ancestor (fast-forward) is only allowed
1383 between different named branches. This flag is used by rebase extension
1392 between different named branches. This flag is used by rebase extension
1384 as a temporary fix and should be avoided in general.
1393 as a temporary fix and should be avoided in general.
1385 labels = labels to use for base, local and other
1394 labels = labels to use for base, local and other
1386 mergeforce = whether the merge was run with 'merge --force' (deprecated): if
1395 mergeforce = whether the merge was run with 'merge --force' (deprecated): if
1387 this is True, then 'force' should be True as well.
1396 this is True, then 'force' should be True as well.
1388
1397
1389 The table below shows all the behaviors of the update command
1398 The table below shows all the behaviors of the update command
1390 given the -c and -C or no options, whether the working directory
1399 given the -c and -C or no options, whether the working directory
1391 is dirty, whether a revision is specified, and the relationship of
1400 is dirty, whether a revision is specified, and the relationship of
1392 the parent rev to the target rev (linear, on the same named
1401 the parent rev to the target rev (linear, on the same named
1393 branch, or on another named branch).
1402 branch, or on another named branch).
1394
1403
1395 This logic is tested by test-update-branches.t.
1404 This logic is tested by test-update-branches.t.
1396
1405
1397 -c -C dirty rev | linear same cross
1406 -c -C dirty rev | linear same cross
1398 n n n n | ok (1) x
1407 n n n n | ok (1) x
1399 n n n y | ok ok ok
1408 n n n y | ok ok ok
1400 n n y n | merge (2) (2)
1409 n n y n | merge (2) (2)
1401 n n y y | merge (3) (3)
1410 n n y y | merge (3) (3)
1402 n y * * | discard discard discard
1411 n y * * | discard discard discard
1403 y n y * | (4) (4) (4)
1412 y n y * | (4) (4) (4)
1404 y n n * | ok ok ok
1413 y n n * | ok ok ok
1405 y y * * | (5) (5) (5)
1414 y y * * | (5) (5) (5)
1406
1415
1407 x = can't happen
1416 x = can't happen
1408 * = don't-care
1417 * = don't-care
1409 1 = abort: not a linear update (merge or update --check to force update)
1418 1 = abort: not a linear update (merge or update --check to force update)
1410 2 = abort: uncommitted changes (commit and merge, or update --clean to
1419 2 = abort: uncommitted changes (commit and merge, or update --clean to
1411 discard changes)
1420 discard changes)
1412 3 = abort: uncommitted changes (commit or update --clean to discard changes)
1421 3 = abort: uncommitted changes (commit or update --clean to discard changes)
1413 4 = abort: uncommitted changes (checked in commands.py)
1422 4 = abort: uncommitted changes (checked in commands.py)
1414 5 = incompatible options (checked in commands.py)
1423 5 = incompatible options (checked in commands.py)
1415
1424
1416 Return the same tuple as applyupdates().
1425 Return the same tuple as applyupdates().
1417 """
1426 """
1418
1427
1419 onode = node
1428 onode = node
1420 # If we're doing a partial update, we need to skip updating
1429 # If we're doing a partial update, we need to skip updating
1421 # the dirstate, so make a note of any partial-ness to the
1430 # the dirstate, so make a note of any partial-ness to the
1422 # update here.
1431 # update here.
1423 if matcher is None or matcher.always():
1432 if matcher is None or matcher.always():
1424 partial = False
1433 partial = False
1425 else:
1434 else:
1426 partial = True
1435 partial = True
1427 with repo.wlock():
1436 with repo.wlock():
1428 wc = repo[None]
1437 wc = repo[None]
1429 pl = wc.parents()
1438 pl = wc.parents()
1430 p1 = pl[0]
1439 p1 = pl[0]
1431 pas = [None]
1440 pas = [None]
1432 if ancestor is not None:
1441 if ancestor is not None:
1433 pas = [repo[ancestor]]
1442 pas = [repo[ancestor]]
1434
1443
1435 if node is None:
1444 if node is None:
1436 if (repo.ui.configbool('devel', 'all-warnings')
1445 if (repo.ui.configbool('devel', 'all-warnings')
1437 or repo.ui.configbool('devel', 'oldapi')):
1446 or repo.ui.configbool('devel', 'oldapi')):
1438 repo.ui.develwarn('update with no target')
1447 repo.ui.develwarn('update with no target')
1439 rev, _mark, _act = destutil.destupdate(repo)
1448 rev, _mark, _act = destutil.destupdate(repo)
1440 node = repo[rev].node()
1449 node = repo[rev].node()
1441
1450
1442 overwrite = force and not branchmerge
1451 overwrite = force and not branchmerge
1443
1452
1444 p2 = repo[node]
1453 p2 = repo[node]
1445 if pas[0] is None:
1454 if pas[0] is None:
1446 if repo.ui.configlist('merge', 'preferancestor', ['*']) == ['*']:
1455 if repo.ui.configlist('merge', 'preferancestor', ['*']) == ['*']:
1447 cahs = repo.changelog.commonancestorsheads(p1.node(), p2.node())
1456 cahs = repo.changelog.commonancestorsheads(p1.node(), p2.node())
1448 pas = [repo[anc] for anc in (sorted(cahs) or [nullid])]
1457 pas = [repo[anc] for anc in (sorted(cahs) or [nullid])]
1449 else:
1458 else:
1450 pas = [p1.ancestor(p2, warn=branchmerge)]
1459 pas = [p1.ancestor(p2, warn=branchmerge)]
1451
1460
1452 fp1, fp2, xp1, xp2 = p1.node(), p2.node(), str(p1), str(p2)
1461 fp1, fp2, xp1, xp2 = p1.node(), p2.node(), str(p1), str(p2)
1453
1462
1454 ### check phase
1463 ### check phase
1455 if not overwrite:
1464 if not overwrite:
1456 if len(pl) > 1:
1465 if len(pl) > 1:
1457 raise error.Abort(_("outstanding uncommitted merge"))
1466 raise error.Abort(_("outstanding uncommitted merge"))
1458 ms = mergestate.read(repo)
1467 ms = mergestate.read(repo)
1459 if list(ms.unresolved()):
1468 if list(ms.unresolved()):
1460 raise error.Abort(_("outstanding merge conflicts"))
1469 raise error.Abort(_("outstanding merge conflicts"))
1461 if branchmerge:
1470 if branchmerge:
1462 if pas == [p2]:
1471 if pas == [p2]:
1463 raise error.Abort(_("merging with a working directory ancestor"
1472 raise error.Abort(_("merging with a working directory ancestor"
1464 " has no effect"))
1473 " has no effect"))
1465 elif pas == [p1]:
1474 elif pas == [p1]:
1466 if not mergeancestor and p1.branch() == p2.branch():
1475 if not mergeancestor and p1.branch() == p2.branch():
1467 raise error.Abort(_("nothing to merge"),
1476 raise error.Abort(_("nothing to merge"),
1468 hint=_("use 'hg update' "
1477 hint=_("use 'hg update' "
1469 "or check 'hg heads'"))
1478 "or check 'hg heads'"))
1470 if not force and (wc.files() or wc.deleted()):
1479 if not force and (wc.files() or wc.deleted()):
1471 raise error.Abort(_("uncommitted changes"),
1480 raise error.Abort(_("uncommitted changes"),
1472 hint=_("use 'hg status' to list changes"))
1481 hint=_("use 'hg status' to list changes"))
1473 for s in sorted(wc.substate):
1482 for s in sorted(wc.substate):
1474 wc.sub(s).bailifchanged()
1483 wc.sub(s).bailifchanged()
1475
1484
1476 elif not overwrite:
1485 elif not overwrite:
1477 if p1 == p2: # no-op update
1486 if p1 == p2: # no-op update
1478 # call the hooks and exit early
1487 # call the hooks and exit early
1479 repo.hook('preupdate', throw=True, parent1=xp2, parent2='')
1488 repo.hook('preupdate', throw=True, parent1=xp2, parent2='')
1480 repo.hook('update', parent1=xp2, parent2='', error=0)
1489 repo.hook('update', parent1=xp2, parent2='', error=0)
1481 return 0, 0, 0, 0
1490 return 0, 0, 0, 0
1482
1491
1483 if pas not in ([p1], [p2]): # nonlinear
1492 if pas not in ([p1], [p2]): # nonlinear
1484 dirty = wc.dirty(missing=True)
1493 dirty = wc.dirty(missing=True)
1485 if dirty or onode is None:
1494 if dirty or onode is None:
1486 # Branching is a bit strange to ensure we do the minimal
1495 # Branching is a bit strange to ensure we do the minimal
1487 # amount of call to obsolete.background.
1496 # amount of call to obsolete.background.
1488 foreground = obsolete.foreground(repo, [p1.node()])
1497 foreground = obsolete.foreground(repo, [p1.node()])
1489 # note: the <node> variable contains a random identifier
1498 # note: the <node> variable contains a random identifier
1490 if repo[node].node() in foreground:
1499 if repo[node].node() in foreground:
1491 pas = [p1] # allow updating to successors
1500 pas = [p1] # allow updating to successors
1492 elif dirty:
1501 elif dirty:
1493 msg = _("uncommitted changes")
1502 msg = _("uncommitted changes")
1494 if onode is None:
1503 if onode is None:
1495 hint = _("commit and merge, or update --clean to"
1504 hint = _("commit and merge, or update --clean to"
1496 " discard changes")
1505 " discard changes")
1497 else:
1506 else:
1498 hint = _("commit or update --clean to discard"
1507 hint = _("commit or update --clean to discard"
1499 " changes")
1508 " changes")
1500 raise error.Abort(msg, hint=hint)
1509 raise error.Abort(msg, hint=hint)
1501 else: # node is none
1510 else: # node is none
1502 msg = _("not a linear update")
1511 msg = _("not a linear update")
1503 hint = _("merge or update --check to force update")
1512 hint = _("merge or update --check to force update")
1504 raise error.Abort(msg, hint=hint)
1513 raise error.Abort(msg, hint=hint)
1505 else:
1514 else:
1506 # Allow jumping branches if clean and specific rev given
1515 # Allow jumping branches if clean and specific rev given
1507 pas = [p1]
1516 pas = [p1]
1508
1517
1509 # deprecated config: merge.followcopies
1518 # deprecated config: merge.followcopies
1510 followcopies = False
1519 followcopies = False
1511 if overwrite:
1520 if overwrite:
1512 pas = [wc]
1521 pas = [wc]
1513 elif pas == [p2]: # backwards
1522 elif pas == [p2]: # backwards
1514 pas = [wc.p1()]
1523 pas = [wc.p1()]
1515 elif not branchmerge and not wc.dirty(missing=True):
1524 elif not branchmerge and not wc.dirty(missing=True):
1516 pass
1525 pass
1517 elif pas[0] and repo.ui.configbool('merge', 'followcopies', True):
1526 elif pas[0] and repo.ui.configbool('merge', 'followcopies', True):
1518 followcopies = True
1527 followcopies = True
1519
1528
1520 ### calculate phase
1529 ### calculate phase
1521 actionbyfile, diverge, renamedelete = calculateupdates(
1530 actionbyfile, diverge, renamedelete = calculateupdates(
1522 repo, wc, p2, pas, branchmerge, force, mergeancestor,
1531 repo, wc, p2, pas, branchmerge, force, mergeancestor,
1523 followcopies, matcher=matcher, mergeforce=mergeforce)
1532 followcopies, matcher=matcher, mergeforce=mergeforce)
1524
1533
1525 # Prompt and create actions. Most of this is in the resolve phase
1534 # Prompt and create actions. Most of this is in the resolve phase
1526 # already, but we can't handle .hgsubstate in filemerge or
1535 # already, but we can't handle .hgsubstate in filemerge or
1527 # subrepo.submerge yet so we have to keep prompting for it.
1536 # subrepo.submerge yet so we have to keep prompting for it.
1528 if '.hgsubstate' in actionbyfile:
1537 if '.hgsubstate' in actionbyfile:
1529 f = '.hgsubstate'
1538 f = '.hgsubstate'
1530 m, args, msg = actionbyfile[f]
1539 m, args, msg = actionbyfile[f]
1531 if m == 'cd':
1540 if m == 'cd':
1532 if repo.ui.promptchoice(
1541 if repo.ui.promptchoice(
1533 _("local changed %s which remote deleted\n"
1542 _("local changed %s which remote deleted\n"
1534 "use (c)hanged version or (d)elete?"
1543 "use (c)hanged version or (d)elete?"
1535 "$$ &Changed $$ &Delete") % f, 0):
1544 "$$ &Changed $$ &Delete") % f, 0):
1536 actionbyfile[f] = ('r', None, "prompt delete")
1545 actionbyfile[f] = ('r', None, "prompt delete")
1537 elif f in p1:
1546 elif f in p1:
1538 actionbyfile[f] = ('am', None, "prompt keep")
1547 actionbyfile[f] = ('am', None, "prompt keep")
1539 else:
1548 else:
1540 actionbyfile[f] = ('a', None, "prompt keep")
1549 actionbyfile[f] = ('a', None, "prompt keep")
1541 elif m == 'dc':
1550 elif m == 'dc':
1542 f1, f2, fa, move, anc = args
1551 f1, f2, fa, move, anc = args
1543 flags = p2[f2].flags()
1552 flags = p2[f2].flags()
1544 if repo.ui.promptchoice(
1553 if repo.ui.promptchoice(
1545 _("remote changed %s which local deleted\n"
1554 _("remote changed %s which local deleted\n"
1546 "use (c)hanged version or leave (d)eleted?"
1555 "use (c)hanged version or leave (d)eleted?"
1547 "$$ &Changed $$ &Deleted") % f, 0) == 0:
1556 "$$ &Changed $$ &Deleted") % f, 0) == 0:
1548 actionbyfile[f] = ('g', (flags, False), "prompt recreating")
1557 actionbyfile[f] = ('g', (flags, False), "prompt recreating")
1549 else:
1558 else:
1550 del actionbyfile[f]
1559 del actionbyfile[f]
1551
1560
1552 # Convert to dictionary-of-lists format
1561 # Convert to dictionary-of-lists format
1553 actions = dict((m, []) for m in 'a am f g cd dc r dm dg m e k'.split())
1562 actions = dict((m, []) for m in 'a am f g cd dc r dm dg m e k'.split())
1554 for f, (m, args, msg) in actionbyfile.iteritems():
1563 for f, (m, args, msg) in actionbyfile.iteritems():
1555 if m not in actions:
1564 if m not in actions:
1556 actions[m] = []
1565 actions[m] = []
1557 actions[m].append((f, args, msg))
1566 actions[m].append((f, args, msg))
1558
1567
1559 if not util.checkcase(repo.path):
1568 if not util.checkcase(repo.path):
1560 # check collision between files only in p2 for clean update
1569 # check collision between files only in p2 for clean update
1561 if (not branchmerge and
1570 if (not branchmerge and
1562 (force or not wc.dirty(missing=True, branch=False))):
1571 (force or not wc.dirty(missing=True, branch=False))):
1563 _checkcollision(repo, p2.manifest(), None)
1572 _checkcollision(repo, p2.manifest(), None)
1564 else:
1573 else:
1565 _checkcollision(repo, wc.manifest(), actions)
1574 _checkcollision(repo, wc.manifest(), actions)
1566
1575
1567 # divergent renames
1576 # divergent renames
1568 for f, fl in sorted(diverge.iteritems()):
1577 for f, fl in sorted(diverge.iteritems()):
1569 repo.ui.warn(_("note: possible conflict - %s was renamed "
1578 repo.ui.warn(_("note: possible conflict - %s was renamed "
1570 "multiple times to:\n") % f)
1579 "multiple times to:\n") % f)
1571 for nf in fl:
1580 for nf in fl:
1572 repo.ui.warn(" %s\n" % nf)
1581 repo.ui.warn(" %s\n" % nf)
1573
1582
1574 # rename and delete
1583 # rename and delete
1575 for f, fl in sorted(renamedelete.iteritems()):
1584 for f, fl in sorted(renamedelete.iteritems()):
1576 repo.ui.warn(_("note: possible conflict - %s was deleted "
1585 repo.ui.warn(_("note: possible conflict - %s was deleted "
1577 "and renamed to:\n") % f)
1586 "and renamed to:\n") % f)
1578 for nf in fl:
1587 for nf in fl:
1579 repo.ui.warn(" %s\n" % nf)
1588 repo.ui.warn(" %s\n" % nf)
1580
1589
1581 ### apply phase
1590 ### apply phase
1582 if not branchmerge: # just jump to the new rev
1591 if not branchmerge: # just jump to the new rev
1583 fp1, fp2, xp1, xp2 = fp2, nullid, xp2, ''
1592 fp1, fp2, xp1, xp2 = fp2, nullid, xp2, ''
1584 if not partial:
1593 if not partial:
1585 repo.hook('preupdate', throw=True, parent1=xp1, parent2=xp2)
1594 repo.hook('preupdate', throw=True, parent1=xp1, parent2=xp2)
1586 # note that we're in the middle of an update
1595 # note that we're in the middle of an update
1587 repo.vfs.write('updatestate', p2.hex())
1596 repo.vfs.write('updatestate', p2.hex())
1588
1597
1589 stats = applyupdates(repo, actions, wc, p2, overwrite, labels=labels)
1598 stats = applyupdates(repo, actions, wc, p2, overwrite, labels=labels)
1590
1599
1591 if not partial:
1600 if not partial:
1592 repo.dirstate.beginparentchange()
1601 repo.dirstate.beginparentchange()
1593 repo.setparents(fp1, fp2)
1602 repo.setparents(fp1, fp2)
1594 recordupdates(repo, actions, branchmerge)
1603 recordupdates(repo, actions, branchmerge)
1595 # update completed, clear state
1604 # update completed, clear state
1596 util.unlink(repo.join('updatestate'))
1605 util.unlink(repo.join('updatestate'))
1597
1606
1598 if not branchmerge:
1607 if not branchmerge:
1599 repo.dirstate.setbranch(p2.branch())
1608 repo.dirstate.setbranch(p2.branch())
1600 repo.dirstate.endparentchange()
1609 repo.dirstate.endparentchange()
1601
1610
1602 if not partial:
1611 if not partial:
1603 repo.hook('update', parent1=xp1, parent2=xp2, error=stats[3])
1612 repo.hook('update', parent1=xp1, parent2=xp2, error=stats[3])
1604 return stats
1613 return stats
1605
1614
1606 def graft(repo, ctx, pctx, labels, keepparent=False):
1615 def graft(repo, ctx, pctx, labels, keepparent=False):
1607 """Do a graft-like merge.
1616 """Do a graft-like merge.
1608
1617
1609 This is a merge where the merge ancestor is chosen such that one
1618 This is a merge where the merge ancestor is chosen such that one
1610 or more changesets are grafted onto the current changeset. In
1619 or more changesets are grafted onto the current changeset. In
1611 addition to the merge, this fixes up the dirstate to include only
1620 addition to the merge, this fixes up the dirstate to include only
1612 a single parent (if keepparent is False) and tries to duplicate any
1621 a single parent (if keepparent is False) and tries to duplicate any
1613 renames/copies appropriately.
1622 renames/copies appropriately.
1614
1623
1615 ctx - changeset to rebase
1624 ctx - changeset to rebase
1616 pctx - merge base, usually ctx.p1()
1625 pctx - merge base, usually ctx.p1()
1617 labels - merge labels eg ['local', 'graft']
1626 labels - merge labels eg ['local', 'graft']
1618 keepparent - keep second parent if any
1627 keepparent - keep second parent if any
1619
1628
1620 """
1629 """
1621 # If we're grafting a descendant onto an ancestor, be sure to pass
1630 # If we're grafting a descendant onto an ancestor, be sure to pass
1622 # mergeancestor=True to update. This does two things: 1) allows the merge if
1631 # mergeancestor=True to update. This does two things: 1) allows the merge if
1623 # the destination is the same as the parent of the ctx (so we can use graft
1632 # the destination is the same as the parent of the ctx (so we can use graft
1624 # to copy commits), and 2) informs update that the incoming changes are
1633 # to copy commits), and 2) informs update that the incoming changes are
1625 # newer than the destination so it doesn't prompt about "remote changed foo
1634 # newer than the destination so it doesn't prompt about "remote changed foo
1626 # which local deleted".
1635 # which local deleted".
1627 mergeancestor = repo.changelog.isancestor(repo['.'].node(), ctx.node())
1636 mergeancestor = repo.changelog.isancestor(repo['.'].node(), ctx.node())
1628
1637
1629 stats = update(repo, ctx.node(), True, True, pctx.node(),
1638 stats = update(repo, ctx.node(), True, True, pctx.node(),
1630 mergeancestor=mergeancestor, labels=labels)
1639 mergeancestor=mergeancestor, labels=labels)
1631
1640
1632 pother = nullid
1641 pother = nullid
1633 parents = ctx.parents()
1642 parents = ctx.parents()
1634 if keepparent and len(parents) == 2 and pctx in parents:
1643 if keepparent and len(parents) == 2 and pctx in parents:
1635 parents.remove(pctx)
1644 parents.remove(pctx)
1636 pother = parents[0].node()
1645 pother = parents[0].node()
1637
1646
1638 repo.dirstate.beginparentchange()
1647 repo.dirstate.beginparentchange()
1639 repo.setparents(repo['.'].node(), pother)
1648 repo.setparents(repo['.'].node(), pother)
1640 repo.dirstate.write(repo.currenttransaction())
1649 repo.dirstate.write(repo.currenttransaction())
1641 # fix up dirstate for copies and renames
1650 # fix up dirstate for copies and renames
1642 copies.duplicatecopies(repo, ctx.rev(), pctx.rev())
1651 copies.duplicatecopies(repo, ctx.rev(), pctx.rev())
1643 repo.dirstate.endparentchange()
1652 repo.dirstate.endparentchange()
1644 return stats
1653 return stats
@@ -1,844 +1,844 b''
1 $ cat >> $HGRCPATH <<EOF
1 $ cat >> $HGRCPATH <<EOF
2 > [extdiff]
2 > [extdiff]
3 > # for portability:
3 > # for portability:
4 > pdiff = sh "$RUNTESTDIR/pdiff"
4 > pdiff = sh "$RUNTESTDIR/pdiff"
5 > EOF
5 > EOF
6
6
7 Create a repo with some stuff in it:
7 Create a repo with some stuff in it:
8
8
9 $ hg init a
9 $ hg init a
10 $ cd a
10 $ cd a
11 $ echo a > a
11 $ echo a > a
12 $ echo a > d
12 $ echo a > d
13 $ echo a > e
13 $ echo a > e
14 $ hg ci -qAm0
14 $ hg ci -qAm0
15 $ echo b > a
15 $ echo b > a
16 $ hg ci -m1 -u bar
16 $ hg ci -m1 -u bar
17 $ hg mv a b
17 $ hg mv a b
18 $ hg ci -m2
18 $ hg ci -m2
19 $ hg cp b c
19 $ hg cp b c
20 $ hg ci -m3 -u baz
20 $ hg ci -m3 -u baz
21 $ echo b > d
21 $ echo b > d
22 $ echo f > e
22 $ echo f > e
23 $ hg ci -m4
23 $ hg ci -m4
24 $ hg up -q 3
24 $ hg up -q 3
25 $ echo b > e
25 $ echo b > e
26 $ hg branch -q stable
26 $ hg branch -q stable
27 $ hg ci -m5
27 $ hg ci -m5
28 $ hg merge -q default --tool internal:local
28 $ hg merge -q default --tool internal:local
29 $ hg branch -q default
29 $ hg branch -q default
30 $ hg ci -m6
30 $ hg ci -m6
31 $ hg phase --public 3
31 $ hg phase --public 3
32 $ hg phase --force --secret 6
32 $ hg phase --force --secret 6
33
33
34 $ hg log -G --template '{author}@{rev}.{phase}: {desc}\n'
34 $ hg log -G --template '{author}@{rev}.{phase}: {desc}\n'
35 @ test@6.secret: 6
35 @ test@6.secret: 6
36 |\
36 |\
37 | o test@5.draft: 5
37 | o test@5.draft: 5
38 | |
38 | |
39 o | test@4.draft: 4
39 o | test@4.draft: 4
40 |/
40 |/
41 o baz@3.public: 3
41 o baz@3.public: 3
42 |
42 |
43 o test@2.public: 2
43 o test@2.public: 2
44 |
44 |
45 o bar@1.public: 1
45 o bar@1.public: 1
46 |
46 |
47 o test@0.public: 0
47 o test@0.public: 0
48
48
49 Can't continue without starting:
49 Can't continue without starting:
50
50
51 $ hg rm -q e
51 $ hg rm -q e
52 $ hg graft --continue
52 $ hg graft --continue
53 abort: no graft in progress
53 abort: no graft in progress
54 [255]
54 [255]
55 $ hg revert -r . -q e
55 $ hg revert -r . -q e
56
56
57 Need to specify a rev:
57 Need to specify a rev:
58
58
59 $ hg graft
59 $ hg graft
60 abort: no revisions specified
60 abort: no revisions specified
61 [255]
61 [255]
62
62
63 Can't graft ancestor:
63 Can't graft ancestor:
64
64
65 $ hg graft 1 2
65 $ hg graft 1 2
66 skipping ancestor revision 1:5d205f8b35b6
66 skipping ancestor revision 1:5d205f8b35b6
67 skipping ancestor revision 2:5c095ad7e90f
67 skipping ancestor revision 2:5c095ad7e90f
68 [255]
68 [255]
69
69
70 Specify revisions with -r:
70 Specify revisions with -r:
71
71
72 $ hg graft -r 1 -r 2
72 $ hg graft -r 1 -r 2
73 skipping ancestor revision 1:5d205f8b35b6
73 skipping ancestor revision 1:5d205f8b35b6
74 skipping ancestor revision 2:5c095ad7e90f
74 skipping ancestor revision 2:5c095ad7e90f
75 [255]
75 [255]
76
76
77 $ hg graft -r 1 2
77 $ hg graft -r 1 2
78 warning: inconsistent use of --rev might give unexpected revision ordering!
78 warning: inconsistent use of --rev might give unexpected revision ordering!
79 skipping ancestor revision 2:5c095ad7e90f
79 skipping ancestor revision 2:5c095ad7e90f
80 skipping ancestor revision 1:5d205f8b35b6
80 skipping ancestor revision 1:5d205f8b35b6
81 [255]
81 [255]
82
82
83 Can't graft with dirty wd:
83 Can't graft with dirty wd:
84
84
85 $ hg up -q 0
85 $ hg up -q 0
86 $ echo foo > a
86 $ echo foo > a
87 $ hg graft 1
87 $ hg graft 1
88 abort: uncommitted changes
88 abort: uncommitted changes
89 [255]
89 [255]
90 $ hg revert a
90 $ hg revert a
91
91
92 Graft a rename:
92 Graft a rename:
93 (this also tests that editor is invoked if '--edit' is specified)
93 (this also tests that editor is invoked if '--edit' is specified)
94
94
95 $ hg status --rev "2^1" --rev 2
95 $ hg status --rev "2^1" --rev 2
96 A b
96 A b
97 R a
97 R a
98 $ HGEDITOR=cat hg graft 2 -u foo --edit
98 $ HGEDITOR=cat hg graft 2 -u foo --edit
99 grafting 2:5c095ad7e90f "2"
99 grafting 2:5c095ad7e90f "2"
100 merging a and b to b
100 merging a and b to b
101 2
101 2
102
102
103
103
104 HG: Enter commit message. Lines beginning with 'HG:' are removed.
104 HG: Enter commit message. Lines beginning with 'HG:' are removed.
105 HG: Leave message empty to abort commit.
105 HG: Leave message empty to abort commit.
106 HG: --
106 HG: --
107 HG: user: foo
107 HG: user: foo
108 HG: branch 'default'
108 HG: branch 'default'
109 HG: added b
109 HG: added b
110 HG: removed a
110 HG: removed a
111 $ hg export tip --git
111 $ hg export tip --git
112 # HG changeset patch
112 # HG changeset patch
113 # User foo
113 # User foo
114 # Date 0 0
114 # Date 0 0
115 # Thu Jan 01 00:00:00 1970 +0000
115 # Thu Jan 01 00:00:00 1970 +0000
116 # Node ID ef0ef43d49e79e81ddafdc7997401ba0041efc82
116 # Node ID ef0ef43d49e79e81ddafdc7997401ba0041efc82
117 # Parent 68795b066622ca79a25816a662041d8f78f3cd9e
117 # Parent 68795b066622ca79a25816a662041d8f78f3cd9e
118 2
118 2
119
119
120 diff --git a/a b/b
120 diff --git a/a b/b
121 rename from a
121 rename from a
122 rename to b
122 rename to b
123
123
124 Look for extra:source
124 Look for extra:source
125
125
126 $ hg log --debug -r tip
126 $ hg log --debug -r tip
127 changeset: 7:ef0ef43d49e79e81ddafdc7997401ba0041efc82
127 changeset: 7:ef0ef43d49e79e81ddafdc7997401ba0041efc82
128 tag: tip
128 tag: tip
129 phase: draft
129 phase: draft
130 parent: 0:68795b066622ca79a25816a662041d8f78f3cd9e
130 parent: 0:68795b066622ca79a25816a662041d8f78f3cd9e
131 parent: -1:0000000000000000000000000000000000000000
131 parent: -1:0000000000000000000000000000000000000000
132 manifest: 7:e59b6b228f9cbf9903d5e9abf996e083a1f533eb
132 manifest: 7:e59b6b228f9cbf9903d5e9abf996e083a1f533eb
133 user: foo
133 user: foo
134 date: Thu Jan 01 00:00:00 1970 +0000
134 date: Thu Jan 01 00:00:00 1970 +0000
135 files+: b
135 files+: b
136 files-: a
136 files-: a
137 extra: branch=default
137 extra: branch=default
138 extra: source=5c095ad7e90f871700f02dd1fa5012cb4498a2d4
138 extra: source=5c095ad7e90f871700f02dd1fa5012cb4498a2d4
139 description:
139 description:
140 2
140 2
141
141
142
142
143
143
144 Graft out of order, skipping a merge and a duplicate
144 Graft out of order, skipping a merge and a duplicate
145 (this also tests that editor is not invoked if '--edit' is not specified)
145 (this also tests that editor is not invoked if '--edit' is not specified)
146
146
147 $ hg graft 1 5 4 3 'merge()' 2 -n
147 $ hg graft 1 5 4 3 'merge()' 2 -n
148 skipping ungraftable merge revision 6
148 skipping ungraftable merge revision 6
149 skipping revision 2:5c095ad7e90f (already grafted to 7:ef0ef43d49e7)
149 skipping revision 2:5c095ad7e90f (already grafted to 7:ef0ef43d49e7)
150 grafting 1:5d205f8b35b6 "1"
150 grafting 1:5d205f8b35b6 "1"
151 grafting 5:97f8bfe72746 "5"
151 grafting 5:97f8bfe72746 "5"
152 grafting 4:9c233e8e184d "4"
152 grafting 4:9c233e8e184d "4"
153 grafting 3:4c60f11aa304 "3"
153 grafting 3:4c60f11aa304 "3"
154
154
155 $ HGEDITOR=cat hg graft 1 5 'merge()' 2 --debug
155 $ HGEDITOR=cat hg graft 1 5 'merge()' 2 --debug
156 skipping ungraftable merge revision 6
156 skipping ungraftable merge revision 6
157 scanning for duplicate grafts
157 scanning for duplicate grafts
158 skipping revision 2:5c095ad7e90f (already grafted to 7:ef0ef43d49e7)
158 skipping revision 2:5c095ad7e90f (already grafted to 7:ef0ef43d49e7)
159 grafting 1:5d205f8b35b6 "1"
159 grafting 1:5d205f8b35b6 "1"
160 searching for copies back to rev 1
160 searching for copies back to rev 1
161 unmatched files in local:
161 unmatched files in local:
162 b
162 b
163 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
163 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
164 src: 'a' -> dst: 'b' *
164 src: 'a' -> dst: 'b' *
165 checking for directory renames
165 checking for directory renames
166 resolving manifests
166 resolving manifests
167 branchmerge: True, force: True, partial: False
167 branchmerge: True, force: True, partial: False
168 ancestor: 68795b066622, local: ef0ef43d49e7+, remote: 5d205f8b35b6
168 ancestor: 68795b066622, local: ef0ef43d49e7+, remote: 5d205f8b35b6
169 preserving b for resolve of b
169 preserving b for resolve of b
170 starting 4 threads for background file closing (?)
170 starting 4 threads for background file closing (?)
171 b: local copied/moved from a -> m (premerge)
171 b: local copied/moved from a -> m (premerge)
172 picked tool ':merge' for b (binary False symlink False changedelete False)
172 picked tool ':merge' for b (binary False symlink False changedelete False)
173 merging b and a to b
173 merging b and a to b
174 my b@ef0ef43d49e7+ other a@5d205f8b35b6 ancestor a@68795b066622
174 my b@ef0ef43d49e7+ other a@5d205f8b35b6 ancestor a@68795b066622
175 premerge successful
175 premerge successful
176 committing files:
176 committing files:
177 b
177 b
178 committing manifest
178 committing manifest
179 committing changelog
179 committing changelog
180 grafting 5:97f8bfe72746 "5"
180 grafting 5:97f8bfe72746 "5"
181 searching for copies back to rev 1
181 searching for copies back to rev 1
182 resolving manifests
182 resolving manifests
183 branchmerge: True, force: True, partial: False
183 branchmerge: True, force: True, partial: False
184 ancestor: 4c60f11aa304, local: 6b9e5368ca4e+, remote: 97f8bfe72746
184 ancestor: 4c60f11aa304, local: 6b9e5368ca4e+, remote: 97f8bfe72746
185 e: remote is newer -> g
185 e: remote is newer -> g
186 getting e
186 getting e
187 b: remote unchanged -> k
187 b: remote unchanged -> k
188 committing files:
188 committing files:
189 e
189 e
190 committing manifest
190 committing manifest
191 committing changelog
191 committing changelog
192 $ HGEDITOR=cat hg graft 4 3 --log --debug
192 $ HGEDITOR=cat hg graft 4 3 --log --debug
193 scanning for duplicate grafts
193 scanning for duplicate grafts
194 grafting 4:9c233e8e184d "4"
194 grafting 4:9c233e8e184d "4"
195 searching for copies back to rev 1
195 searching for copies back to rev 1
196 resolving manifests
196 resolving manifests
197 branchmerge: True, force: True, partial: False
197 branchmerge: True, force: True, partial: False
198 ancestor: 4c60f11aa304, local: 1905859650ec+, remote: 9c233e8e184d
198 ancestor: 4c60f11aa304, local: 1905859650ec+, remote: 9c233e8e184d
199 preserving e for resolve of e
199 preserving e for resolve of e
200 d: remote is newer -> g
200 d: remote is newer -> g
201 getting d
201 getting d
202 b: remote unchanged -> k
202 b: remote unchanged -> k
203 e: versions differ -> m (premerge)
203 e: versions differ -> m (premerge)
204 picked tool ':merge' for e (binary False symlink False changedelete False)
204 picked tool ':merge' for e (binary False symlink False changedelete False)
205 merging e
205 merging e
206 my e@1905859650ec+ other e@9c233e8e184d ancestor e@4c60f11aa304
206 my e@1905859650ec+ other e@9c233e8e184d ancestor e@4c60f11aa304
207 e: versions differ -> m (merge)
207 e: versions differ -> m (merge)
208 picked tool ':merge' for e (binary False symlink False changedelete False)
208 picked tool ':merge' for e (binary False symlink False changedelete False)
209 my e@1905859650ec+ other e@9c233e8e184d ancestor e@4c60f11aa304
209 my e@1905859650ec+ other e@9c233e8e184d ancestor e@4c60f11aa304
210 warning: conflicts while merging e! (edit, then use 'hg resolve --mark')
210 warning: conflicts while merging e! (edit, then use 'hg resolve --mark')
211 abort: unresolved conflicts, can't continue
211 abort: unresolved conflicts, can't continue
212 (use hg resolve and hg graft --continue --log)
212 (use hg resolve and hg graft --continue --log)
213 [255]
213 [255]
214
214
215 Summary should mention graft:
215 Summary should mention graft:
216
216
217 $ hg summary |grep graft
217 $ hg summary |grep graft
218 commit: 2 modified, 2 unknown, 1 unresolved (graft in progress)
218 commit: 2 modified, 2 unknown, 1 unresolved (graft in progress)
219
219
220 Commit while interrupted should fail:
220 Commit while interrupted should fail:
221
221
222 $ hg ci -m 'commit interrupted graft'
222 $ hg ci -m 'commit interrupted graft'
223 abort: graft in progress
223 abort: graft in progress
224 (use 'hg graft --continue' or 'hg update' to abort)
224 (use 'hg graft --continue' or 'hg update' to abort)
225 [255]
225 [255]
226
226
227 Abort the graft and try committing:
227 Abort the graft and try committing:
228
228
229 $ hg up -C .
229 $ hg up -C .
230 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
230 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
231 $ echo c >> e
231 $ echo c >> e
232 $ hg ci -mtest
232 $ hg ci -mtest
233
233
234 $ hg strip . --config extensions.strip=
234 $ hg strip . --config extensions.strip=
235 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
235 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
236 saved backup bundle to $TESTTMP/a/.hg/strip-backup/*-backup.hg (glob)
236 saved backup bundle to $TESTTMP/a/.hg/strip-backup/*-backup.hg (glob)
237
237
238 Graft again:
238 Graft again:
239
239
240 $ hg graft 1 5 4 3 'merge()' 2
240 $ hg graft 1 5 4 3 'merge()' 2
241 skipping ungraftable merge revision 6
241 skipping ungraftable merge revision 6
242 skipping revision 2:5c095ad7e90f (already grafted to 7:ef0ef43d49e7)
242 skipping revision 2:5c095ad7e90f (already grafted to 7:ef0ef43d49e7)
243 skipping revision 1:5d205f8b35b6 (already grafted to 8:6b9e5368ca4e)
243 skipping revision 1:5d205f8b35b6 (already grafted to 8:6b9e5368ca4e)
244 skipping revision 5:97f8bfe72746 (already grafted to 9:1905859650ec)
244 skipping revision 5:97f8bfe72746 (already grafted to 9:1905859650ec)
245 grafting 4:9c233e8e184d "4"
245 grafting 4:9c233e8e184d "4"
246 merging e
246 merging e
247 warning: conflicts while merging e! (edit, then use 'hg resolve --mark')
247 warning: conflicts while merging e! (edit, then use 'hg resolve --mark')
248 abort: unresolved conflicts, can't continue
248 abort: unresolved conflicts, can't continue
249 (use hg resolve and hg graft --continue)
249 (use hg resolve and hg graft --continue)
250 [255]
250 [255]
251
251
252 Continue without resolve should fail:
252 Continue without resolve should fail:
253
253
254 $ hg graft -c
254 $ hg graft -c
255 grafting 4:9c233e8e184d "4"
255 grafting 4:9c233e8e184d "4"
256 abort: unresolved merge conflicts (see "hg help resolve")
256 abort: unresolved merge conflicts (see "hg help resolve")
257 [255]
257 [255]
258
258
259 Fix up:
259 Fix up:
260
260
261 $ echo b > e
261 $ echo b > e
262 $ hg resolve -m e
262 $ hg resolve -m e
263 (no more unresolved files)
263 (no more unresolved files)
264 continue: hg graft --continue
264 continue: hg graft --continue
265
265
266 Continue with a revision should fail:
266 Continue with a revision should fail:
267
267
268 $ hg graft -c 6
268 $ hg graft -c 6
269 abort: can't specify --continue and revisions
269 abort: can't specify --continue and revisions
270 [255]
270 [255]
271
271
272 $ hg graft -c -r 6
272 $ hg graft -c -r 6
273 abort: can't specify --continue and revisions
273 abort: can't specify --continue and revisions
274 [255]
274 [255]
275
275
276 Continue for real, clobber usernames
276 Continue for real, clobber usernames
277
277
278 $ hg graft -c -U
278 $ hg graft -c -U
279 grafting 4:9c233e8e184d "4"
279 grafting 4:9c233e8e184d "4"
280 grafting 3:4c60f11aa304 "3"
280 grafting 3:4c60f11aa304 "3"
281
281
282 Compare with original:
282 Compare with original:
283
283
284 $ hg diff -r 6
284 $ hg diff -r 6
285 $ hg status --rev 0:. -C
285 $ hg status --rev 0:. -C
286 M d
286 M d
287 M e
287 M e
288 A b
288 A b
289 a
289 a
290 A c
290 A c
291 a
291 a
292 R a
292 R a
293
293
294 View graph:
294 View graph:
295
295
296 $ hg log -G --template '{author}@{rev}.{phase}: {desc}\n'
296 $ hg log -G --template '{author}@{rev}.{phase}: {desc}\n'
297 @ test@11.draft: 3
297 @ test@11.draft: 3
298 |
298 |
299 o test@10.draft: 4
299 o test@10.draft: 4
300 |
300 |
301 o test@9.draft: 5
301 o test@9.draft: 5
302 |
302 |
303 o bar@8.draft: 1
303 o bar@8.draft: 1
304 |
304 |
305 o foo@7.draft: 2
305 o foo@7.draft: 2
306 |
306 |
307 | o test@6.secret: 6
307 | o test@6.secret: 6
308 | |\
308 | |\
309 | | o test@5.draft: 5
309 | | o test@5.draft: 5
310 | | |
310 | | |
311 | o | test@4.draft: 4
311 | o | test@4.draft: 4
312 | |/
312 | |/
313 | o baz@3.public: 3
313 | o baz@3.public: 3
314 | |
314 | |
315 | o test@2.public: 2
315 | o test@2.public: 2
316 | |
316 | |
317 | o bar@1.public: 1
317 | o bar@1.public: 1
318 |/
318 |/
319 o test@0.public: 0
319 o test@0.public: 0
320
320
321 Graft again onto another branch should preserve the original source
321 Graft again onto another branch should preserve the original source
322 $ hg up -q 0
322 $ hg up -q 0
323 $ echo 'g'>g
323 $ echo 'g'>g
324 $ hg add g
324 $ hg add g
325 $ hg ci -m 7
325 $ hg ci -m 7
326 created new head
326 created new head
327 $ hg graft 7
327 $ hg graft 7
328 grafting 7:ef0ef43d49e7 "2"
328 grafting 7:ef0ef43d49e7 "2"
329
329
330 $ hg log -r 7 --template '{rev}:{node}\n'
330 $ hg log -r 7 --template '{rev}:{node}\n'
331 7:ef0ef43d49e79e81ddafdc7997401ba0041efc82
331 7:ef0ef43d49e79e81ddafdc7997401ba0041efc82
332 $ hg log -r 2 --template '{rev}:{node}\n'
332 $ hg log -r 2 --template '{rev}:{node}\n'
333 2:5c095ad7e90f871700f02dd1fa5012cb4498a2d4
333 2:5c095ad7e90f871700f02dd1fa5012cb4498a2d4
334
334
335 $ hg log --debug -r tip
335 $ hg log --debug -r tip
336 changeset: 13:7a4785234d87ec1aa420ed6b11afe40fa73e12a9
336 changeset: 13:7a4785234d87ec1aa420ed6b11afe40fa73e12a9
337 tag: tip
337 tag: tip
338 phase: draft
338 phase: draft
339 parent: 12:b592ea63bb0c19a6c5c44685ee29a2284f9f1b8f
339 parent: 12:b592ea63bb0c19a6c5c44685ee29a2284f9f1b8f
340 parent: -1:0000000000000000000000000000000000000000
340 parent: -1:0000000000000000000000000000000000000000
341 manifest: 13:dc313617b8c32457c0d589e0dbbedfe71f3cd637
341 manifest: 13:dc313617b8c32457c0d589e0dbbedfe71f3cd637
342 user: foo
342 user: foo
343 date: Thu Jan 01 00:00:00 1970 +0000
343 date: Thu Jan 01 00:00:00 1970 +0000
344 files+: b
344 files+: b
345 files-: a
345 files-: a
346 extra: branch=default
346 extra: branch=default
347 extra: intermediate-source=ef0ef43d49e79e81ddafdc7997401ba0041efc82
347 extra: intermediate-source=ef0ef43d49e79e81ddafdc7997401ba0041efc82
348 extra: source=5c095ad7e90f871700f02dd1fa5012cb4498a2d4
348 extra: source=5c095ad7e90f871700f02dd1fa5012cb4498a2d4
349 description:
349 description:
350 2
350 2
351
351
352
352
353 Disallow grafting an already grafted cset onto its original branch
353 Disallow grafting an already grafted cset onto its original branch
354 $ hg up -q 6
354 $ hg up -q 6
355 $ hg graft 7
355 $ hg graft 7
356 skipping already grafted revision 7:ef0ef43d49e7 (was grafted from 2:5c095ad7e90f)
356 skipping already grafted revision 7:ef0ef43d49e7 (was grafted from 2:5c095ad7e90f)
357 [255]
357 [255]
358
358
359 $ hg pdiff --config extensions.extdiff= --patch -r 2 -r 13
359 $ hg pdiff --config extensions.extdiff= --patch -r 2 -r 13
360 --- */hg-5c095ad7e90f.patch * (glob)
360 --- */hg-5c095ad7e90f.patch * (glob)
361 +++ */hg-7a4785234d87.patch * (glob)
361 +++ */hg-7a4785234d87.patch * (glob)
362 @@ -1,18 +1,18 @@
362 @@ -1,18 +1,18 @@
363 # HG changeset patch
363 # HG changeset patch
364 -# User test
364 -# User test
365 +# User foo
365 +# User foo
366 # Date 0 0
366 # Date 0 0
367 # Thu Jan 01 00:00:00 1970 +0000
367 # Thu Jan 01 00:00:00 1970 +0000
368 -# Node ID 5c095ad7e90f871700f02dd1fa5012cb4498a2d4
368 -# Node ID 5c095ad7e90f871700f02dd1fa5012cb4498a2d4
369 -# Parent 5d205f8b35b66bc36375c9534ffd3237730e8f04
369 -# Parent 5d205f8b35b66bc36375c9534ffd3237730e8f04
370 +# Node ID 7a4785234d87ec1aa420ed6b11afe40fa73e12a9
370 +# Node ID 7a4785234d87ec1aa420ed6b11afe40fa73e12a9
371 +# Parent b592ea63bb0c19a6c5c44685ee29a2284f9f1b8f
371 +# Parent b592ea63bb0c19a6c5c44685ee29a2284f9f1b8f
372 2
372 2
373
373
374 -diff -r 5d205f8b35b6 -r 5c095ad7e90f a
374 -diff -r 5d205f8b35b6 -r 5c095ad7e90f a
375 +diff -r b592ea63bb0c -r 7a4785234d87 a
375 +diff -r b592ea63bb0c -r 7a4785234d87 a
376 --- a/a Thu Jan 01 00:00:00 1970 +0000
376 --- a/a Thu Jan 01 00:00:00 1970 +0000
377 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
377 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
378 @@ -1,1 +0,0 @@
378 @@ -1,1 +0,0 @@
379 --b
379 --b
380 -diff -r 5d205f8b35b6 -r 5c095ad7e90f b
380 -diff -r 5d205f8b35b6 -r 5c095ad7e90f b
381 +-a
381 +-a
382 +diff -r b592ea63bb0c -r 7a4785234d87 b
382 +diff -r b592ea63bb0c -r 7a4785234d87 b
383 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
383 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
384 +++ b/b Thu Jan 01 00:00:00 1970 +0000
384 +++ b/b Thu Jan 01 00:00:00 1970 +0000
385 @@ -0,0 +1,1 @@
385 @@ -0,0 +1,1 @@
386 -+b
386 -+b
387 ++a
387 ++a
388 [1]
388 [1]
389
389
390 $ hg pdiff --config extensions.extdiff= --patch -r 2 -r 13 -X .
390 $ hg pdiff --config extensions.extdiff= --patch -r 2 -r 13 -X .
391 --- */hg-5c095ad7e90f.patch * (glob)
391 --- */hg-5c095ad7e90f.patch * (glob)
392 +++ */hg-7a4785234d87.patch * (glob)
392 +++ */hg-7a4785234d87.patch * (glob)
393 @@ -1,8 +1,8 @@
393 @@ -1,8 +1,8 @@
394 # HG changeset patch
394 # HG changeset patch
395 -# User test
395 -# User test
396 +# User foo
396 +# User foo
397 # Date 0 0
397 # Date 0 0
398 # Thu Jan 01 00:00:00 1970 +0000
398 # Thu Jan 01 00:00:00 1970 +0000
399 -# Node ID 5c095ad7e90f871700f02dd1fa5012cb4498a2d4
399 -# Node ID 5c095ad7e90f871700f02dd1fa5012cb4498a2d4
400 -# Parent 5d205f8b35b66bc36375c9534ffd3237730e8f04
400 -# Parent 5d205f8b35b66bc36375c9534ffd3237730e8f04
401 +# Node ID 7a4785234d87ec1aa420ed6b11afe40fa73e12a9
401 +# Node ID 7a4785234d87ec1aa420ed6b11afe40fa73e12a9
402 +# Parent b592ea63bb0c19a6c5c44685ee29a2284f9f1b8f
402 +# Parent b592ea63bb0c19a6c5c44685ee29a2284f9f1b8f
403 2
403 2
404
404
405 [1]
405 [1]
406
406
407 Disallow grafting already grafted csets with the same origin onto each other
407 Disallow grafting already grafted csets with the same origin onto each other
408 $ hg up -q 13
408 $ hg up -q 13
409 $ hg graft 2
409 $ hg graft 2
410 skipping revision 2:5c095ad7e90f (already grafted to 13:7a4785234d87)
410 skipping revision 2:5c095ad7e90f (already grafted to 13:7a4785234d87)
411 [255]
411 [255]
412 $ hg graft 7
412 $ hg graft 7
413 skipping already grafted revision 7:ef0ef43d49e7 (13:7a4785234d87 also has origin 2:5c095ad7e90f)
413 skipping already grafted revision 7:ef0ef43d49e7 (13:7a4785234d87 also has origin 2:5c095ad7e90f)
414 [255]
414 [255]
415
415
416 $ hg up -q 7
416 $ hg up -q 7
417 $ hg graft 2
417 $ hg graft 2
418 skipping revision 2:5c095ad7e90f (already grafted to 7:ef0ef43d49e7)
418 skipping revision 2:5c095ad7e90f (already grafted to 7:ef0ef43d49e7)
419 [255]
419 [255]
420 $ hg graft tip
420 $ hg graft tip
421 skipping already grafted revision 13:7a4785234d87 (7:ef0ef43d49e7 also has origin 2:5c095ad7e90f)
421 skipping already grafted revision 13:7a4785234d87 (7:ef0ef43d49e7 also has origin 2:5c095ad7e90f)
422 [255]
422 [255]
423
423
424 Graft with --log
424 Graft with --log
425
425
426 $ hg up -Cq 1
426 $ hg up -Cq 1
427 $ hg graft 3 --log -u foo
427 $ hg graft 3 --log -u foo
428 grafting 3:4c60f11aa304 "3"
428 grafting 3:4c60f11aa304 "3"
429 warning: can't find ancestor for 'c' copied from 'b'!
429 warning: can't find ancestor for 'c' copied from 'b'!
430 $ hg log --template '{rev} {parents} {desc}\n' -r tip
430 $ hg log --template '{rev} {parents} {desc}\n' -r tip
431 14 1:5d205f8b35b6 3
431 14 1:5d205f8b35b6 3
432 (grafted from 4c60f11aa304a54ae1c199feb94e7fc771e51ed8)
432 (grafted from 4c60f11aa304a54ae1c199feb94e7fc771e51ed8)
433
433
434 Resolve conflicted graft
434 Resolve conflicted graft
435 $ hg up -q 0
435 $ hg up -q 0
436 $ echo b > a
436 $ echo b > a
437 $ hg ci -m 8
437 $ hg ci -m 8
438 created new head
438 created new head
439 $ echo c > a
439 $ echo c > a
440 $ hg ci -m 9
440 $ hg ci -m 9
441 $ hg graft 1 --tool internal:fail
441 $ hg graft 1 --tool internal:fail
442 grafting 1:5d205f8b35b6 "1"
442 grafting 1:5d205f8b35b6 "1"
443 abort: unresolved conflicts, can't continue
443 abort: unresolved conflicts, can't continue
444 (use hg resolve and hg graft --continue)
444 (use hg resolve and hg graft --continue)
445 [255]
445 [255]
446 $ hg resolve --all
446 $ hg resolve --all
447 merging a
447 merging a
448 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
448 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
449 [1]
449 [1]
450 $ cat a
450 $ cat a
451 <<<<<<< local: aaa4406d4f0a - test: 9
451 <<<<<<< local: aaa4406d4f0a - test: 9
452 c
452 c
453 =======
453 =======
454 b
454 b
455 >>>>>>> other: 5d205f8b35b6 - bar: 1
455 >>>>>>> graft: 5d205f8b35b6 - bar: 1
456 $ echo b > a
456 $ echo b > a
457 $ hg resolve -m a
457 $ hg resolve -m a
458 (no more unresolved files)
458 (no more unresolved files)
459 continue: hg graft --continue
459 continue: hg graft --continue
460 $ hg graft -c
460 $ hg graft -c
461 grafting 1:5d205f8b35b6 "1"
461 grafting 1:5d205f8b35b6 "1"
462 $ hg export tip --git
462 $ hg export tip --git
463 # HG changeset patch
463 # HG changeset patch
464 # User bar
464 # User bar
465 # Date 0 0
465 # Date 0 0
466 # Thu Jan 01 00:00:00 1970 +0000
466 # Thu Jan 01 00:00:00 1970 +0000
467 # Node ID f67661df0c4804d301f064f332b57e7d5ddaf2be
467 # Node ID f67661df0c4804d301f064f332b57e7d5ddaf2be
468 # Parent aaa4406d4f0ae9befd6e58c82ec63706460cbca6
468 # Parent aaa4406d4f0ae9befd6e58c82ec63706460cbca6
469 1
469 1
470
470
471 diff --git a/a b/a
471 diff --git a/a b/a
472 --- a/a
472 --- a/a
473 +++ b/a
473 +++ b/a
474 @@ -1,1 +1,1 @@
474 @@ -1,1 +1,1 @@
475 -c
475 -c
476 +b
476 +b
477
477
478 Resolve conflicted graft with rename
478 Resolve conflicted graft with rename
479 $ echo c > a
479 $ echo c > a
480 $ hg ci -m 10
480 $ hg ci -m 10
481 $ hg graft 2 --tool internal:fail
481 $ hg graft 2 --tool internal:fail
482 grafting 2:5c095ad7e90f "2"
482 grafting 2:5c095ad7e90f "2"
483 abort: unresolved conflicts, can't continue
483 abort: unresolved conflicts, can't continue
484 (use hg resolve and hg graft --continue)
484 (use hg resolve and hg graft --continue)
485 [255]
485 [255]
486 $ hg resolve --all
486 $ hg resolve --all
487 merging a and b to b
487 merging a and b to b
488 (no more unresolved files)
488 (no more unresolved files)
489 continue: hg graft --continue
489 continue: hg graft --continue
490 $ hg graft -c
490 $ hg graft -c
491 grafting 2:5c095ad7e90f "2"
491 grafting 2:5c095ad7e90f "2"
492 $ hg export tip --git
492 $ hg export tip --git
493 # HG changeset patch
493 # HG changeset patch
494 # User test
494 # User test
495 # Date 0 0
495 # Date 0 0
496 # Thu Jan 01 00:00:00 1970 +0000
496 # Thu Jan 01 00:00:00 1970 +0000
497 # Node ID 9627f653b421c61fc1ea4c4e366745070fa3d2bc
497 # Node ID 9627f653b421c61fc1ea4c4e366745070fa3d2bc
498 # Parent ee295f490a40b97f3d18dd4c4f1c8936c233b612
498 # Parent ee295f490a40b97f3d18dd4c4f1c8936c233b612
499 2
499 2
500
500
501 diff --git a/a b/b
501 diff --git a/a b/b
502 rename from a
502 rename from a
503 rename to b
503 rename to b
504
504
505 Test simple origin(), with and without args
505 Test simple origin(), with and without args
506 $ hg log -r 'origin()'
506 $ hg log -r 'origin()'
507 changeset: 1:5d205f8b35b6
507 changeset: 1:5d205f8b35b6
508 user: bar
508 user: bar
509 date: Thu Jan 01 00:00:00 1970 +0000
509 date: Thu Jan 01 00:00:00 1970 +0000
510 summary: 1
510 summary: 1
511
511
512 changeset: 2:5c095ad7e90f
512 changeset: 2:5c095ad7e90f
513 user: test
513 user: test
514 date: Thu Jan 01 00:00:00 1970 +0000
514 date: Thu Jan 01 00:00:00 1970 +0000
515 summary: 2
515 summary: 2
516
516
517 changeset: 3:4c60f11aa304
517 changeset: 3:4c60f11aa304
518 user: baz
518 user: baz
519 date: Thu Jan 01 00:00:00 1970 +0000
519 date: Thu Jan 01 00:00:00 1970 +0000
520 summary: 3
520 summary: 3
521
521
522 changeset: 4:9c233e8e184d
522 changeset: 4:9c233e8e184d
523 user: test
523 user: test
524 date: Thu Jan 01 00:00:00 1970 +0000
524 date: Thu Jan 01 00:00:00 1970 +0000
525 summary: 4
525 summary: 4
526
526
527 changeset: 5:97f8bfe72746
527 changeset: 5:97f8bfe72746
528 branch: stable
528 branch: stable
529 parent: 3:4c60f11aa304
529 parent: 3:4c60f11aa304
530 user: test
530 user: test
531 date: Thu Jan 01 00:00:00 1970 +0000
531 date: Thu Jan 01 00:00:00 1970 +0000
532 summary: 5
532 summary: 5
533
533
534 $ hg log -r 'origin(7)'
534 $ hg log -r 'origin(7)'
535 changeset: 2:5c095ad7e90f
535 changeset: 2:5c095ad7e90f
536 user: test
536 user: test
537 date: Thu Jan 01 00:00:00 1970 +0000
537 date: Thu Jan 01 00:00:00 1970 +0000
538 summary: 2
538 summary: 2
539
539
540 Now transplant a graft to test following through copies
540 Now transplant a graft to test following through copies
541 $ hg up -q 0
541 $ hg up -q 0
542 $ hg branch -q dev
542 $ hg branch -q dev
543 $ hg ci -qm "dev branch"
543 $ hg ci -qm "dev branch"
544 $ hg --config extensions.transplant= transplant -q 7
544 $ hg --config extensions.transplant= transplant -q 7
545 $ hg log -r 'origin(.)'
545 $ hg log -r 'origin(.)'
546 changeset: 2:5c095ad7e90f
546 changeset: 2:5c095ad7e90f
547 user: test
547 user: test
548 date: Thu Jan 01 00:00:00 1970 +0000
548 date: Thu Jan 01 00:00:00 1970 +0000
549 summary: 2
549 summary: 2
550
550
551 Test that the graft and transplant markers in extra are converted, allowing
551 Test that the graft and transplant markers in extra are converted, allowing
552 origin() to still work. Note that these recheck the immediately preceeding two
552 origin() to still work. Note that these recheck the immediately preceeding two
553 tests.
553 tests.
554 $ hg --quiet --config extensions.convert= --config convert.hg.saverev=True convert . ../converted
554 $ hg --quiet --config extensions.convert= --config convert.hg.saverev=True convert . ../converted
555
555
556 The graft case
556 The graft case
557 $ hg -R ../converted log -r 7 --template "{rev}: {node}\n{join(extras, '\n')}\n"
557 $ hg -R ../converted log -r 7 --template "{rev}: {node}\n{join(extras, '\n')}\n"
558 7: 7ae846e9111fc8f57745634250c7b9ac0a60689b
558 7: 7ae846e9111fc8f57745634250c7b9ac0a60689b
559 branch=default
559 branch=default
560 convert_revision=ef0ef43d49e79e81ddafdc7997401ba0041efc82
560 convert_revision=ef0ef43d49e79e81ddafdc7997401ba0041efc82
561 source=e0213322b2c1a5d5d236c74e79666441bee67a7d
561 source=e0213322b2c1a5d5d236c74e79666441bee67a7d
562 $ hg -R ../converted log -r 'origin(7)'
562 $ hg -R ../converted log -r 'origin(7)'
563 changeset: 2:e0213322b2c1
563 changeset: 2:e0213322b2c1
564 user: test
564 user: test
565 date: Thu Jan 01 00:00:00 1970 +0000
565 date: Thu Jan 01 00:00:00 1970 +0000
566 summary: 2
566 summary: 2
567
567
568 Test that template correctly expands more than one 'extra' (issue4362), and that
568 Test that template correctly expands more than one 'extra' (issue4362), and that
569 'intermediate-source' is converted.
569 'intermediate-source' is converted.
570 $ hg -R ../converted log -r 13 --template "{extras % ' Extra: {extra}\n'}"
570 $ hg -R ../converted log -r 13 --template "{extras % ' Extra: {extra}\n'}"
571 Extra: branch=default
571 Extra: branch=default
572 Extra: convert_revision=7a4785234d87ec1aa420ed6b11afe40fa73e12a9
572 Extra: convert_revision=7a4785234d87ec1aa420ed6b11afe40fa73e12a9
573 Extra: intermediate-source=7ae846e9111fc8f57745634250c7b9ac0a60689b
573 Extra: intermediate-source=7ae846e9111fc8f57745634250c7b9ac0a60689b
574 Extra: source=e0213322b2c1a5d5d236c74e79666441bee67a7d
574 Extra: source=e0213322b2c1a5d5d236c74e79666441bee67a7d
575
575
576 The transplant case
576 The transplant case
577 $ hg -R ../converted log -r tip --template "{rev}: {node}\n{join(extras, '\n')}\n"
577 $ hg -R ../converted log -r tip --template "{rev}: {node}\n{join(extras, '\n')}\n"
578 21: fbb6c5cc81002f2b4b49c9d731404688bcae5ade
578 21: fbb6c5cc81002f2b4b49c9d731404688bcae5ade
579 branch=dev
579 branch=dev
580 convert_revision=7e61b508e709a11d28194a5359bc3532d910af21
580 convert_revision=7e61b508e709a11d28194a5359bc3532d910af21
581 transplant_source=z\xe8F\xe9\x11\x1f\xc8\xf5wEcBP\xc7\xb9\xac (esc)
581 transplant_source=z\xe8F\xe9\x11\x1f\xc8\xf5wEcBP\xc7\xb9\xac (esc)
582 `h\x9b (esc)
582 `h\x9b (esc)
583 $ hg -R ../converted log -r 'origin(tip)'
583 $ hg -R ../converted log -r 'origin(tip)'
584 changeset: 2:e0213322b2c1
584 changeset: 2:e0213322b2c1
585 user: test
585 user: test
586 date: Thu Jan 01 00:00:00 1970 +0000
586 date: Thu Jan 01 00:00:00 1970 +0000
587 summary: 2
587 summary: 2
588
588
589
589
590 Test simple destination
590 Test simple destination
591 $ hg log -r 'destination()'
591 $ hg log -r 'destination()'
592 changeset: 7:ef0ef43d49e7
592 changeset: 7:ef0ef43d49e7
593 parent: 0:68795b066622
593 parent: 0:68795b066622
594 user: foo
594 user: foo
595 date: Thu Jan 01 00:00:00 1970 +0000
595 date: Thu Jan 01 00:00:00 1970 +0000
596 summary: 2
596 summary: 2
597
597
598 changeset: 8:6b9e5368ca4e
598 changeset: 8:6b9e5368ca4e
599 user: bar
599 user: bar
600 date: Thu Jan 01 00:00:00 1970 +0000
600 date: Thu Jan 01 00:00:00 1970 +0000
601 summary: 1
601 summary: 1
602
602
603 changeset: 9:1905859650ec
603 changeset: 9:1905859650ec
604 user: test
604 user: test
605 date: Thu Jan 01 00:00:00 1970 +0000
605 date: Thu Jan 01 00:00:00 1970 +0000
606 summary: 5
606 summary: 5
607
607
608 changeset: 10:52dc0b4c6907
608 changeset: 10:52dc0b4c6907
609 user: test
609 user: test
610 date: Thu Jan 01 00:00:00 1970 +0000
610 date: Thu Jan 01 00:00:00 1970 +0000
611 summary: 4
611 summary: 4
612
612
613 changeset: 11:882b35362a6b
613 changeset: 11:882b35362a6b
614 user: test
614 user: test
615 date: Thu Jan 01 00:00:00 1970 +0000
615 date: Thu Jan 01 00:00:00 1970 +0000
616 summary: 3
616 summary: 3
617
617
618 changeset: 13:7a4785234d87
618 changeset: 13:7a4785234d87
619 user: foo
619 user: foo
620 date: Thu Jan 01 00:00:00 1970 +0000
620 date: Thu Jan 01 00:00:00 1970 +0000
621 summary: 2
621 summary: 2
622
622
623 changeset: 14:f64defefacee
623 changeset: 14:f64defefacee
624 parent: 1:5d205f8b35b6
624 parent: 1:5d205f8b35b6
625 user: foo
625 user: foo
626 date: Thu Jan 01 00:00:00 1970 +0000
626 date: Thu Jan 01 00:00:00 1970 +0000
627 summary: 3
627 summary: 3
628
628
629 changeset: 17:f67661df0c48
629 changeset: 17:f67661df0c48
630 user: bar
630 user: bar
631 date: Thu Jan 01 00:00:00 1970 +0000
631 date: Thu Jan 01 00:00:00 1970 +0000
632 summary: 1
632 summary: 1
633
633
634 changeset: 19:9627f653b421
634 changeset: 19:9627f653b421
635 user: test
635 user: test
636 date: Thu Jan 01 00:00:00 1970 +0000
636 date: Thu Jan 01 00:00:00 1970 +0000
637 summary: 2
637 summary: 2
638
638
639 changeset: 21:7e61b508e709
639 changeset: 21:7e61b508e709
640 branch: dev
640 branch: dev
641 tag: tip
641 tag: tip
642 user: foo
642 user: foo
643 date: Thu Jan 01 00:00:00 1970 +0000
643 date: Thu Jan 01 00:00:00 1970 +0000
644 summary: 2
644 summary: 2
645
645
646 $ hg log -r 'destination(2)'
646 $ hg log -r 'destination(2)'
647 changeset: 7:ef0ef43d49e7
647 changeset: 7:ef0ef43d49e7
648 parent: 0:68795b066622
648 parent: 0:68795b066622
649 user: foo
649 user: foo
650 date: Thu Jan 01 00:00:00 1970 +0000
650 date: Thu Jan 01 00:00:00 1970 +0000
651 summary: 2
651 summary: 2
652
652
653 changeset: 13:7a4785234d87
653 changeset: 13:7a4785234d87
654 user: foo
654 user: foo
655 date: Thu Jan 01 00:00:00 1970 +0000
655 date: Thu Jan 01 00:00:00 1970 +0000
656 summary: 2
656 summary: 2
657
657
658 changeset: 19:9627f653b421
658 changeset: 19:9627f653b421
659 user: test
659 user: test
660 date: Thu Jan 01 00:00:00 1970 +0000
660 date: Thu Jan 01 00:00:00 1970 +0000
661 summary: 2
661 summary: 2
662
662
663 changeset: 21:7e61b508e709
663 changeset: 21:7e61b508e709
664 branch: dev
664 branch: dev
665 tag: tip
665 tag: tip
666 user: foo
666 user: foo
667 date: Thu Jan 01 00:00:00 1970 +0000
667 date: Thu Jan 01 00:00:00 1970 +0000
668 summary: 2
668 summary: 2
669
669
670 Transplants of grafts can find a destination...
670 Transplants of grafts can find a destination...
671 $ hg log -r 'destination(7)'
671 $ hg log -r 'destination(7)'
672 changeset: 21:7e61b508e709
672 changeset: 21:7e61b508e709
673 branch: dev
673 branch: dev
674 tag: tip
674 tag: tip
675 user: foo
675 user: foo
676 date: Thu Jan 01 00:00:00 1970 +0000
676 date: Thu Jan 01 00:00:00 1970 +0000
677 summary: 2
677 summary: 2
678
678
679 ... grafts of grafts unfortunately can't
679 ... grafts of grafts unfortunately can't
680 $ hg graft -q 13
680 $ hg graft -q 13
681 warning: can't find ancestor for 'b' copied from 'a'!
681 warning: can't find ancestor for 'b' copied from 'a'!
682 $ hg log -r 'destination(13)'
682 $ hg log -r 'destination(13)'
683 All copies of a cset
683 All copies of a cset
684 $ hg log -r 'origin(13) or destination(origin(13))'
684 $ hg log -r 'origin(13) or destination(origin(13))'
685 changeset: 2:5c095ad7e90f
685 changeset: 2:5c095ad7e90f
686 user: test
686 user: test
687 date: Thu Jan 01 00:00:00 1970 +0000
687 date: Thu Jan 01 00:00:00 1970 +0000
688 summary: 2
688 summary: 2
689
689
690 changeset: 7:ef0ef43d49e7
690 changeset: 7:ef0ef43d49e7
691 parent: 0:68795b066622
691 parent: 0:68795b066622
692 user: foo
692 user: foo
693 date: Thu Jan 01 00:00:00 1970 +0000
693 date: Thu Jan 01 00:00:00 1970 +0000
694 summary: 2
694 summary: 2
695
695
696 changeset: 13:7a4785234d87
696 changeset: 13:7a4785234d87
697 user: foo
697 user: foo
698 date: Thu Jan 01 00:00:00 1970 +0000
698 date: Thu Jan 01 00:00:00 1970 +0000
699 summary: 2
699 summary: 2
700
700
701 changeset: 19:9627f653b421
701 changeset: 19:9627f653b421
702 user: test
702 user: test
703 date: Thu Jan 01 00:00:00 1970 +0000
703 date: Thu Jan 01 00:00:00 1970 +0000
704 summary: 2
704 summary: 2
705
705
706 changeset: 21:7e61b508e709
706 changeset: 21:7e61b508e709
707 branch: dev
707 branch: dev
708 user: foo
708 user: foo
709 date: Thu Jan 01 00:00:00 1970 +0000
709 date: Thu Jan 01 00:00:00 1970 +0000
710 summary: 2
710 summary: 2
711
711
712 changeset: 22:d1cb6591fa4b
712 changeset: 22:d1cb6591fa4b
713 branch: dev
713 branch: dev
714 tag: tip
714 tag: tip
715 user: foo
715 user: foo
716 date: Thu Jan 01 00:00:00 1970 +0000
716 date: Thu Jan 01 00:00:00 1970 +0000
717 summary: 2
717 summary: 2
718
718
719
719
720 graft works on complex revset
720 graft works on complex revset
721
721
722 $ hg graft 'origin(13) or destination(origin(13))'
722 $ hg graft 'origin(13) or destination(origin(13))'
723 skipping ancestor revision 21:7e61b508e709
723 skipping ancestor revision 21:7e61b508e709
724 skipping ancestor revision 22:d1cb6591fa4b
724 skipping ancestor revision 22:d1cb6591fa4b
725 skipping revision 2:5c095ad7e90f (already grafted to 22:d1cb6591fa4b)
725 skipping revision 2:5c095ad7e90f (already grafted to 22:d1cb6591fa4b)
726 grafting 7:ef0ef43d49e7 "2"
726 grafting 7:ef0ef43d49e7 "2"
727 warning: can't find ancestor for 'b' copied from 'a'!
727 warning: can't find ancestor for 'b' copied from 'a'!
728 grafting 13:7a4785234d87 "2"
728 grafting 13:7a4785234d87 "2"
729 warning: can't find ancestor for 'b' copied from 'a'!
729 warning: can't find ancestor for 'b' copied from 'a'!
730 grafting 19:9627f653b421 "2"
730 grafting 19:9627f653b421 "2"
731 merging b
731 merging b
732 warning: can't find ancestor for 'b' copied from 'a'!
732 warning: can't find ancestor for 'b' copied from 'a'!
733
733
734 graft with --force (still doesn't graft merges)
734 graft with --force (still doesn't graft merges)
735
735
736 $ hg graft 19 0 6
736 $ hg graft 19 0 6
737 skipping ungraftable merge revision 6
737 skipping ungraftable merge revision 6
738 skipping ancestor revision 0:68795b066622
738 skipping ancestor revision 0:68795b066622
739 skipping already grafted revision 19:9627f653b421 (22:d1cb6591fa4b also has origin 2:5c095ad7e90f)
739 skipping already grafted revision 19:9627f653b421 (22:d1cb6591fa4b also has origin 2:5c095ad7e90f)
740 [255]
740 [255]
741 $ hg graft 19 0 6 --force
741 $ hg graft 19 0 6 --force
742 skipping ungraftable merge revision 6
742 skipping ungraftable merge revision 6
743 grafting 19:9627f653b421 "2"
743 grafting 19:9627f653b421 "2"
744 merging b
744 merging b
745 warning: can't find ancestor for 'b' copied from 'a'!
745 warning: can't find ancestor for 'b' copied from 'a'!
746 grafting 0:68795b066622 "0"
746 grafting 0:68795b066622 "0"
747
747
748 graft --force after backout
748 graft --force after backout
749
749
750 $ echo abc > a
750 $ echo abc > a
751 $ hg ci -m 28
751 $ hg ci -m 28
752 $ hg backout 28
752 $ hg backout 28
753 reverting a
753 reverting a
754 changeset 29:53177ba928f6 backs out changeset 28:50a516bb8b57
754 changeset 29:53177ba928f6 backs out changeset 28:50a516bb8b57
755 $ hg graft 28
755 $ hg graft 28
756 skipping ancestor revision 28:50a516bb8b57
756 skipping ancestor revision 28:50a516bb8b57
757 [255]
757 [255]
758 $ hg graft 28 --force
758 $ hg graft 28 --force
759 grafting 28:50a516bb8b57 "28"
759 grafting 28:50a516bb8b57 "28"
760 merging a
760 merging a
761 $ cat a
761 $ cat a
762 abc
762 abc
763
763
764 graft --continue after --force
764 graft --continue after --force
765
765
766 $ echo def > a
766 $ echo def > a
767 $ hg ci -m 31
767 $ hg ci -m 31
768 $ hg graft 28 --force --tool internal:fail
768 $ hg graft 28 --force --tool internal:fail
769 grafting 28:50a516bb8b57 "28"
769 grafting 28:50a516bb8b57 "28"
770 abort: unresolved conflicts, can't continue
770 abort: unresolved conflicts, can't continue
771 (use hg resolve and hg graft --continue)
771 (use hg resolve and hg graft --continue)
772 [255]
772 [255]
773 $ hg resolve --all
773 $ hg resolve --all
774 merging a
774 merging a
775 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
775 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
776 [1]
776 [1]
777 $ echo abc > a
777 $ echo abc > a
778 $ hg resolve -m a
778 $ hg resolve -m a
779 (no more unresolved files)
779 (no more unresolved files)
780 continue: hg graft --continue
780 continue: hg graft --continue
781 $ hg graft -c
781 $ hg graft -c
782 grafting 28:50a516bb8b57 "28"
782 grafting 28:50a516bb8b57 "28"
783 $ cat a
783 $ cat a
784 abc
784 abc
785
785
786 Continue testing same origin policy, using revision numbers from test above
786 Continue testing same origin policy, using revision numbers from test above
787 but do some destructive editing of the repo:
787 but do some destructive editing of the repo:
788
788
789 $ hg up -qC 7
789 $ hg up -qC 7
790 $ hg tag -l -r 13 tmp
790 $ hg tag -l -r 13 tmp
791 $ hg --config extensions.strip= strip 2
791 $ hg --config extensions.strip= strip 2
792 saved backup bundle to $TESTTMP/a/.hg/strip-backup/5c095ad7e90f-d323a1e4-backup.hg (glob)
792 saved backup bundle to $TESTTMP/a/.hg/strip-backup/5c095ad7e90f-d323a1e4-backup.hg (glob)
793 $ hg graft tmp
793 $ hg graft tmp
794 skipping already grafted revision 8:7a4785234d87 (2:ef0ef43d49e7 also has unknown origin 5c095ad7e90f)
794 skipping already grafted revision 8:7a4785234d87 (2:ef0ef43d49e7 also has unknown origin 5c095ad7e90f)
795 [255]
795 [255]
796
796
797 Empty graft
797 Empty graft
798
798
799 $ hg up -qr 26
799 $ hg up -qr 26
800 $ hg tag -f something
800 $ hg tag -f something
801 $ hg graft -qr 27
801 $ hg graft -qr 27
802 $ hg graft -f 27
802 $ hg graft -f 27
803 grafting 27:ed6c7e54e319 "28"
803 grafting 27:ed6c7e54e319 "28"
804 note: graft of 27:ed6c7e54e319 created no changes to commit
804 note: graft of 27:ed6c7e54e319 created no changes to commit
805
805
806 $ cd ..
806 $ cd ..
807
807
808 Graft to duplicate a commit
808 Graft to duplicate a commit
809
809
810 $ hg init graftsibling
810 $ hg init graftsibling
811 $ cd graftsibling
811 $ cd graftsibling
812 $ touch a
812 $ touch a
813 $ hg commit -qAm a
813 $ hg commit -qAm a
814 $ touch b
814 $ touch b
815 $ hg commit -qAm b
815 $ hg commit -qAm b
816 $ hg log -G -T '{rev}\n'
816 $ hg log -G -T '{rev}\n'
817 @ 1
817 @ 1
818 |
818 |
819 o 0
819 o 0
820
820
821 $ hg up -q 0
821 $ hg up -q 0
822 $ hg graft -r 1
822 $ hg graft -r 1
823 grafting 1:0e067c57feba "b" (tip)
823 grafting 1:0e067c57feba "b" (tip)
824 $ hg log -G -T '{rev}\n'
824 $ hg log -G -T '{rev}\n'
825 @ 2
825 @ 2
826 |
826 |
827 | o 1
827 | o 1
828 |/
828 |/
829 o 0
829 o 0
830
830
831 Graft to duplicate a commit twice
831 Graft to duplicate a commit twice
832
832
833 $ hg up -q 0
833 $ hg up -q 0
834 $ hg graft -r 2
834 $ hg graft -r 2
835 grafting 2:044ec77f6389 "b" (tip)
835 grafting 2:044ec77f6389 "b" (tip)
836 $ hg log -G -T '{rev}\n'
836 $ hg log -G -T '{rev}\n'
837 @ 3
837 @ 3
838 |
838 |
839 | o 2
839 | o 2
840 |/
840 |/
841 | o 1
841 | o 1
842 |/
842 |/
843 o 0
843 o 0
844
844
@@ -1,159 +1,165 b''
1 $ . "$TESTDIR/histedit-helpers.sh"
1 $ . "$TESTDIR/histedit-helpers.sh"
2
2
3 $ cat >> $HGRCPATH <<EOF
3 $ cat >> $HGRCPATH <<EOF
4 > [extensions]
4 > [extensions]
5 > histedit=
5 > histedit=
6 > EOF
6 > EOF
7
7
8 $ initrepo ()
8 $ initrepo ()
9 > {
9 > {
10 > hg init r
10 > hg init r
11 > cd r
11 > cd r
12 > for x in a b c d e f ; do
12 > for x in a b c d e f ; do
13 > echo $x > $x
13 > echo $x > $x
14 > hg add $x
14 > hg add $x
15 > hg ci -m $x
15 > hg ci -m $x
16 > done
16 > done
17 > echo a >> e
17 > echo a >> e
18 > hg ci -m 'does not commute with e'
18 > hg ci -m 'does not commute with e'
19 > cd ..
19 > cd ..
20 > }
20 > }
21
21
22 $ initrepo
22 $ initrepo
23 $ cd r
23 $ cd r
24
24
25 log before edit
25 log before edit
26 $ hg log --graph
26 $ hg log --graph
27 @ changeset: 6:bfa474341cc9
27 @ changeset: 6:bfa474341cc9
28 | tag: tip
28 | tag: tip
29 | user: test
29 | user: test
30 | date: Thu Jan 01 00:00:00 1970 +0000
30 | date: Thu Jan 01 00:00:00 1970 +0000
31 | summary: does not commute with e
31 | summary: does not commute with e
32 |
32 |
33 o changeset: 5:652413bf663e
33 o changeset: 5:652413bf663e
34 | user: test
34 | user: test
35 | date: Thu Jan 01 00:00:00 1970 +0000
35 | date: Thu Jan 01 00:00:00 1970 +0000
36 | summary: f
36 | summary: f
37 |
37 |
38 o changeset: 4:e860deea161a
38 o changeset: 4:e860deea161a
39 | user: test
39 | user: test
40 | date: Thu Jan 01 00:00:00 1970 +0000
40 | date: Thu Jan 01 00:00:00 1970 +0000
41 | summary: e
41 | summary: e
42 |
42 |
43 o changeset: 3:055a42cdd887
43 o changeset: 3:055a42cdd887
44 | user: test
44 | user: test
45 | date: Thu Jan 01 00:00:00 1970 +0000
45 | date: Thu Jan 01 00:00:00 1970 +0000
46 | summary: d
46 | summary: d
47 |
47 |
48 o changeset: 2:177f92b77385
48 o changeset: 2:177f92b77385
49 | user: test
49 | user: test
50 | date: Thu Jan 01 00:00:00 1970 +0000
50 | date: Thu Jan 01 00:00:00 1970 +0000
51 | summary: c
51 | summary: c
52 |
52 |
53 o changeset: 1:d2ae7f538514
53 o changeset: 1:d2ae7f538514
54 | user: test
54 | user: test
55 | date: Thu Jan 01 00:00:00 1970 +0000
55 | date: Thu Jan 01 00:00:00 1970 +0000
56 | summary: b
56 | summary: b
57 |
57 |
58 o changeset: 0:cb9a9f314b8b
58 o changeset: 0:cb9a9f314b8b
59 user: test
59 user: test
60 date: Thu Jan 01 00:00:00 1970 +0000
60 date: Thu Jan 01 00:00:00 1970 +0000
61 summary: a
61 summary: a
62
62
63
63
64 edit the history
64 edit the history
65 $ hg histedit 177f92b77385 --commands - 2>&1 <<EOF | fixbundle
65 $ hg histedit 177f92b77385 --commands - 2>&1 <<EOF | fixbundle
66 > pick 177f92b77385 c
66 > pick 177f92b77385 c
67 > pick 055a42cdd887 d
67 > pick 055a42cdd887 d
68 > pick bfa474341cc9 does not commute with e
68 > pick bfa474341cc9 does not commute with e
69 > pick e860deea161a e
69 > pick e860deea161a e
70 > pick 652413bf663e f
70 > pick 652413bf663e f
71 > EOF
71 > EOF
72 merging e
72 merging e
73 warning: conflicts while merging e! (edit, then use 'hg resolve --mark')
73 warning: conflicts while merging e! (edit, then use 'hg resolve --mark')
74 Fix up the change (pick e860deea161a)
74 Fix up the change (pick e860deea161a)
75 (hg histedit --continue to resume)
75 (hg histedit --continue to resume)
76
76
77 insert unsupported advisory merge record
77 insert unsupported advisory merge record
78 $ hg --config extensions.fakemergerecord=$TESTDIR/fakemergerecord.py fakemergerecord -x
78 $ hg --config extensions.fakemergerecord=$TESTDIR/fakemergerecord.py fakemergerecord -x
79 $ hg debugmergestate
79 $ hg debugmergestate
80 * version 2 records
80 * version 2 records
81 local: 8f7551c7e4a2f2efe0bc8c741baf7f227d65d758
81 local: 8f7551c7e4a2f2efe0bc8c741baf7f227d65d758
82 other: e860deea161a2f77de56603b340ebbb4536308ae
82 other: e860deea161a2f77de56603b340ebbb4536308ae
83 labels:
84 local: local
85 other: histedit
83 unrecognized entry: x advisory record
86 unrecognized entry: x advisory record
84 file extras: e (ancestorlinknode = 0000000000000000000000000000000000000000)
87 file extras: e (ancestorlinknode = 0000000000000000000000000000000000000000)
85 file: e (record type "F", state "u", hash 58e6b3a414a1e090dfc6029add0f3555ccba127f)
88 file: e (record type "F", state "u", hash 58e6b3a414a1e090dfc6029add0f3555ccba127f)
86 local path: e (flags "")
89 local path: e (flags "")
87 ancestor path: e (node null)
90 ancestor path: e (node null)
88 other path: e (node 6b67ccefd5ce6de77e7ead4f5292843a0255329f)
91 other path: e (node 6b67ccefd5ce6de77e7ead4f5292843a0255329f)
89 $ hg resolve -l
92 $ hg resolve -l
90 U e
93 U e
91
94
92 insert unsupported mandatory merge record
95 insert unsupported mandatory merge record
93 $ hg --config extensions.fakemergerecord=$TESTDIR/fakemergerecord.py fakemergerecord -X
96 $ hg --config extensions.fakemergerecord=$TESTDIR/fakemergerecord.py fakemergerecord -X
94 $ hg debugmergestate
97 $ hg debugmergestate
95 * version 2 records
98 * version 2 records
96 local: 8f7551c7e4a2f2efe0bc8c741baf7f227d65d758
99 local: 8f7551c7e4a2f2efe0bc8c741baf7f227d65d758
97 other: e860deea161a2f77de56603b340ebbb4536308ae
100 other: e860deea161a2f77de56603b340ebbb4536308ae
101 labels:
102 local: local
103 other: histedit
98 file extras: e (ancestorlinknode = 0000000000000000000000000000000000000000)
104 file extras: e (ancestorlinknode = 0000000000000000000000000000000000000000)
99 file: e (record type "F", state "u", hash 58e6b3a414a1e090dfc6029add0f3555ccba127f)
105 file: e (record type "F", state "u", hash 58e6b3a414a1e090dfc6029add0f3555ccba127f)
100 local path: e (flags "")
106 local path: e (flags "")
101 ancestor path: e (node null)
107 ancestor path: e (node null)
102 other path: e (node 6b67ccefd5ce6de77e7ead4f5292843a0255329f)
108 other path: e (node 6b67ccefd5ce6de77e7ead4f5292843a0255329f)
103 unrecognized entry: X mandatory record
109 unrecognized entry: X mandatory record
104 $ hg resolve -l
110 $ hg resolve -l
105 abort: unsupported merge state records: X
111 abort: unsupported merge state records: X
106 (see https://mercurial-scm.org/wiki/MergeStateRecords for more information)
112 (see https://mercurial-scm.org/wiki/MergeStateRecords for more information)
107 [255]
113 [255]
108 $ hg resolve -ma
114 $ hg resolve -ma
109 abort: unsupported merge state records: X
115 abort: unsupported merge state records: X
110 (see https://mercurial-scm.org/wiki/MergeStateRecords for more information)
116 (see https://mercurial-scm.org/wiki/MergeStateRecords for more information)
111 [255]
117 [255]
112
118
113 abort the edit (should clear out merge state)
119 abort the edit (should clear out merge state)
114 $ hg histedit --abort 2>&1 | fixbundle
120 $ hg histedit --abort 2>&1 | fixbundle
115 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
121 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
116 $ hg debugmergestate
122 $ hg debugmergestate
117 no merge state found
123 no merge state found
118
124
119 log after abort
125 log after abort
120 $ hg resolve -l
126 $ hg resolve -l
121 $ hg log --graph
127 $ hg log --graph
122 @ changeset: 6:bfa474341cc9
128 @ changeset: 6:bfa474341cc9
123 | tag: tip
129 | tag: tip
124 | user: test
130 | user: test
125 | date: Thu Jan 01 00:00:00 1970 +0000
131 | date: Thu Jan 01 00:00:00 1970 +0000
126 | summary: does not commute with e
132 | summary: does not commute with e
127 |
133 |
128 o changeset: 5:652413bf663e
134 o changeset: 5:652413bf663e
129 | user: test
135 | user: test
130 | date: Thu Jan 01 00:00:00 1970 +0000
136 | date: Thu Jan 01 00:00:00 1970 +0000
131 | summary: f
137 | summary: f
132 |
138 |
133 o changeset: 4:e860deea161a
139 o changeset: 4:e860deea161a
134 | user: test
140 | user: test
135 | date: Thu Jan 01 00:00:00 1970 +0000
141 | date: Thu Jan 01 00:00:00 1970 +0000
136 | summary: e
142 | summary: e
137 |
143 |
138 o changeset: 3:055a42cdd887
144 o changeset: 3:055a42cdd887
139 | user: test
145 | user: test
140 | date: Thu Jan 01 00:00:00 1970 +0000
146 | date: Thu Jan 01 00:00:00 1970 +0000
141 | summary: d
147 | summary: d
142 |
148 |
143 o changeset: 2:177f92b77385
149 o changeset: 2:177f92b77385
144 | user: test
150 | user: test
145 | date: Thu Jan 01 00:00:00 1970 +0000
151 | date: Thu Jan 01 00:00:00 1970 +0000
146 | summary: c
152 | summary: c
147 |
153 |
148 o changeset: 1:d2ae7f538514
154 o changeset: 1:d2ae7f538514
149 | user: test
155 | user: test
150 | date: Thu Jan 01 00:00:00 1970 +0000
156 | date: Thu Jan 01 00:00:00 1970 +0000
151 | summary: b
157 | summary: b
152 |
158 |
153 o changeset: 0:cb9a9f314b8b
159 o changeset: 0:cb9a9f314b8b
154 user: test
160 user: test
155 date: Thu Jan 01 00:00:00 1970 +0000
161 date: Thu Jan 01 00:00:00 1970 +0000
156 summary: a
162 summary: a
157
163
158
164
159 $ cd ..
165 $ cd ..
@@ -1,1043 +1,1061 b''
1 Tests for change/delete conflicts, including:
1 Tests for change/delete conflicts, including:
2 b5605d88dc27: Make ui.prompt repeat on "unrecognized response" again
2 b5605d88dc27: Make ui.prompt repeat on "unrecognized response" again
3 (issue897)
3 (issue897)
4
4
5 840e2b315c1f: Fix misleading error and prompts during update/merge
5 840e2b315c1f: Fix misleading error and prompts during update/merge
6 (issue556)
6 (issue556)
7
7
8 Make sure HGMERGE doesn't interfere with the test
8 Make sure HGMERGE doesn't interfere with the test
9 $ unset HGMERGE
9 $ unset HGMERGE
10
10
11 $ status() {
11 $ status() {
12 > echo "--- status ---"
12 > echo "--- status ---"
13 > hg st -A file1 file2 file3
13 > hg st -A file1 file2 file3
14 > echo "--- resolve --list ---"
14 > echo "--- resolve --list ---"
15 > hg resolve --list file1 file2 file3
15 > hg resolve --list file1 file2 file3
16 > echo "--- debugmergestate ---"
16 > echo "--- debugmergestate ---"
17 > hg debugmergestate
17 > hg debugmergestate
18 > for file in file1 file2 file3; do
18 > for file in file1 file2 file3; do
19 > if [ -f $file ]; then
19 > if [ -f $file ]; then
20 > echo "--- $file ---"
20 > echo "--- $file ---"
21 > cat $file
21 > cat $file
22 > else
22 > else
23 > echo "*** $file does not exist"
23 > echo "*** $file does not exist"
24 > fi
24 > fi
25 > done
25 > done
26 > }
26 > }
27
27
28 $ hg init repo
28 $ hg init repo
29 $ cd repo
29 $ cd repo
30
30
31 $ echo 1 > file1
31 $ echo 1 > file1
32 $ echo 2 > file2
32 $ echo 2 > file2
33 $ echo 3 > file3
33 $ echo 3 > file3
34 $ hg ci -Am 'added files'
34 $ hg ci -Am 'added files'
35 adding file1
35 adding file1
36 adding file2
36 adding file2
37 adding file3
37 adding file3
38
38
39 $ hg rm file1
39 $ hg rm file1
40 $ echo changed >> file2
40 $ echo changed >> file2
41 $ echo changed1 >> file3
41 $ echo changed1 >> file3
42 $ hg ci -m 'removed file1, changed file2, changed file3'
42 $ hg ci -m 'removed file1, changed file2, changed file3'
43
43
44 $ hg co 0
44 $ hg co 0
45 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
45 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
46
46
47 $ echo changed >> file1
47 $ echo changed >> file1
48 $ hg rm file2
48 $ hg rm file2
49 $ echo changed2 >> file3
49 $ echo changed2 >> file3
50 $ hg ci -m 'changed file1, removed file2, changed file3'
50 $ hg ci -m 'changed file1, removed file2, changed file3'
51 created new head
51 created new head
52
52
53
53
54 Non-interactive merge:
54 Non-interactive merge:
55
55
56 $ hg merge -y
56 $ hg merge -y
57 local changed file1 which remote deleted
57 local changed file1 which remote deleted
58 use (c)hanged version, (d)elete, or leave (u)nresolved? u
58 use (c)hanged version, (d)elete, or leave (u)nresolved? u
59 remote changed file2 which local deleted
59 remote changed file2 which local deleted
60 use (c)hanged version, leave (d)eleted, or leave (u)nresolved? u
60 use (c)hanged version, leave (d)eleted, or leave (u)nresolved? u
61 merging file3
61 merging file3
62 warning: conflicts while merging file3! (edit, then use 'hg resolve --mark')
62 warning: conflicts while merging file3! (edit, then use 'hg resolve --mark')
63 0 files updated, 0 files merged, 0 files removed, 3 files unresolved
63 0 files updated, 0 files merged, 0 files removed, 3 files unresolved
64 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
64 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
65 [1]
65 [1]
66
66
67 $ status
67 $ status
68 --- status ---
68 --- status ---
69 M file2
69 M file2
70 M file3
70 M file3
71 C file1
71 C file1
72 --- resolve --list ---
72 --- resolve --list ---
73 U file1
73 U file1
74 U file2
74 U file2
75 U file3
75 U file3
76 --- debugmergestate ---
76 --- debugmergestate ---
77 * version 2 records
77 * version 2 records
78 local: 13910f48cf7bdb2a0ba6e24b4900e4fdd5739dd4
78 local: 13910f48cf7bdb2a0ba6e24b4900e4fdd5739dd4
79 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
79 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
80 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
80 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
81 file: file1 (record type "C", state "u", hash 60b27f004e454aca81b0480209cce5081ec52390)
81 file: file1 (record type "C", state "u", hash 60b27f004e454aca81b0480209cce5081ec52390)
82 local path: file1 (flags "")
82 local path: file1 (flags "")
83 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
83 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
84 other path: file1 (node null)
84 other path: file1 (node null)
85 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
85 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
86 file: file2 (record type "C", state "u", hash null)
86 file: file2 (record type "C", state "u", hash null)
87 local path: file2 (flags "")
87 local path: file2 (flags "")
88 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
88 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
89 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
89 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
90 file extras: file3 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
90 file extras: file3 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
91 file: file3 (record type "F", state "u", hash d5b0a58bc47161b1b8a831084b366f757c4f0b11)
91 file: file3 (record type "F", state "u", hash d5b0a58bc47161b1b8a831084b366f757c4f0b11)
92 local path: file3 (flags "")
92 local path: file3 (flags "")
93 ancestor path: file3 (node 2661d26c649684b482d10f91960cc3db683c38b4)
93 ancestor path: file3 (node 2661d26c649684b482d10f91960cc3db683c38b4)
94 other path: file3 (node a2644c43e210356772c7772a8674544a62e06beb)
94 other path: file3 (node a2644c43e210356772c7772a8674544a62e06beb)
95 --- file1 ---
95 --- file1 ---
96 1
96 1
97 changed
97 changed
98 --- file2 ---
98 --- file2 ---
99 2
99 2
100 changed
100 changed
101 --- file3 ---
101 --- file3 ---
102 3
102 3
103 <<<<<<< local: 13910f48cf7b - test: changed file1, removed file2, changed file3
103 <<<<<<< local: 13910f48cf7b - test: changed file1, removed file2, changed file3
104 changed2
104 changed2
105 =======
105 =======
106 changed1
106 changed1
107 >>>>>>> other: 10f9a0a634e8 - test: removed file1, changed file2, changed file3
107 >>>>>>> other: 10f9a0a634e8 - test: removed file1, changed file2, changed file3
108
108
109
109
110 Interactive merge:
110 Interactive merge:
111
111
112 $ hg co -C
112 $ hg co -C
113 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
113 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
114 1 other heads for branch "default"
114 1 other heads for branch "default"
115
115
116 $ hg merge --config ui.interactive=true <<EOF
116 $ hg merge --config ui.interactive=true <<EOF
117 > c
117 > c
118 > d
118 > d
119 > EOF
119 > EOF
120 local changed file1 which remote deleted
120 local changed file1 which remote deleted
121 use (c)hanged version, (d)elete, or leave (u)nresolved? c
121 use (c)hanged version, (d)elete, or leave (u)nresolved? c
122 remote changed file2 which local deleted
122 remote changed file2 which local deleted
123 use (c)hanged version, leave (d)eleted, or leave (u)nresolved? d
123 use (c)hanged version, leave (d)eleted, or leave (u)nresolved? d
124 merging file3
124 merging file3
125 warning: conflicts while merging file3! (edit, then use 'hg resolve --mark')
125 warning: conflicts while merging file3! (edit, then use 'hg resolve --mark')
126 0 files updated, 2 files merged, 0 files removed, 1 files unresolved
126 0 files updated, 2 files merged, 0 files removed, 1 files unresolved
127 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
127 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
128 [1]
128 [1]
129
129
130 $ status
130 $ status
131 --- status ---
131 --- status ---
132 file2: * (glob)
132 file2: * (glob)
133 M file3
133 M file3
134 C file1
134 C file1
135 --- resolve --list ---
135 --- resolve --list ---
136 R file1
136 R file1
137 R file2
137 R file2
138 U file3
138 U file3
139 --- debugmergestate ---
139 --- debugmergestate ---
140 * version 2 records
140 * version 2 records
141 local: 13910f48cf7bdb2a0ba6e24b4900e4fdd5739dd4
141 local: 13910f48cf7bdb2a0ba6e24b4900e4fdd5739dd4
142 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
142 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
143 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
143 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
144 file: file1 (record type "C", state "r", hash 60b27f004e454aca81b0480209cce5081ec52390)
144 file: file1 (record type "C", state "r", hash 60b27f004e454aca81b0480209cce5081ec52390)
145 local path: file1 (flags "")
145 local path: file1 (flags "")
146 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
146 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
147 other path: file1 (node null)
147 other path: file1 (node null)
148 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
148 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
149 file: file2 (record type "C", state "r", hash null)
149 file: file2 (record type "C", state "r", hash null)
150 local path: file2 (flags "")
150 local path: file2 (flags "")
151 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
151 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
152 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
152 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
153 file extras: file3 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
153 file extras: file3 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
154 file: file3 (record type "F", state "u", hash d5b0a58bc47161b1b8a831084b366f757c4f0b11)
154 file: file3 (record type "F", state "u", hash d5b0a58bc47161b1b8a831084b366f757c4f0b11)
155 local path: file3 (flags "")
155 local path: file3 (flags "")
156 ancestor path: file3 (node 2661d26c649684b482d10f91960cc3db683c38b4)
156 ancestor path: file3 (node 2661d26c649684b482d10f91960cc3db683c38b4)
157 other path: file3 (node a2644c43e210356772c7772a8674544a62e06beb)
157 other path: file3 (node a2644c43e210356772c7772a8674544a62e06beb)
158 --- file1 ---
158 --- file1 ---
159 1
159 1
160 changed
160 changed
161 *** file2 does not exist
161 *** file2 does not exist
162 --- file3 ---
162 --- file3 ---
163 3
163 3
164 <<<<<<< local: 13910f48cf7b - test: changed file1, removed file2, changed file3
164 <<<<<<< local: 13910f48cf7b - test: changed file1, removed file2, changed file3
165 changed2
165 changed2
166 =======
166 =======
167 changed1
167 changed1
168 >>>>>>> other: 10f9a0a634e8 - test: removed file1, changed file2, changed file3
168 >>>>>>> other: 10f9a0a634e8 - test: removed file1, changed file2, changed file3
169
169
170
170
171 Interactive merge with bad input:
171 Interactive merge with bad input:
172
172
173 $ hg co -C
173 $ hg co -C
174 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
174 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
175 1 other heads for branch "default"
175 1 other heads for branch "default"
176
176
177 $ hg merge --config ui.interactive=true <<EOF
177 $ hg merge --config ui.interactive=true <<EOF
178 > foo
178 > foo
179 > bar
179 > bar
180 > d
180 > d
181 > baz
181 > baz
182 > c
182 > c
183 > EOF
183 > EOF
184 local changed file1 which remote deleted
184 local changed file1 which remote deleted
185 use (c)hanged version, (d)elete, or leave (u)nresolved? foo
185 use (c)hanged version, (d)elete, or leave (u)nresolved? foo
186 unrecognized response
186 unrecognized response
187 local changed file1 which remote deleted
187 local changed file1 which remote deleted
188 use (c)hanged version, (d)elete, or leave (u)nresolved? bar
188 use (c)hanged version, (d)elete, or leave (u)nresolved? bar
189 unrecognized response
189 unrecognized response
190 local changed file1 which remote deleted
190 local changed file1 which remote deleted
191 use (c)hanged version, (d)elete, or leave (u)nresolved? d
191 use (c)hanged version, (d)elete, or leave (u)nresolved? d
192 remote changed file2 which local deleted
192 remote changed file2 which local deleted
193 use (c)hanged version, leave (d)eleted, or leave (u)nresolved? baz
193 use (c)hanged version, leave (d)eleted, or leave (u)nresolved? baz
194 unrecognized response
194 unrecognized response
195 remote changed file2 which local deleted
195 remote changed file2 which local deleted
196 use (c)hanged version, leave (d)eleted, or leave (u)nresolved? c
196 use (c)hanged version, leave (d)eleted, or leave (u)nresolved? c
197 merging file3
197 merging file3
198 warning: conflicts while merging file3! (edit, then use 'hg resolve --mark')
198 warning: conflicts while merging file3! (edit, then use 'hg resolve --mark')
199 0 files updated, 1 files merged, 1 files removed, 1 files unresolved
199 0 files updated, 1 files merged, 1 files removed, 1 files unresolved
200 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
200 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
201 [1]
201 [1]
202
202
203 $ status
203 $ status
204 --- status ---
204 --- status ---
205 M file2
205 M file2
206 M file3
206 M file3
207 R file1
207 R file1
208 --- resolve --list ---
208 --- resolve --list ---
209 R file1
209 R file1
210 R file2
210 R file2
211 U file3
211 U file3
212 --- debugmergestate ---
212 --- debugmergestate ---
213 * version 2 records
213 * version 2 records
214 local: 13910f48cf7bdb2a0ba6e24b4900e4fdd5739dd4
214 local: 13910f48cf7bdb2a0ba6e24b4900e4fdd5739dd4
215 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
215 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
216 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
216 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
217 file: file1 (record type "C", state "r", hash 60b27f004e454aca81b0480209cce5081ec52390)
217 file: file1 (record type "C", state "r", hash 60b27f004e454aca81b0480209cce5081ec52390)
218 local path: file1 (flags "")
218 local path: file1 (flags "")
219 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
219 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
220 other path: file1 (node null)
220 other path: file1 (node null)
221 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
221 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
222 file: file2 (record type "C", state "r", hash null)
222 file: file2 (record type "C", state "r", hash null)
223 local path: file2 (flags "")
223 local path: file2 (flags "")
224 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
224 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
225 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
225 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
226 file extras: file3 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
226 file extras: file3 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
227 file: file3 (record type "F", state "u", hash d5b0a58bc47161b1b8a831084b366f757c4f0b11)
227 file: file3 (record type "F", state "u", hash d5b0a58bc47161b1b8a831084b366f757c4f0b11)
228 local path: file3 (flags "")
228 local path: file3 (flags "")
229 ancestor path: file3 (node 2661d26c649684b482d10f91960cc3db683c38b4)
229 ancestor path: file3 (node 2661d26c649684b482d10f91960cc3db683c38b4)
230 other path: file3 (node a2644c43e210356772c7772a8674544a62e06beb)
230 other path: file3 (node a2644c43e210356772c7772a8674544a62e06beb)
231 *** file1 does not exist
231 *** file1 does not exist
232 --- file2 ---
232 --- file2 ---
233 2
233 2
234 changed
234 changed
235 --- file3 ---
235 --- file3 ---
236 3
236 3
237 <<<<<<< local: 13910f48cf7b - test: changed file1, removed file2, changed file3
237 <<<<<<< local: 13910f48cf7b - test: changed file1, removed file2, changed file3
238 changed2
238 changed2
239 =======
239 =======
240 changed1
240 changed1
241 >>>>>>> other: 10f9a0a634e8 - test: removed file1, changed file2, changed file3
241 >>>>>>> other: 10f9a0a634e8 - test: removed file1, changed file2, changed file3
242
242
243
243
244 Interactive merge with not enough input:
244 Interactive merge with not enough input:
245
245
246 $ hg co -C
246 $ hg co -C
247 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
247 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
248 1 other heads for branch "default"
248 1 other heads for branch "default"
249
249
250 $ hg merge --config ui.interactive=true <<EOF
250 $ hg merge --config ui.interactive=true <<EOF
251 > d
251 > d
252 > EOF
252 > EOF
253 local changed file1 which remote deleted
253 local changed file1 which remote deleted
254 use (c)hanged version, (d)elete, or leave (u)nresolved? d
254 use (c)hanged version, (d)elete, or leave (u)nresolved? d
255 remote changed file2 which local deleted
255 remote changed file2 which local deleted
256 use (c)hanged version, leave (d)eleted, or leave (u)nresolved?
256 use (c)hanged version, leave (d)eleted, or leave (u)nresolved?
257 merging file3
257 merging file3
258 warning: conflicts while merging file3! (edit, then use 'hg resolve --mark')
258 warning: conflicts while merging file3! (edit, then use 'hg resolve --mark')
259 0 files updated, 0 files merged, 1 files removed, 2 files unresolved
259 0 files updated, 0 files merged, 1 files removed, 2 files unresolved
260 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
260 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
261 [1]
261 [1]
262
262
263 $ status
263 $ status
264 --- status ---
264 --- status ---
265 M file2
265 M file2
266 M file3
266 M file3
267 R file1
267 R file1
268 --- resolve --list ---
268 --- resolve --list ---
269 R file1
269 R file1
270 U file2
270 U file2
271 U file3
271 U file3
272 --- debugmergestate ---
272 --- debugmergestate ---
273 * version 2 records
273 * version 2 records
274 local: 13910f48cf7bdb2a0ba6e24b4900e4fdd5739dd4
274 local: 13910f48cf7bdb2a0ba6e24b4900e4fdd5739dd4
275 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
275 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
276 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
276 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
277 file: file1 (record type "C", state "r", hash 60b27f004e454aca81b0480209cce5081ec52390)
277 file: file1 (record type "C", state "r", hash 60b27f004e454aca81b0480209cce5081ec52390)
278 local path: file1 (flags "")
278 local path: file1 (flags "")
279 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
279 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
280 other path: file1 (node null)
280 other path: file1 (node null)
281 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
281 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
282 file: file2 (record type "C", state "u", hash null)
282 file: file2 (record type "C", state "u", hash null)
283 local path: file2 (flags "")
283 local path: file2 (flags "")
284 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
284 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
285 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
285 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
286 file extras: file3 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
286 file extras: file3 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
287 file: file3 (record type "F", state "u", hash d5b0a58bc47161b1b8a831084b366f757c4f0b11)
287 file: file3 (record type "F", state "u", hash d5b0a58bc47161b1b8a831084b366f757c4f0b11)
288 local path: file3 (flags "")
288 local path: file3 (flags "")
289 ancestor path: file3 (node 2661d26c649684b482d10f91960cc3db683c38b4)
289 ancestor path: file3 (node 2661d26c649684b482d10f91960cc3db683c38b4)
290 other path: file3 (node a2644c43e210356772c7772a8674544a62e06beb)
290 other path: file3 (node a2644c43e210356772c7772a8674544a62e06beb)
291 *** file1 does not exist
291 *** file1 does not exist
292 --- file2 ---
292 --- file2 ---
293 2
293 2
294 changed
294 changed
295 --- file3 ---
295 --- file3 ---
296 3
296 3
297 <<<<<<< local: 13910f48cf7b - test: changed file1, removed file2, changed file3
297 <<<<<<< local: 13910f48cf7b - test: changed file1, removed file2, changed file3
298 changed2
298 changed2
299 =======
299 =======
300 changed1
300 changed1
301 >>>>>>> other: 10f9a0a634e8 - test: removed file1, changed file2, changed file3
301 >>>>>>> other: 10f9a0a634e8 - test: removed file1, changed file2, changed file3
302
302
303 Choose local versions of files
303 Choose local versions of files
304
304
305 $ hg co -C
305 $ hg co -C
306 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
306 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
307 1 other heads for branch "default"
307 1 other heads for branch "default"
308
308
309 $ hg merge --tool :local
309 $ hg merge --tool :local
310 0 files updated, 3 files merged, 0 files removed, 0 files unresolved
310 0 files updated, 3 files merged, 0 files removed, 0 files unresolved
311 (branch merge, don't forget to commit)
311 (branch merge, don't forget to commit)
312 $ status 2>&1 | tee $TESTTMP/local.status
312 $ status 2>&1 | tee $TESTTMP/local.status
313 --- status ---
313 --- status ---
314 file2: * (glob)
314 file2: * (glob)
315 M file3
315 M file3
316 C file1
316 C file1
317 --- resolve --list ---
317 --- resolve --list ---
318 R file1
318 R file1
319 R file2
319 R file2
320 R file3
320 R file3
321 --- debugmergestate ---
321 --- debugmergestate ---
322 * version 2 records
322 * version 2 records
323 local: 13910f48cf7bdb2a0ba6e24b4900e4fdd5739dd4
323 local: 13910f48cf7bdb2a0ba6e24b4900e4fdd5739dd4
324 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
324 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
325 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
325 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
326 file: file1 (record type "C", state "r", hash 60b27f004e454aca81b0480209cce5081ec52390)
326 file: file1 (record type "C", state "r", hash 60b27f004e454aca81b0480209cce5081ec52390)
327 local path: file1 (flags "")
327 local path: file1 (flags "")
328 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
328 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
329 other path: file1 (node null)
329 other path: file1 (node null)
330 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
330 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
331 file: file2 (record type "C", state "r", hash null)
331 file: file2 (record type "C", state "r", hash null)
332 local path: file2 (flags "")
332 local path: file2 (flags "")
333 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
333 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
334 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
334 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
335 file extras: file3 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
335 file extras: file3 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
336 file: file3 (record type "F", state "r", hash d5b0a58bc47161b1b8a831084b366f757c4f0b11)
336 file: file3 (record type "F", state "r", hash d5b0a58bc47161b1b8a831084b366f757c4f0b11)
337 local path: file3 (flags "")
337 local path: file3 (flags "")
338 ancestor path: file3 (node 2661d26c649684b482d10f91960cc3db683c38b4)
338 ancestor path: file3 (node 2661d26c649684b482d10f91960cc3db683c38b4)
339 other path: file3 (node a2644c43e210356772c7772a8674544a62e06beb)
339 other path: file3 (node a2644c43e210356772c7772a8674544a62e06beb)
340 --- file1 ---
340 --- file1 ---
341 1
341 1
342 changed
342 changed
343 *** file2 does not exist
343 *** file2 does not exist
344 --- file3 ---
344 --- file3 ---
345 3
345 3
346 changed2
346 changed2
347
347
348 Choose other versions of files
348 Choose other versions of files
349
349
350 $ hg co -C
350 $ hg co -C
351 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
351 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
352 1 other heads for branch "default"
352 1 other heads for branch "default"
353
353
354 $ hg merge --tool :other
354 $ hg merge --tool :other
355 0 files updated, 2 files merged, 1 files removed, 0 files unresolved
355 0 files updated, 2 files merged, 1 files removed, 0 files unresolved
356 (branch merge, don't forget to commit)
356 (branch merge, don't forget to commit)
357 $ status 2>&1 | tee $TESTTMP/other.status
357 $ status 2>&1 | tee $TESTTMP/other.status
358 --- status ---
358 --- status ---
359 M file2
359 M file2
360 M file3
360 M file3
361 R file1
361 R file1
362 --- resolve --list ---
362 --- resolve --list ---
363 R file1
363 R file1
364 R file2
364 R file2
365 R file3
365 R file3
366 --- debugmergestate ---
366 --- debugmergestate ---
367 * version 2 records
367 * version 2 records
368 local: 13910f48cf7bdb2a0ba6e24b4900e4fdd5739dd4
368 local: 13910f48cf7bdb2a0ba6e24b4900e4fdd5739dd4
369 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
369 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
370 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
370 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
371 file: file1 (record type "C", state "r", hash 60b27f004e454aca81b0480209cce5081ec52390)
371 file: file1 (record type "C", state "r", hash 60b27f004e454aca81b0480209cce5081ec52390)
372 local path: file1 (flags "")
372 local path: file1 (flags "")
373 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
373 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
374 other path: file1 (node null)
374 other path: file1 (node null)
375 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
375 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
376 file: file2 (record type "C", state "r", hash null)
376 file: file2 (record type "C", state "r", hash null)
377 local path: file2 (flags "")
377 local path: file2 (flags "")
378 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
378 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
379 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
379 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
380 file extras: file3 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
380 file extras: file3 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
381 file: file3 (record type "F", state "r", hash d5b0a58bc47161b1b8a831084b366f757c4f0b11)
381 file: file3 (record type "F", state "r", hash d5b0a58bc47161b1b8a831084b366f757c4f0b11)
382 local path: file3 (flags "")
382 local path: file3 (flags "")
383 ancestor path: file3 (node 2661d26c649684b482d10f91960cc3db683c38b4)
383 ancestor path: file3 (node 2661d26c649684b482d10f91960cc3db683c38b4)
384 other path: file3 (node a2644c43e210356772c7772a8674544a62e06beb)
384 other path: file3 (node a2644c43e210356772c7772a8674544a62e06beb)
385 *** file1 does not exist
385 *** file1 does not exist
386 --- file2 ---
386 --- file2 ---
387 2
387 2
388 changed
388 changed
389 --- file3 ---
389 --- file3 ---
390 3
390 3
391 changed1
391 changed1
392
392
393 Fail
393 Fail
394
394
395 $ hg co -C
395 $ hg co -C
396 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
396 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
397 1 other heads for branch "default"
397 1 other heads for branch "default"
398
398
399 $ hg merge --tool :fail
399 $ hg merge --tool :fail
400 0 files updated, 0 files merged, 0 files removed, 3 files unresolved
400 0 files updated, 0 files merged, 0 files removed, 3 files unresolved
401 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
401 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
402 [1]
402 [1]
403 $ status 2>&1 | tee $TESTTMP/fail.status
403 $ status 2>&1 | tee $TESTTMP/fail.status
404 --- status ---
404 --- status ---
405 M file2
405 M file2
406 M file3
406 M file3
407 C file1
407 C file1
408 --- resolve --list ---
408 --- resolve --list ---
409 U file1
409 U file1
410 U file2
410 U file2
411 U file3
411 U file3
412 --- debugmergestate ---
412 --- debugmergestate ---
413 * version 2 records
413 * version 2 records
414 local: 13910f48cf7bdb2a0ba6e24b4900e4fdd5739dd4
414 local: 13910f48cf7bdb2a0ba6e24b4900e4fdd5739dd4
415 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
415 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
416 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
416 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
417 file: file1 (record type "C", state "u", hash 60b27f004e454aca81b0480209cce5081ec52390)
417 file: file1 (record type "C", state "u", hash 60b27f004e454aca81b0480209cce5081ec52390)
418 local path: file1 (flags "")
418 local path: file1 (flags "")
419 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
419 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
420 other path: file1 (node null)
420 other path: file1 (node null)
421 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
421 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
422 file: file2 (record type "C", state "u", hash null)
422 file: file2 (record type "C", state "u", hash null)
423 local path: file2 (flags "")
423 local path: file2 (flags "")
424 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
424 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
425 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
425 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
426 file extras: file3 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
426 file extras: file3 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
427 file: file3 (record type "F", state "u", hash d5b0a58bc47161b1b8a831084b366f757c4f0b11)
427 file: file3 (record type "F", state "u", hash d5b0a58bc47161b1b8a831084b366f757c4f0b11)
428 local path: file3 (flags "")
428 local path: file3 (flags "")
429 ancestor path: file3 (node 2661d26c649684b482d10f91960cc3db683c38b4)
429 ancestor path: file3 (node 2661d26c649684b482d10f91960cc3db683c38b4)
430 other path: file3 (node a2644c43e210356772c7772a8674544a62e06beb)
430 other path: file3 (node a2644c43e210356772c7772a8674544a62e06beb)
431 --- file1 ---
431 --- file1 ---
432 1
432 1
433 changed
433 changed
434 --- file2 ---
434 --- file2 ---
435 2
435 2
436 changed
436 changed
437 --- file3 ---
437 --- file3 ---
438 3
438 3
439 changed2
439 changed2
440
440
441 Force prompts with no input (should be similar to :fail)
441 Force prompts with no input (should be similar to :fail)
442
442
443 $ hg co -C
443 $ hg co -C
444 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
444 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
445 1 other heads for branch "default"
445 1 other heads for branch "default"
446
446
447 $ hg merge --config ui.interactive=True --tool :prompt
447 $ hg merge --config ui.interactive=True --tool :prompt
448 local changed file1 which remote deleted
448 local changed file1 which remote deleted
449 use (c)hanged version, (d)elete, or leave (u)nresolved?
449 use (c)hanged version, (d)elete, or leave (u)nresolved?
450 remote changed file2 which local deleted
450 remote changed file2 which local deleted
451 use (c)hanged version, leave (d)eleted, or leave (u)nresolved?
451 use (c)hanged version, leave (d)eleted, or leave (u)nresolved?
452 no tool found to merge file3
452 no tool found to merge file3
453 keep (l)ocal, take (o)ther, or leave (u)nresolved?
453 keep (l)ocal, take (o)ther, or leave (u)nresolved?
454 0 files updated, 0 files merged, 0 files removed, 3 files unresolved
454 0 files updated, 0 files merged, 0 files removed, 3 files unresolved
455 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
455 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
456 [1]
456 [1]
457 $ status 2>&1 | tee $TESTTMP/prompt.status
457 $ status 2>&1 | tee $TESTTMP/prompt.status
458 --- status ---
458 --- status ---
459 M file2
459 M file2
460 M file3
460 M file3
461 C file1
461 C file1
462 --- resolve --list ---
462 --- resolve --list ---
463 U file1
463 U file1
464 U file2
464 U file2
465 U file3
465 U file3
466 --- debugmergestate ---
466 --- debugmergestate ---
467 * version 2 records
467 * version 2 records
468 local: 13910f48cf7bdb2a0ba6e24b4900e4fdd5739dd4
468 local: 13910f48cf7bdb2a0ba6e24b4900e4fdd5739dd4
469 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
469 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
470 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
470 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
471 file: file1 (record type "C", state "u", hash 60b27f004e454aca81b0480209cce5081ec52390)
471 file: file1 (record type "C", state "u", hash 60b27f004e454aca81b0480209cce5081ec52390)
472 local path: file1 (flags "")
472 local path: file1 (flags "")
473 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
473 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
474 other path: file1 (node null)
474 other path: file1 (node null)
475 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
475 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
476 file: file2 (record type "C", state "u", hash null)
476 file: file2 (record type "C", state "u", hash null)
477 local path: file2 (flags "")
477 local path: file2 (flags "")
478 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
478 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
479 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
479 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
480 file extras: file3 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
480 file extras: file3 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
481 file: file3 (record type "F", state "u", hash d5b0a58bc47161b1b8a831084b366f757c4f0b11)
481 file: file3 (record type "F", state "u", hash d5b0a58bc47161b1b8a831084b366f757c4f0b11)
482 local path: file3 (flags "")
482 local path: file3 (flags "")
483 ancestor path: file3 (node 2661d26c649684b482d10f91960cc3db683c38b4)
483 ancestor path: file3 (node 2661d26c649684b482d10f91960cc3db683c38b4)
484 other path: file3 (node a2644c43e210356772c7772a8674544a62e06beb)
484 other path: file3 (node a2644c43e210356772c7772a8674544a62e06beb)
485 --- file1 ---
485 --- file1 ---
486 1
486 1
487 changed
487 changed
488 --- file2 ---
488 --- file2 ---
489 2
489 2
490 changed
490 changed
491 --- file3 ---
491 --- file3 ---
492 3
492 3
493 changed2
493 changed2
494 $ cmp $TESTTMP/fail.status $TESTTMP/prompt.status || diff -U8 $TESTTMP/fail.status $TESTTMP/prompt.status
494 $ cmp $TESTTMP/fail.status $TESTTMP/prompt.status || diff -U8 $TESTTMP/fail.status $TESTTMP/prompt.status
495
495
496
496
497 Force prompts
497 Force prompts
498
498
499 $ hg co -C
499 $ hg co -C
500 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
500 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
501 1 other heads for branch "default"
501 1 other heads for branch "default"
502
502
503 $ hg merge --tool :prompt
503 $ hg merge --tool :prompt
504 local changed file1 which remote deleted
504 local changed file1 which remote deleted
505 use (c)hanged version, (d)elete, or leave (u)nresolved? u
505 use (c)hanged version, (d)elete, or leave (u)nresolved? u
506 remote changed file2 which local deleted
506 remote changed file2 which local deleted
507 use (c)hanged version, leave (d)eleted, or leave (u)nresolved? u
507 use (c)hanged version, leave (d)eleted, or leave (u)nresolved? u
508 no tool found to merge file3
508 no tool found to merge file3
509 keep (l)ocal, take (o)ther, or leave (u)nresolved? u
509 keep (l)ocal, take (o)ther, or leave (u)nresolved? u
510 0 files updated, 0 files merged, 0 files removed, 3 files unresolved
510 0 files updated, 0 files merged, 0 files removed, 3 files unresolved
511 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
511 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
512 [1]
512 [1]
513 $ status
513 $ status
514 --- status ---
514 --- status ---
515 M file2
515 M file2
516 M file3
516 M file3
517 C file1
517 C file1
518 --- resolve --list ---
518 --- resolve --list ---
519 U file1
519 U file1
520 U file2
520 U file2
521 U file3
521 U file3
522 --- debugmergestate ---
522 --- debugmergestate ---
523 * version 2 records
523 * version 2 records
524 local: 13910f48cf7bdb2a0ba6e24b4900e4fdd5739dd4
524 local: 13910f48cf7bdb2a0ba6e24b4900e4fdd5739dd4
525 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
525 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
526 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
526 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
527 file: file1 (record type "C", state "u", hash 60b27f004e454aca81b0480209cce5081ec52390)
527 file: file1 (record type "C", state "u", hash 60b27f004e454aca81b0480209cce5081ec52390)
528 local path: file1 (flags "")
528 local path: file1 (flags "")
529 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
529 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
530 other path: file1 (node null)
530 other path: file1 (node null)
531 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
531 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
532 file: file2 (record type "C", state "u", hash null)
532 file: file2 (record type "C", state "u", hash null)
533 local path: file2 (flags "")
533 local path: file2 (flags "")
534 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
534 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
535 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
535 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
536 file extras: file3 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
536 file extras: file3 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
537 file: file3 (record type "F", state "u", hash d5b0a58bc47161b1b8a831084b366f757c4f0b11)
537 file: file3 (record type "F", state "u", hash d5b0a58bc47161b1b8a831084b366f757c4f0b11)
538 local path: file3 (flags "")
538 local path: file3 (flags "")
539 ancestor path: file3 (node 2661d26c649684b482d10f91960cc3db683c38b4)
539 ancestor path: file3 (node 2661d26c649684b482d10f91960cc3db683c38b4)
540 other path: file3 (node a2644c43e210356772c7772a8674544a62e06beb)
540 other path: file3 (node a2644c43e210356772c7772a8674544a62e06beb)
541 --- file1 ---
541 --- file1 ---
542 1
542 1
543 changed
543 changed
544 --- file2 ---
544 --- file2 ---
545 2
545 2
546 changed
546 changed
547 --- file3 ---
547 --- file3 ---
548 3
548 3
549 changed2
549 changed2
550
550
551 Choose to merge all files
551 Choose to merge all files
552
552
553 $ hg co -C
553 $ hg co -C
554 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
554 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
555 1 other heads for branch "default"
555 1 other heads for branch "default"
556
556
557 $ hg merge --tool :merge3
557 $ hg merge --tool :merge3
558 local changed file1 which remote deleted
558 local changed file1 which remote deleted
559 use (c)hanged version, (d)elete, or leave (u)nresolved? u
559 use (c)hanged version, (d)elete, or leave (u)nresolved? u
560 remote changed file2 which local deleted
560 remote changed file2 which local deleted
561 use (c)hanged version, leave (d)eleted, or leave (u)nresolved? u
561 use (c)hanged version, leave (d)eleted, or leave (u)nresolved? u
562 merging file3
562 merging file3
563 warning: conflicts while merging file3! (edit, then use 'hg resolve --mark')
563 warning: conflicts while merging file3! (edit, then use 'hg resolve --mark')
564 0 files updated, 0 files merged, 0 files removed, 3 files unresolved
564 0 files updated, 0 files merged, 0 files removed, 3 files unresolved
565 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
565 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
566 [1]
566 [1]
567 $ status
567 $ status
568 --- status ---
568 --- status ---
569 M file2
569 M file2
570 M file3
570 M file3
571 C file1
571 C file1
572 --- resolve --list ---
572 --- resolve --list ---
573 U file1
573 U file1
574 U file2
574 U file2
575 U file3
575 U file3
576 --- debugmergestate ---
576 --- debugmergestate ---
577 * version 2 records
577 * version 2 records
578 local: 13910f48cf7bdb2a0ba6e24b4900e4fdd5739dd4
578 local: 13910f48cf7bdb2a0ba6e24b4900e4fdd5739dd4
579 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
579 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
580 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
580 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
581 file: file1 (record type "C", state "u", hash 60b27f004e454aca81b0480209cce5081ec52390)
581 file: file1 (record type "C", state "u", hash 60b27f004e454aca81b0480209cce5081ec52390)
582 local path: file1 (flags "")
582 local path: file1 (flags "")
583 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
583 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
584 other path: file1 (node null)
584 other path: file1 (node null)
585 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
585 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
586 file: file2 (record type "C", state "u", hash null)
586 file: file2 (record type "C", state "u", hash null)
587 local path: file2 (flags "")
587 local path: file2 (flags "")
588 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
588 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
589 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
589 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
590 file extras: file3 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
590 file extras: file3 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
591 file: file3 (record type "F", state "u", hash d5b0a58bc47161b1b8a831084b366f757c4f0b11)
591 file: file3 (record type "F", state "u", hash d5b0a58bc47161b1b8a831084b366f757c4f0b11)
592 local path: file3 (flags "")
592 local path: file3 (flags "")
593 ancestor path: file3 (node 2661d26c649684b482d10f91960cc3db683c38b4)
593 ancestor path: file3 (node 2661d26c649684b482d10f91960cc3db683c38b4)
594 other path: file3 (node a2644c43e210356772c7772a8674544a62e06beb)
594 other path: file3 (node a2644c43e210356772c7772a8674544a62e06beb)
595 --- file1 ---
595 --- file1 ---
596 1
596 1
597 changed
597 changed
598 --- file2 ---
598 --- file2 ---
599 2
599 2
600 changed
600 changed
601 --- file3 ---
601 --- file3 ---
602 3
602 3
603 <<<<<<< local: 13910f48cf7b - test: changed file1, removed file2, changed file3
603 <<<<<<< local: 13910f48cf7b - test: changed file1, removed file2, changed file3
604 changed2
604 changed2
605 ||||||| base
605 ||||||| base
606 =======
606 =======
607 changed1
607 changed1
608 >>>>>>> other: 10f9a0a634e8 - test: removed file1, changed file2, changed file3
608 >>>>>>> other: 10f9a0a634e8 - test: removed file1, changed file2, changed file3
609
609
610 Exercise transitions between local, other, fail and prompt, and make sure the
610 Exercise transitions between local, other, fail and prompt, and make sure the
611 dirstate stays consistent. (Compare with each other and to the above
611 dirstate stays consistent. (Compare with each other and to the above
612 invocations.)
612 invocations.)
613
613
614 $ testtransitions() {
614 $ testtransitions() {
615 > # this traversal order covers every transition
615 > # this traversal order covers every transition
616 > tools="local other prompt local fail other local prompt other fail prompt fail local"
616 > tools="local other prompt local fail other local prompt other fail prompt fail local"
617 > lasttool="merge3"
617 > lasttool="merge3"
618 > for tool in $tools; do
618 > for tool in $tools; do
619 > echo "=== :$lasttool -> :$tool ==="
619 > echo "=== :$lasttool -> :$tool ==="
620 > ref="$TESTTMP/$tool.status"
620 > ref="$TESTTMP/$tool.status"
621 > hg resolve --unmark --all
621 > hg resolve --unmark --all
622 > hg resolve --tool ":$tool" --all --config ui.interactive=True
622 > hg resolve --tool ":$tool" --all --config ui.interactive=True
623 > status > "$TESTTMP/compare.status" 2>&1
623 > status > "$TESTTMP/compare.status" 2>&1
624 > echo '--- diff of status ---'
624 > echo '--- diff of status ---'
625 > if cmp "$TESTTMP/$tool.status" "$TESTTMP/compare.status" || diff -U8 "$TESTTMP/$tool.status" "$TESTTMP/compare.status"; then
625 > if cmp "$TESTTMP/$tool.status" "$TESTTMP/compare.status" || diff -U8 "$TESTTMP/$tool.status" "$TESTTMP/compare.status"; then
626 > echo '(status identical)'
626 > echo '(status identical)'
627 > fi
627 > fi
628 > lasttool="$tool"
628 > lasttool="$tool"
629 > echo
629 > echo
630 > done
630 > done
631 > }
631 > }
632
632
633 $ testtransitions
633 $ testtransitions
634 === :merge3 -> :local ===
634 === :merge3 -> :local ===
635 (no more unresolved files)
635 (no more unresolved files)
636 --- diff of status ---
636 --- diff of status ---
637 (status identical)
637 (status identical)
638
638
639 === :local -> :other ===
639 === :local -> :other ===
640 (no more unresolved files)
640 (no more unresolved files)
641 --- diff of status ---
641 --- diff of status ---
642 (status identical)
642 (status identical)
643
643
644 === :other -> :prompt ===
644 === :other -> :prompt ===
645 local changed file1 which remote deleted
645 local changed file1 which remote deleted
646 use (c)hanged version, (d)elete, or leave (u)nresolved?
646 use (c)hanged version, (d)elete, or leave (u)nresolved?
647 remote changed file2 which local deleted
647 remote changed file2 which local deleted
648 use (c)hanged version, leave (d)eleted, or leave (u)nresolved?
648 use (c)hanged version, leave (d)eleted, or leave (u)nresolved?
649 no tool found to merge file3
649 no tool found to merge file3
650 keep (l)ocal, take (o)ther, or leave (u)nresolved?
650 keep (l)ocal, take (o)ther, or leave (u)nresolved?
651 --- diff of status ---
651 --- diff of status ---
652 (status identical)
652 (status identical)
653
653
654 === :prompt -> :local ===
654 === :prompt -> :local ===
655 (no more unresolved files)
655 (no more unresolved files)
656 --- diff of status ---
656 --- diff of status ---
657 (status identical)
657 (status identical)
658
658
659 === :local -> :fail ===
659 === :local -> :fail ===
660 --- diff of status ---
660 --- diff of status ---
661 (status identical)
661 (status identical)
662
662
663 === :fail -> :other ===
663 === :fail -> :other ===
664 (no more unresolved files)
664 (no more unresolved files)
665 --- diff of status ---
665 --- diff of status ---
666 (status identical)
666 (status identical)
667
667
668 === :other -> :local ===
668 === :other -> :local ===
669 (no more unresolved files)
669 (no more unresolved files)
670 --- diff of status ---
670 --- diff of status ---
671 (status identical)
671 (status identical)
672
672
673 === :local -> :prompt ===
673 === :local -> :prompt ===
674 local changed file1 which remote deleted
674 local changed file1 which remote deleted
675 use (c)hanged version, (d)elete, or leave (u)nresolved?
675 use (c)hanged version, (d)elete, or leave (u)nresolved?
676 remote changed file2 which local deleted
676 remote changed file2 which local deleted
677 use (c)hanged version, leave (d)eleted, or leave (u)nresolved?
677 use (c)hanged version, leave (d)eleted, or leave (u)nresolved?
678 no tool found to merge file3
678 no tool found to merge file3
679 keep (l)ocal, take (o)ther, or leave (u)nresolved?
679 keep (l)ocal, take (o)ther, or leave (u)nresolved?
680 --- diff of status ---
680 --- diff of status ---
681 (status identical)
681 (status identical)
682
682
683 === :prompt -> :other ===
683 === :prompt -> :other ===
684 (no more unresolved files)
684 (no more unresolved files)
685 --- diff of status ---
685 --- diff of status ---
686 (status identical)
686 (status identical)
687
687
688 === :other -> :fail ===
688 === :other -> :fail ===
689 --- diff of status ---
689 --- diff of status ---
690 (status identical)
690 (status identical)
691
691
692 === :fail -> :prompt ===
692 === :fail -> :prompt ===
693 local changed file1 which remote deleted
693 local changed file1 which remote deleted
694 use (c)hanged version, (d)elete, or leave (u)nresolved?
694 use (c)hanged version, (d)elete, or leave (u)nresolved?
695 remote changed file2 which local deleted
695 remote changed file2 which local deleted
696 use (c)hanged version, leave (d)eleted, or leave (u)nresolved?
696 use (c)hanged version, leave (d)eleted, or leave (u)nresolved?
697 no tool found to merge file3
697 no tool found to merge file3
698 keep (l)ocal, take (o)ther, or leave (u)nresolved?
698 keep (l)ocal, take (o)ther, or leave (u)nresolved?
699 --- diff of status ---
699 --- diff of status ---
700 (status identical)
700 (status identical)
701
701
702 === :prompt -> :fail ===
702 === :prompt -> :fail ===
703 --- diff of status ---
703 --- diff of status ---
704 (status identical)
704 (status identical)
705
705
706 === :fail -> :local ===
706 === :fail -> :local ===
707 (no more unresolved files)
707 (no more unresolved files)
708 --- diff of status ---
708 --- diff of status ---
709 (status identical)
709 (status identical)
710
710
711
711
712
712
713 Non-interactive linear update
713 Non-interactive linear update
714
714
715 $ hg co -C 0
715 $ hg co -C 0
716 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
716 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
717 $ echo changed >> file1
717 $ echo changed >> file1
718 $ hg rm file2
718 $ hg rm file2
719 $ hg update 1 -y
719 $ hg update 1 -y
720 local changed file1 which remote deleted
720 local changed file1 which remote deleted
721 use (c)hanged version, (d)elete, or leave (u)nresolved? u
721 use (c)hanged version, (d)elete, or leave (u)nresolved? u
722 remote changed file2 which local deleted
722 remote changed file2 which local deleted
723 use (c)hanged version, leave (d)eleted, or leave (u)nresolved? u
723 use (c)hanged version, leave (d)eleted, or leave (u)nresolved? u
724 1 files updated, 0 files merged, 0 files removed, 2 files unresolved
724 1 files updated, 0 files merged, 0 files removed, 2 files unresolved
725 use 'hg resolve' to retry unresolved file merges
725 use 'hg resolve' to retry unresolved file merges
726 [1]
726 [1]
727 $ status
727 $ status
728 --- status ---
728 --- status ---
729 A file1
729 A file1
730 C file2
730 C file2
731 C file3
731 C file3
732 --- resolve --list ---
732 --- resolve --list ---
733 U file1
733 U file1
734 U file2
734 U file2
735 --- debugmergestate ---
735 --- debugmergestate ---
736 * version 2 records
736 * version 2 records
737 local: ab57bf49aa276a22d35a473592d4c34b5abc3eff
737 local: ab57bf49aa276a22d35a473592d4c34b5abc3eff
738 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
738 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
739 labels:
740 local: working copy
741 other: destination
739 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
742 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
740 file: file1 (record type "C", state "u", hash 60b27f004e454aca81b0480209cce5081ec52390)
743 file: file1 (record type "C", state "u", hash 60b27f004e454aca81b0480209cce5081ec52390)
741 local path: file1 (flags "")
744 local path: file1 (flags "")
742 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
745 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
743 other path: file1 (node null)
746 other path: file1 (node null)
744 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
747 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
745 file: file2 (record type "C", state "u", hash null)
748 file: file2 (record type "C", state "u", hash null)
746 local path: file2 (flags "")
749 local path: file2 (flags "")
747 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
750 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
748 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
751 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
749 --- file1 ---
752 --- file1 ---
750 1
753 1
751 changed
754 changed
752 --- file2 ---
755 --- file2 ---
753 2
756 2
754 changed
757 changed
755 --- file3 ---
758 --- file3 ---
756 3
759 3
757 changed1
760 changed1
758
761
759 Choose local versions of files
762 Choose local versions of files
760
763
761 $ hg co -C 0
764 $ hg co -C 0
762 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
765 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
763 $ echo changed >> file1
766 $ echo changed >> file1
764 $ hg rm file2
767 $ hg rm file2
765 $ hg update 1 --tool :local
768 $ hg update 1 --tool :local
766 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
769 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
767 $ status 2>&1 | tee $TESTTMP/local.status
770 $ status 2>&1 | tee $TESTTMP/local.status
768 --- status ---
771 --- status ---
769 file2: * (glob)
772 file2: * (glob)
770 A file1
773 A file1
771 C file3
774 C file3
772 --- resolve --list ---
775 --- resolve --list ---
773 R file1
776 R file1
774 R file2
777 R file2
775 --- debugmergestate ---
778 --- debugmergestate ---
776 * version 2 records
779 * version 2 records
777 local: ab57bf49aa276a22d35a473592d4c34b5abc3eff
780 local: ab57bf49aa276a22d35a473592d4c34b5abc3eff
778 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
781 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
782 labels:
783 local: working copy
784 other: destination
779 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
785 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
780 file: file1 (record type "C", state "r", hash 60b27f004e454aca81b0480209cce5081ec52390)
786 file: file1 (record type "C", state "r", hash 60b27f004e454aca81b0480209cce5081ec52390)
781 local path: file1 (flags "")
787 local path: file1 (flags "")
782 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
788 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
783 other path: file1 (node null)
789 other path: file1 (node null)
784 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
790 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
785 file: file2 (record type "C", state "r", hash null)
791 file: file2 (record type "C", state "r", hash null)
786 local path: file2 (flags "")
792 local path: file2 (flags "")
787 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
793 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
788 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
794 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
789 --- file1 ---
795 --- file1 ---
790 1
796 1
791 changed
797 changed
792 *** file2 does not exist
798 *** file2 does not exist
793 --- file3 ---
799 --- file3 ---
794 3
800 3
795 changed1
801 changed1
796
802
797 Choose other versions of files
803 Choose other versions of files
798
804
799 $ hg co -C 0
805 $ hg co -C 0
800 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
806 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
801 $ echo changed >> file1
807 $ echo changed >> file1
802 $ hg rm file2
808 $ hg rm file2
803 $ hg update 1 --tool :other
809 $ hg update 1 --tool :other
804 1 files updated, 1 files merged, 1 files removed, 0 files unresolved
810 1 files updated, 1 files merged, 1 files removed, 0 files unresolved
805 $ status 2>&1 | tee $TESTTMP/other.status
811 $ status 2>&1 | tee $TESTTMP/other.status
806 --- status ---
812 --- status ---
807 file1: * (glob)
813 file1: * (glob)
808 C file2
814 C file2
809 C file3
815 C file3
810 --- resolve --list ---
816 --- resolve --list ---
811 R file1
817 R file1
812 R file2
818 R file2
813 --- debugmergestate ---
819 --- debugmergestate ---
814 * version 2 records
820 * version 2 records
815 local: ab57bf49aa276a22d35a473592d4c34b5abc3eff
821 local: ab57bf49aa276a22d35a473592d4c34b5abc3eff
816 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
822 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
823 labels:
824 local: working copy
825 other: destination
817 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
826 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
818 file: file1 (record type "C", state "r", hash 60b27f004e454aca81b0480209cce5081ec52390)
827 file: file1 (record type "C", state "r", hash 60b27f004e454aca81b0480209cce5081ec52390)
819 local path: file1 (flags "")
828 local path: file1 (flags "")
820 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
829 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
821 other path: file1 (node null)
830 other path: file1 (node null)
822 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
831 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
823 file: file2 (record type "C", state "r", hash null)
832 file: file2 (record type "C", state "r", hash null)
824 local path: file2 (flags "")
833 local path: file2 (flags "")
825 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
834 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
826 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
835 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
827 *** file1 does not exist
836 *** file1 does not exist
828 --- file2 ---
837 --- file2 ---
829 2
838 2
830 changed
839 changed
831 --- file3 ---
840 --- file3 ---
832 3
841 3
833 changed1
842 changed1
834
843
835 Fail
844 Fail
836
845
837 $ hg co -C 0
846 $ hg co -C 0
838 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
847 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
839 $ echo changed >> file1
848 $ echo changed >> file1
840 $ hg rm file2
849 $ hg rm file2
841 $ hg update 1 --tool :fail
850 $ hg update 1 --tool :fail
842 1 files updated, 0 files merged, 0 files removed, 2 files unresolved
851 1 files updated, 0 files merged, 0 files removed, 2 files unresolved
843 use 'hg resolve' to retry unresolved file merges
852 use 'hg resolve' to retry unresolved file merges
844 [1]
853 [1]
845 $ status 2>&1 | tee $TESTTMP/fail.status
854 $ status 2>&1 | tee $TESTTMP/fail.status
846 --- status ---
855 --- status ---
847 A file1
856 A file1
848 C file2
857 C file2
849 C file3
858 C file3
850 --- resolve --list ---
859 --- resolve --list ---
851 U file1
860 U file1
852 U file2
861 U file2
853 --- debugmergestate ---
862 --- debugmergestate ---
854 * version 2 records
863 * version 2 records
855 local: ab57bf49aa276a22d35a473592d4c34b5abc3eff
864 local: ab57bf49aa276a22d35a473592d4c34b5abc3eff
856 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
865 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
866 labels:
867 local: working copy
868 other: destination
857 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
869 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
858 file: file1 (record type "C", state "u", hash 60b27f004e454aca81b0480209cce5081ec52390)
870 file: file1 (record type "C", state "u", hash 60b27f004e454aca81b0480209cce5081ec52390)
859 local path: file1 (flags "")
871 local path: file1 (flags "")
860 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
872 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
861 other path: file1 (node null)
873 other path: file1 (node null)
862 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
874 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
863 file: file2 (record type "C", state "u", hash null)
875 file: file2 (record type "C", state "u", hash null)
864 local path: file2 (flags "")
876 local path: file2 (flags "")
865 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
877 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
866 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
878 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
867 --- file1 ---
879 --- file1 ---
868 1
880 1
869 changed
881 changed
870 --- file2 ---
882 --- file2 ---
871 2
883 2
872 changed
884 changed
873 --- file3 ---
885 --- file3 ---
874 3
886 3
875 changed1
887 changed1
876
888
877 Force prompts with no input
889 Force prompts with no input
878
890
879 $ hg co -C 0
891 $ hg co -C 0
880 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
892 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
881 $ echo changed >> file1
893 $ echo changed >> file1
882 $ hg rm file2
894 $ hg rm file2
883 $ hg update 1 --config ui.interactive=True --tool :prompt
895 $ hg update 1 --config ui.interactive=True --tool :prompt
884 local changed file1 which remote deleted
896 local changed file1 which remote deleted
885 use (c)hanged version, (d)elete, or leave (u)nresolved?
897 use (c)hanged version, (d)elete, or leave (u)nresolved?
886 remote changed file2 which local deleted
898 remote changed file2 which local deleted
887 use (c)hanged version, leave (d)eleted, or leave (u)nresolved?
899 use (c)hanged version, leave (d)eleted, or leave (u)nresolved?
888 1 files updated, 0 files merged, 0 files removed, 2 files unresolved
900 1 files updated, 0 files merged, 0 files removed, 2 files unresolved
889 use 'hg resolve' to retry unresolved file merges
901 use 'hg resolve' to retry unresolved file merges
890 [1]
902 [1]
891 $ status 2>&1 | tee $TESTTMP/prompt.status
903 $ status 2>&1 | tee $TESTTMP/prompt.status
892 --- status ---
904 --- status ---
893 A file1
905 A file1
894 C file2
906 C file2
895 C file3
907 C file3
896 --- resolve --list ---
908 --- resolve --list ---
897 U file1
909 U file1
898 U file2
910 U file2
899 --- debugmergestate ---
911 --- debugmergestate ---
900 * version 2 records
912 * version 2 records
901 local: ab57bf49aa276a22d35a473592d4c34b5abc3eff
913 local: ab57bf49aa276a22d35a473592d4c34b5abc3eff
902 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
914 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
915 labels:
916 local: working copy
917 other: destination
903 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
918 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
904 file: file1 (record type "C", state "u", hash 60b27f004e454aca81b0480209cce5081ec52390)
919 file: file1 (record type "C", state "u", hash 60b27f004e454aca81b0480209cce5081ec52390)
905 local path: file1 (flags "")
920 local path: file1 (flags "")
906 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
921 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
907 other path: file1 (node null)
922 other path: file1 (node null)
908 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
923 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
909 file: file2 (record type "C", state "u", hash null)
924 file: file2 (record type "C", state "u", hash null)
910 local path: file2 (flags "")
925 local path: file2 (flags "")
911 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
926 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
912 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
927 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
913 --- file1 ---
928 --- file1 ---
914 1
929 1
915 changed
930 changed
916 --- file2 ---
931 --- file2 ---
917 2
932 2
918 changed
933 changed
919 --- file3 ---
934 --- file3 ---
920 3
935 3
921 changed1
936 changed1
922 $ cmp $TESTTMP/fail.status $TESTTMP/prompt.status || diff -U8 $TESTTMP/fail.status $TESTTMP/prompt.status
937 $ cmp $TESTTMP/fail.status $TESTTMP/prompt.status || diff -U8 $TESTTMP/fail.status $TESTTMP/prompt.status
923
938
924 Choose to merge all files
939 Choose to merge all files
925
940
926 $ hg co -C 0
941 $ hg co -C 0
927 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
942 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
928 $ echo changed >> file1
943 $ echo changed >> file1
929 $ hg rm file2
944 $ hg rm file2
930 $ hg update 1 --tool :merge3
945 $ hg update 1 --tool :merge3
931 local changed file1 which remote deleted
946 local changed file1 which remote deleted
932 use (c)hanged version, (d)elete, or leave (u)nresolved? u
947 use (c)hanged version, (d)elete, or leave (u)nresolved? u
933 remote changed file2 which local deleted
948 remote changed file2 which local deleted
934 use (c)hanged version, leave (d)eleted, or leave (u)nresolved? u
949 use (c)hanged version, leave (d)eleted, or leave (u)nresolved? u
935 1 files updated, 0 files merged, 0 files removed, 2 files unresolved
950 1 files updated, 0 files merged, 0 files removed, 2 files unresolved
936 use 'hg resolve' to retry unresolved file merges
951 use 'hg resolve' to retry unresolved file merges
937 [1]
952 [1]
938 $ status
953 $ status
939 --- status ---
954 --- status ---
940 A file1
955 A file1
941 C file2
956 C file2
942 C file3
957 C file3
943 --- resolve --list ---
958 --- resolve --list ---
944 U file1
959 U file1
945 U file2
960 U file2
946 --- debugmergestate ---
961 --- debugmergestate ---
947 * version 2 records
962 * version 2 records
948 local: ab57bf49aa276a22d35a473592d4c34b5abc3eff
963 local: ab57bf49aa276a22d35a473592d4c34b5abc3eff
949 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
964 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
965 labels:
966 local: working copy
967 other: destination
950 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
968 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
951 file: file1 (record type "C", state "u", hash 60b27f004e454aca81b0480209cce5081ec52390)
969 file: file1 (record type "C", state "u", hash 60b27f004e454aca81b0480209cce5081ec52390)
952 local path: file1 (flags "")
970 local path: file1 (flags "")
953 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
971 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
954 other path: file1 (node null)
972 other path: file1 (node null)
955 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
973 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
956 file: file2 (record type "C", state "u", hash null)
974 file: file2 (record type "C", state "u", hash null)
957 local path: file2 (flags "")
975 local path: file2 (flags "")
958 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
976 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
959 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
977 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
960 --- file1 ---
978 --- file1 ---
961 1
979 1
962 changed
980 changed
963 --- file2 ---
981 --- file2 ---
964 2
982 2
965 changed
983 changed
966 --- file3 ---
984 --- file3 ---
967 3
985 3
968 changed1
986 changed1
969
987
970 Test transitions between different merge tools
988 Test transitions between different merge tools
971
989
972 $ testtransitions
990 $ testtransitions
973 === :merge3 -> :local ===
991 === :merge3 -> :local ===
974 (no more unresolved files)
992 (no more unresolved files)
975 --- diff of status ---
993 --- diff of status ---
976 (status identical)
994 (status identical)
977
995
978 === :local -> :other ===
996 === :local -> :other ===
979 (no more unresolved files)
997 (no more unresolved files)
980 --- diff of status ---
998 --- diff of status ---
981 (status identical)
999 (status identical)
982
1000
983 === :other -> :prompt ===
1001 === :other -> :prompt ===
984 local changed file1 which remote deleted
1002 local changed file1 which remote deleted
985 use (c)hanged version, (d)elete, or leave (u)nresolved?
1003 use (c)hanged version, (d)elete, or leave (u)nresolved?
986 remote changed file2 which local deleted
1004 remote changed file2 which local deleted
987 use (c)hanged version, leave (d)eleted, or leave (u)nresolved?
1005 use (c)hanged version, leave (d)eleted, or leave (u)nresolved?
988 --- diff of status ---
1006 --- diff of status ---
989 (status identical)
1007 (status identical)
990
1008
991 === :prompt -> :local ===
1009 === :prompt -> :local ===
992 (no more unresolved files)
1010 (no more unresolved files)
993 --- diff of status ---
1011 --- diff of status ---
994 (status identical)
1012 (status identical)
995
1013
996 === :local -> :fail ===
1014 === :local -> :fail ===
997 --- diff of status ---
1015 --- diff of status ---
998 (status identical)
1016 (status identical)
999
1017
1000 === :fail -> :other ===
1018 === :fail -> :other ===
1001 (no more unresolved files)
1019 (no more unresolved files)
1002 --- diff of status ---
1020 --- diff of status ---
1003 (status identical)
1021 (status identical)
1004
1022
1005 === :other -> :local ===
1023 === :other -> :local ===
1006 (no more unresolved files)
1024 (no more unresolved files)
1007 --- diff of status ---
1025 --- diff of status ---
1008 (status identical)
1026 (status identical)
1009
1027
1010 === :local -> :prompt ===
1028 === :local -> :prompt ===
1011 local changed file1 which remote deleted
1029 local changed file1 which remote deleted
1012 use (c)hanged version, (d)elete, or leave (u)nresolved?
1030 use (c)hanged version, (d)elete, or leave (u)nresolved?
1013 remote changed file2 which local deleted
1031 remote changed file2 which local deleted
1014 use (c)hanged version, leave (d)eleted, or leave (u)nresolved?
1032 use (c)hanged version, leave (d)eleted, or leave (u)nresolved?
1015 --- diff of status ---
1033 --- diff of status ---
1016 (status identical)
1034 (status identical)
1017
1035
1018 === :prompt -> :other ===
1036 === :prompt -> :other ===
1019 (no more unresolved files)
1037 (no more unresolved files)
1020 --- diff of status ---
1038 --- diff of status ---
1021 (status identical)
1039 (status identical)
1022
1040
1023 === :other -> :fail ===
1041 === :other -> :fail ===
1024 --- diff of status ---
1042 --- diff of status ---
1025 (status identical)
1043 (status identical)
1026
1044
1027 === :fail -> :prompt ===
1045 === :fail -> :prompt ===
1028 local changed file1 which remote deleted
1046 local changed file1 which remote deleted
1029 use (c)hanged version, (d)elete, or leave (u)nresolved?
1047 use (c)hanged version, (d)elete, or leave (u)nresolved?
1030 remote changed file2 which local deleted
1048 remote changed file2 which local deleted
1031 use (c)hanged version, leave (d)eleted, or leave (u)nresolved?
1049 use (c)hanged version, leave (d)eleted, or leave (u)nresolved?
1032 --- diff of status ---
1050 --- diff of status ---
1033 (status identical)
1051 (status identical)
1034
1052
1035 === :prompt -> :fail ===
1053 === :prompt -> :fail ===
1036 --- diff of status ---
1054 --- diff of status ---
1037 (status identical)
1055 (status identical)
1038
1056
1039 === :fail -> :local ===
1057 === :fail -> :local ===
1040 (no more unresolved files)
1058 (no more unresolved files)
1041 --- diff of status ---
1059 --- diff of status ---
1042 (status identical)
1060 (status identical)
1043
1061
@@ -1,468 +1,474 b''
1 $ cat >> $HGRCPATH <<EOF
1 $ cat >> $HGRCPATH <<EOF
2 > [extensions]
2 > [extensions]
3 > rebase=
3 > rebase=
4 >
4 >
5 > [phases]
5 > [phases]
6 > publish=False
6 > publish=False
7 >
7 >
8 > [alias]
8 > [alias]
9 > tglog = log -G --template "{rev}:{phase} '{desc}' {branches}\n"
9 > tglog = log -G --template "{rev}:{phase} '{desc}' {branches}\n"
10 > EOF
10 > EOF
11
11
12
12
13 $ hg init a
13 $ hg init a
14 $ cd a
14 $ cd a
15
15
16 $ touch .hg/rebasestate
16 $ touch .hg/rebasestate
17 $ hg sum
17 $ hg sum
18 parent: -1:000000000000 tip (empty repository)
18 parent: -1:000000000000 tip (empty repository)
19 branch: default
19 branch: default
20 commit: (clean)
20 commit: (clean)
21 update: (current)
21 update: (current)
22 abort: .hg/rebasestate is incomplete
22 abort: .hg/rebasestate is incomplete
23 [255]
23 [255]
24 $ rm .hg/rebasestate
24 $ rm .hg/rebasestate
25
25
26 $ echo c1 > common
26 $ echo c1 > common
27 $ hg add common
27 $ hg add common
28 $ hg ci -m C1
28 $ hg ci -m C1
29
29
30 $ echo c2 >> common
30 $ echo c2 >> common
31 $ hg ci -m C2
31 $ hg ci -m C2
32
32
33 $ echo c3 >> common
33 $ echo c3 >> common
34 $ hg ci -m C3
34 $ hg ci -m C3
35
35
36 $ hg up -q -C 1
36 $ hg up -q -C 1
37
37
38 $ echo l1 >> extra
38 $ echo l1 >> extra
39 $ hg add extra
39 $ hg add extra
40 $ hg ci -m L1
40 $ hg ci -m L1
41 created new head
41 created new head
42
42
43 $ sed -e 's/c2/l2/' common > common.new
43 $ sed -e 's/c2/l2/' common > common.new
44 $ mv common.new common
44 $ mv common.new common
45 $ hg ci -m L2
45 $ hg ci -m L2
46
46
47 $ hg phase --force --secret 2
47 $ hg phase --force --secret 2
48
48
49 $ hg tglog
49 $ hg tglog
50 @ 4:draft 'L2'
50 @ 4:draft 'L2'
51 |
51 |
52 o 3:draft 'L1'
52 o 3:draft 'L1'
53 |
53 |
54 | o 2:secret 'C3'
54 | o 2:secret 'C3'
55 |/
55 |/
56 o 1:draft 'C2'
56 o 1:draft 'C2'
57 |
57 |
58 o 0:draft 'C1'
58 o 0:draft 'C1'
59
59
60
60
61 Conflicting rebase:
61 Conflicting rebase:
62
62
63 $ hg rebase -s 3 -d 2
63 $ hg rebase -s 3 -d 2
64 rebasing 3:3163e20567cc "L1"
64 rebasing 3:3163e20567cc "L1"
65 rebasing 4:46f0b057b5c0 "L2" (tip)
65 rebasing 4:46f0b057b5c0 "L2" (tip)
66 merging common
66 merging common
67 warning: conflicts while merging common! (edit, then use 'hg resolve --mark')
67 warning: conflicts while merging common! (edit, then use 'hg resolve --mark')
68 unresolved conflicts (see hg resolve, then hg rebase --continue)
68 unresolved conflicts (see hg resolve, then hg rebase --continue)
69 [1]
69 [1]
70
70
71 Insert unsupported advisory merge record:
71 Insert unsupported advisory merge record:
72
72
73 $ hg --config extensions.fakemergerecord=$TESTDIR/fakemergerecord.py fakemergerecord -x
73 $ hg --config extensions.fakemergerecord=$TESTDIR/fakemergerecord.py fakemergerecord -x
74 $ hg debugmergestate
74 $ hg debugmergestate
75 * version 2 records
75 * version 2 records
76 local: 3e046f2ecedb793b97ed32108086edd1a162f8bc
76 local: 3e046f2ecedb793b97ed32108086edd1a162f8bc
77 other: 46f0b057b5c061d276b91491c22151f78698abd2
77 other: 46f0b057b5c061d276b91491c22151f78698abd2
78 labels:
79 local: dest
80 other: source
78 unrecognized entry: x advisory record
81 unrecognized entry: x advisory record
79 file extras: common (ancestorlinknode = 3163e20567cc93074fbb7a53c8b93312e59dbf2c)
82 file extras: common (ancestorlinknode = 3163e20567cc93074fbb7a53c8b93312e59dbf2c)
80 file: common (record type "F", state "u", hash 94c8c21d08740f5da9eaa38d1f175c592692f0d1)
83 file: common (record type "F", state "u", hash 94c8c21d08740f5da9eaa38d1f175c592692f0d1)
81 local path: common (flags "")
84 local path: common (flags "")
82 ancestor path: common (node de0a666fdd9c1a0b0698b90d85064d8bd34f74b6)
85 ancestor path: common (node de0a666fdd9c1a0b0698b90d85064d8bd34f74b6)
83 other path: common (node 2f6411de53677f6f1048fef5bf888d67a342e0a5)
86 other path: common (node 2f6411de53677f6f1048fef5bf888d67a342e0a5)
84 $ hg resolve -l
87 $ hg resolve -l
85 U common
88 U common
86
89
87 Insert unsupported mandatory merge record:
90 Insert unsupported mandatory merge record:
88
91
89 $ hg --config extensions.fakemergerecord=$TESTDIR/fakemergerecord.py fakemergerecord -X
92 $ hg --config extensions.fakemergerecord=$TESTDIR/fakemergerecord.py fakemergerecord -X
90 $ hg debugmergestate
93 $ hg debugmergestate
91 * version 2 records
94 * version 2 records
92 local: 3e046f2ecedb793b97ed32108086edd1a162f8bc
95 local: 3e046f2ecedb793b97ed32108086edd1a162f8bc
93 other: 46f0b057b5c061d276b91491c22151f78698abd2
96 other: 46f0b057b5c061d276b91491c22151f78698abd2
97 labels:
98 local: dest
99 other: source
94 file extras: common (ancestorlinknode = 3163e20567cc93074fbb7a53c8b93312e59dbf2c)
100 file extras: common (ancestorlinknode = 3163e20567cc93074fbb7a53c8b93312e59dbf2c)
95 file: common (record type "F", state "u", hash 94c8c21d08740f5da9eaa38d1f175c592692f0d1)
101 file: common (record type "F", state "u", hash 94c8c21d08740f5da9eaa38d1f175c592692f0d1)
96 local path: common (flags "")
102 local path: common (flags "")
97 ancestor path: common (node de0a666fdd9c1a0b0698b90d85064d8bd34f74b6)
103 ancestor path: common (node de0a666fdd9c1a0b0698b90d85064d8bd34f74b6)
98 other path: common (node 2f6411de53677f6f1048fef5bf888d67a342e0a5)
104 other path: common (node 2f6411de53677f6f1048fef5bf888d67a342e0a5)
99 unrecognized entry: X mandatory record
105 unrecognized entry: X mandatory record
100 $ hg resolve -l
106 $ hg resolve -l
101 abort: unsupported merge state records: X
107 abort: unsupported merge state records: X
102 (see https://mercurial-scm.org/wiki/MergeStateRecords for more information)
108 (see https://mercurial-scm.org/wiki/MergeStateRecords for more information)
103 [255]
109 [255]
104 $ hg resolve -ma
110 $ hg resolve -ma
105 abort: unsupported merge state records: X
111 abort: unsupported merge state records: X
106 (see https://mercurial-scm.org/wiki/MergeStateRecords for more information)
112 (see https://mercurial-scm.org/wiki/MergeStateRecords for more information)
107 [255]
113 [255]
108
114
109 Abort (should clear out unsupported merge state):
115 Abort (should clear out unsupported merge state):
110
116
111 $ hg rebase --abort
117 $ hg rebase --abort
112 saved backup bundle to $TESTTMP/a/.hg/strip-backup/3e046f2ecedb-6beef7d5-backup.hg (glob)
118 saved backup bundle to $TESTTMP/a/.hg/strip-backup/3e046f2ecedb-6beef7d5-backup.hg (glob)
113 rebase aborted
119 rebase aborted
114 $ hg debugmergestate
120 $ hg debugmergestate
115 no merge state found
121 no merge state found
116
122
117 $ hg tglog
123 $ hg tglog
118 @ 4:draft 'L2'
124 @ 4:draft 'L2'
119 |
125 |
120 o 3:draft 'L1'
126 o 3:draft 'L1'
121 |
127 |
122 | o 2:secret 'C3'
128 | o 2:secret 'C3'
123 |/
129 |/
124 o 1:draft 'C2'
130 o 1:draft 'C2'
125 |
131 |
126 o 0:draft 'C1'
132 o 0:draft 'C1'
127
133
128 Test safety for inconsistent rebase state, which may be created (and
134 Test safety for inconsistent rebase state, which may be created (and
129 forgotten) by Mercurial earlier than 2.7. This emulates Mercurial
135 forgotten) by Mercurial earlier than 2.7. This emulates Mercurial
130 earlier than 2.7 by renaming ".hg/rebasestate" temporarily.
136 earlier than 2.7 by renaming ".hg/rebasestate" temporarily.
131
137
132 $ hg rebase -s 3 -d 2
138 $ hg rebase -s 3 -d 2
133 rebasing 3:3163e20567cc "L1"
139 rebasing 3:3163e20567cc "L1"
134 rebasing 4:46f0b057b5c0 "L2" (tip)
140 rebasing 4:46f0b057b5c0 "L2" (tip)
135 merging common
141 merging common
136 warning: conflicts while merging common! (edit, then use 'hg resolve --mark')
142 warning: conflicts while merging common! (edit, then use 'hg resolve --mark')
137 unresolved conflicts (see hg resolve, then hg rebase --continue)
143 unresolved conflicts (see hg resolve, then hg rebase --continue)
138 [1]
144 [1]
139
145
140 $ mv .hg/rebasestate .hg/rebasestate.back
146 $ mv .hg/rebasestate .hg/rebasestate.back
141 $ hg update --quiet --clean 2
147 $ hg update --quiet --clean 2
142 $ hg --config extensions.mq= strip --quiet "destination()"
148 $ hg --config extensions.mq= strip --quiet "destination()"
143 $ mv .hg/rebasestate.back .hg/rebasestate
149 $ mv .hg/rebasestate.back .hg/rebasestate
144
150
145 $ hg rebase --continue
151 $ hg rebase --continue
146 abort: cannot continue inconsistent rebase
152 abort: cannot continue inconsistent rebase
147 (use "hg rebase --abort" to clear broken state)
153 (use "hg rebase --abort" to clear broken state)
148 [255]
154 [255]
149 $ hg summary | grep '^rebase: '
155 $ hg summary | grep '^rebase: '
150 rebase: (use "hg rebase --abort" to clear broken state)
156 rebase: (use "hg rebase --abort" to clear broken state)
151 $ hg rebase --abort
157 $ hg rebase --abort
152 rebase aborted (no revision is removed, only broken state is cleared)
158 rebase aborted (no revision is removed, only broken state is cleared)
153
159
154 $ cd ..
160 $ cd ..
155
161
156
162
157 Construct new repo:
163 Construct new repo:
158
164
159 $ hg init b
165 $ hg init b
160 $ cd b
166 $ cd b
161
167
162 $ echo a > a
168 $ echo a > a
163 $ hg ci -Am A
169 $ hg ci -Am A
164 adding a
170 adding a
165
171
166 $ echo b > b
172 $ echo b > b
167 $ hg ci -Am B
173 $ hg ci -Am B
168 adding b
174 adding b
169
175
170 $ echo c > c
176 $ echo c > c
171 $ hg ci -Am C
177 $ hg ci -Am C
172 adding c
178 adding c
173
179
174 $ hg up -q 0
180 $ hg up -q 0
175
181
176 $ echo b > b
182 $ echo b > b
177 $ hg ci -Am 'B bis'
183 $ hg ci -Am 'B bis'
178 adding b
184 adding b
179 created new head
185 created new head
180
186
181 $ echo c1 > c
187 $ echo c1 > c
182 $ hg ci -Am C1
188 $ hg ci -Am C1
183 adding c
189 adding c
184
190
185 $ hg phase --force --secret 1
191 $ hg phase --force --secret 1
186 $ hg phase --public 1
192 $ hg phase --public 1
187
193
188 Rebase and abort without generating new changesets:
194 Rebase and abort without generating new changesets:
189
195
190 $ hg tglog
196 $ hg tglog
191 @ 4:draft 'C1'
197 @ 4:draft 'C1'
192 |
198 |
193 o 3:draft 'B bis'
199 o 3:draft 'B bis'
194 |
200 |
195 | o 2:secret 'C'
201 | o 2:secret 'C'
196 | |
202 | |
197 | o 1:public 'B'
203 | o 1:public 'B'
198 |/
204 |/
199 o 0:public 'A'
205 o 0:public 'A'
200
206
201 $ hg rebase -b 4 -d 2
207 $ hg rebase -b 4 -d 2
202 rebasing 3:a6484957d6b9 "B bis"
208 rebasing 3:a6484957d6b9 "B bis"
203 note: rebase of 3:a6484957d6b9 created no changes to commit
209 note: rebase of 3:a6484957d6b9 created no changes to commit
204 rebasing 4:145842775fec "C1" (tip)
210 rebasing 4:145842775fec "C1" (tip)
205 merging c
211 merging c
206 warning: conflicts while merging c! (edit, then use 'hg resolve --mark')
212 warning: conflicts while merging c! (edit, then use 'hg resolve --mark')
207 unresolved conflicts (see hg resolve, then hg rebase --continue)
213 unresolved conflicts (see hg resolve, then hg rebase --continue)
208 [1]
214 [1]
209
215
210 $ hg tglog
216 $ hg tglog
211 @ 4:draft 'C1'
217 @ 4:draft 'C1'
212 |
218 |
213 o 3:draft 'B bis'
219 o 3:draft 'B bis'
214 |
220 |
215 | @ 2:secret 'C'
221 | @ 2:secret 'C'
216 | |
222 | |
217 | o 1:public 'B'
223 | o 1:public 'B'
218 |/
224 |/
219 o 0:public 'A'
225 o 0:public 'A'
220
226
221 $ hg rebase -a
227 $ hg rebase -a
222 rebase aborted
228 rebase aborted
223
229
224 $ hg tglog
230 $ hg tglog
225 @ 4:draft 'C1'
231 @ 4:draft 'C1'
226 |
232 |
227 o 3:draft 'B bis'
233 o 3:draft 'B bis'
228 |
234 |
229 | o 2:secret 'C'
235 | o 2:secret 'C'
230 | |
236 | |
231 | o 1:public 'B'
237 | o 1:public 'B'
232 |/
238 |/
233 o 0:public 'A'
239 o 0:public 'A'
234
240
235
241
236 $ cd ..
242 $ cd ..
237
243
238 rebase abort should not leave working copy in a merge state if tip-1 is public
244 rebase abort should not leave working copy in a merge state if tip-1 is public
239 (issue4082)
245 (issue4082)
240
246
241 $ hg init abortpublic
247 $ hg init abortpublic
242 $ cd abortpublic
248 $ cd abortpublic
243 $ echo a > a && hg ci -Aqm a
249 $ echo a > a && hg ci -Aqm a
244 $ hg book master
250 $ hg book master
245 $ hg book foo
251 $ hg book foo
246 $ echo b > b && hg ci -Aqm b
252 $ echo b > b && hg ci -Aqm b
247 $ hg up -q master
253 $ hg up -q master
248 $ echo c > c && hg ci -Aqm c
254 $ echo c > c && hg ci -Aqm c
249 $ hg phase -p -r .
255 $ hg phase -p -r .
250 $ hg up -q foo
256 $ hg up -q foo
251 $ echo C > c && hg ci -Aqm C
257 $ echo C > c && hg ci -Aqm C
252 $ hg log -G --template "{rev} {desc} {bookmarks}"
258 $ hg log -G --template "{rev} {desc} {bookmarks}"
253 @ 3 C foo
259 @ 3 C foo
254 |
260 |
255 | o 2 c master
261 | o 2 c master
256 | |
262 | |
257 o | 1 b
263 o | 1 b
258 |/
264 |/
259 o 0 a
265 o 0 a
260
266
261
267
262 $ hg rebase -d master -r foo
268 $ hg rebase -d master -r foo
263 rebasing 3:6c0f977a22d8 "C" (tip foo)
269 rebasing 3:6c0f977a22d8 "C" (tip foo)
264 merging c
270 merging c
265 warning: conflicts while merging c! (edit, then use 'hg resolve --mark')
271 warning: conflicts while merging c! (edit, then use 'hg resolve --mark')
266 unresolved conflicts (see hg resolve, then hg rebase --continue)
272 unresolved conflicts (see hg resolve, then hg rebase --continue)
267 [1]
273 [1]
268 $ hg rebase --abort
274 $ hg rebase --abort
269 rebase aborted
275 rebase aborted
270 $ hg log -G --template "{rev} {desc} {bookmarks}"
276 $ hg log -G --template "{rev} {desc} {bookmarks}"
271 @ 3 C foo
277 @ 3 C foo
272 |
278 |
273 | o 2 c master
279 | o 2 c master
274 | |
280 | |
275 o | 1 b
281 o | 1 b
276 |/
282 |/
277 o 0 a
283 o 0 a
278
284
279 $ cd ..
285 $ cd ..
280
286
281 Make sure we don't clobber changes in the working directory when the
287 Make sure we don't clobber changes in the working directory when the
282 user has somehow managed to update to a different revision (issue4009)
288 user has somehow managed to update to a different revision (issue4009)
283
289
284 $ hg init noupdate
290 $ hg init noupdate
285 $ cd noupdate
291 $ cd noupdate
286 $ hg book @
292 $ hg book @
287 $ echo original > a
293 $ echo original > a
288 $ hg add a
294 $ hg add a
289 $ hg commit -m a
295 $ hg commit -m a
290 $ echo x > b
296 $ echo x > b
291 $ hg add b
297 $ hg add b
292 $ hg commit -m b1
298 $ hg commit -m b1
293 $ hg up 0
299 $ hg up 0
294 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
300 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
295 (leaving bookmark @)
301 (leaving bookmark @)
296 $ hg book foo
302 $ hg book foo
297 $ echo y > b
303 $ echo y > b
298 $ hg add b
304 $ hg add b
299 $ hg commit -m b2
305 $ hg commit -m b2
300 created new head
306 created new head
301
307
302 $ hg rebase -d @ -b foo --tool=internal:fail
308 $ hg rebase -d @ -b foo --tool=internal:fail
303 rebasing 2:070cf4580bb5 "b2" (tip foo)
309 rebasing 2:070cf4580bb5 "b2" (tip foo)
304 unresolved conflicts (see hg resolve, then hg rebase --continue)
310 unresolved conflicts (see hg resolve, then hg rebase --continue)
305 [1]
311 [1]
306
312
307 $ mv .hg/rebasestate ./ # so we're allowed to hg up like in mercurial <2.6.3
313 $ mv .hg/rebasestate ./ # so we're allowed to hg up like in mercurial <2.6.3
308 $ hg up -C 0 # user does other stuff in the repo
314 $ hg up -C 0 # user does other stuff in the repo
309 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
315 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
310
316
311 $ mv rebasestate .hg/ # user upgrades to 2.7
317 $ mv rebasestate .hg/ # user upgrades to 2.7
312
318
313 $ echo new > a
319 $ echo new > a
314 $ hg up 1 # user gets an error saying to run hg rebase --abort
320 $ hg up 1 # user gets an error saying to run hg rebase --abort
315 abort: rebase in progress
321 abort: rebase in progress
316 (use 'hg rebase --continue' or 'hg rebase --abort')
322 (use 'hg rebase --continue' or 'hg rebase --abort')
317 [255]
323 [255]
318
324
319 $ cat a
325 $ cat a
320 new
326 new
321 $ hg rebase --abort
327 $ hg rebase --abort
322 rebase aborted
328 rebase aborted
323 $ cat a
329 $ cat a
324 new
330 new
325
331
326 $ cd ..
332 $ cd ..
327
333
328 test aborting an interrupted series (issue5084)
334 test aborting an interrupted series (issue5084)
329 $ hg init interrupted
335 $ hg init interrupted
330 $ cd interrupted
336 $ cd interrupted
331 $ touch base
337 $ touch base
332 $ hg add base
338 $ hg add base
333 $ hg commit -m base
339 $ hg commit -m base
334 $ touch a
340 $ touch a
335 $ hg add a
341 $ hg add a
336 $ hg commit -m a
342 $ hg commit -m a
337 $ echo 1 > a
343 $ echo 1 > a
338 $ hg commit -m 1
344 $ hg commit -m 1
339 $ touch b
345 $ touch b
340 $ hg add b
346 $ hg add b
341 $ hg commit -m b
347 $ hg commit -m b
342 $ echo 2 >> a
348 $ echo 2 >> a
343 $ hg commit -m c
349 $ hg commit -m c
344 $ touch d
350 $ touch d
345 $ hg add d
351 $ hg add d
346 $ hg commit -m d
352 $ hg commit -m d
347 $ hg co -q 1
353 $ hg co -q 1
348 $ hg rm a
354 $ hg rm a
349 $ hg commit -m no-a
355 $ hg commit -m no-a
350 created new head
356 created new head
351 $ hg co 0
357 $ hg co 0
352 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
358 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
353 $ hg log -G --template "{rev} {desc} {bookmarks}"
359 $ hg log -G --template "{rev} {desc} {bookmarks}"
354 o 6 no-a
360 o 6 no-a
355 |
361 |
356 | o 5 d
362 | o 5 d
357 | |
363 | |
358 | o 4 c
364 | o 4 c
359 | |
365 | |
360 | o 3 b
366 | o 3 b
361 | |
367 | |
362 | o 2 1
368 | o 2 1
363 |/
369 |/
364 o 1 a
370 o 1 a
365 |
371 |
366 @ 0 base
372 @ 0 base
367
373
368 $ hg --config extensions.n=$TESTDIR/failfilemerge.py rebase -s 3 -d tip
374 $ hg --config extensions.n=$TESTDIR/failfilemerge.py rebase -s 3 -d tip
369 rebasing 3:3a71550954f1 "b"
375 rebasing 3:3a71550954f1 "b"
370 rebasing 4:e80b69427d80 "c"
376 rebasing 4:e80b69427d80 "c"
371 abort: ^C
377 abort: ^C
372 [255]
378 [255]
373 $ hg rebase --abort
379 $ hg rebase --abort
374 saved backup bundle to $TESTTMP/interrupted/.hg/strip-backup/3d8812cf300d-93041a90-backup.hg (glob)
380 saved backup bundle to $TESTTMP/interrupted/.hg/strip-backup/3d8812cf300d-93041a90-backup.hg (glob)
375 rebase aborted
381 rebase aborted
376 $ hg log -G --template "{rev} {desc} {bookmarks}"
382 $ hg log -G --template "{rev} {desc} {bookmarks}"
377 o 6 no-a
383 o 6 no-a
378 |
384 |
379 | o 5 d
385 | o 5 d
380 | |
386 | |
381 | o 4 c
387 | o 4 c
382 | |
388 | |
383 | o 3 b
389 | o 3 b
384 | |
390 | |
385 | o 2 1
391 | o 2 1
386 |/
392 |/
387 o 1 a
393 o 1 a
388 |
394 |
389 @ 0 base
395 @ 0 base
390
396
391 $ hg summary
397 $ hg summary
392 parent: 0:df4f53cec30a
398 parent: 0:df4f53cec30a
393 base
399 base
394 branch: default
400 branch: default
395 commit: (clean)
401 commit: (clean)
396 update: 6 new changesets (update)
402 update: 6 new changesets (update)
397 phases: 7 draft
403 phases: 7 draft
398
404
399 $ cd ..
405 $ cd ..
400 On the other hand, make sure we *do* clobber changes whenever we
406 On the other hand, make sure we *do* clobber changes whenever we
401 haven't somehow managed to update the repo to a different revision
407 haven't somehow managed to update the repo to a different revision
402 during a rebase (issue4661)
408 during a rebase (issue4661)
403
409
404 $ hg ini yesupdate
410 $ hg ini yesupdate
405 $ cd yesupdate
411 $ cd yesupdate
406 $ echo "initial data" > foo.txt
412 $ echo "initial data" > foo.txt
407 $ hg add
413 $ hg add
408 adding foo.txt
414 adding foo.txt
409 $ hg ci -m "initial checkin"
415 $ hg ci -m "initial checkin"
410 $ echo "change 1" > foo.txt
416 $ echo "change 1" > foo.txt
411 $ hg ci -m "change 1"
417 $ hg ci -m "change 1"
412 $ hg up 0
418 $ hg up 0
413 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
419 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
414 $ echo "conflicting change 1" > foo.txt
420 $ echo "conflicting change 1" > foo.txt
415 $ hg ci -m "conflicting 1"
421 $ hg ci -m "conflicting 1"
416 created new head
422 created new head
417 $ echo "conflicting change 2" > foo.txt
423 $ echo "conflicting change 2" > foo.txt
418 $ hg ci -m "conflicting 2"
424 $ hg ci -m "conflicting 2"
419
425
420 $ hg rebase -d 1 --tool 'internal:fail'
426 $ hg rebase -d 1 --tool 'internal:fail'
421 rebasing 2:e4ea5cdc9789 "conflicting 1"
427 rebasing 2:e4ea5cdc9789 "conflicting 1"
422 unresolved conflicts (see hg resolve, then hg rebase --continue)
428 unresolved conflicts (see hg resolve, then hg rebase --continue)
423 [1]
429 [1]
424 $ hg rebase --abort
430 $ hg rebase --abort
425 rebase aborted
431 rebase aborted
426 $ hg summary
432 $ hg summary
427 parent: 3:b16646383533 tip
433 parent: 3:b16646383533 tip
428 conflicting 2
434 conflicting 2
429 branch: default
435 branch: default
430 commit: (clean)
436 commit: (clean)
431 update: 1 new changesets, 2 branch heads (merge)
437 update: 1 new changesets, 2 branch heads (merge)
432 phases: 4 draft
438 phases: 4 draft
433 $ cd ..
439 $ cd ..
434
440
435 test aborting a rebase succeeds after rebasing with skipped commits onto a
441 test aborting a rebase succeeds after rebasing with skipped commits onto a
436 public changeset (issue4896)
442 public changeset (issue4896)
437
443
438 $ hg init succeedonpublic
444 $ hg init succeedonpublic
439 $ cd succeedonpublic
445 $ cd succeedonpublic
440 $ echo 'content' > root
446 $ echo 'content' > root
441 $ hg commit -A -m 'root' -q
447 $ hg commit -A -m 'root' -q
442
448
443 set up public branch
449 set up public branch
444 $ echo 'content' > disappear
450 $ echo 'content' > disappear
445 $ hg commit -A -m 'disappear public' -q
451 $ hg commit -A -m 'disappear public' -q
446 commit will cause merge conflict on rebase
452 commit will cause merge conflict on rebase
447 $ echo '' > root
453 $ echo '' > root
448 $ hg commit -m 'remove content public' -q
454 $ hg commit -m 'remove content public' -q
449 $ hg phase --public
455 $ hg phase --public
450
456
451 setup the draft branch that will be rebased onto public commit
457 setup the draft branch that will be rebased onto public commit
452 $ hg up -r 0 -q
458 $ hg up -r 0 -q
453 $ echo 'content' > disappear
459 $ echo 'content' > disappear
454 commit will disappear
460 commit will disappear
455 $ hg commit -A -m 'disappear draft' -q
461 $ hg commit -A -m 'disappear draft' -q
456 $ echo 'addedcontADDEDentadded' > root
462 $ echo 'addedcontADDEDentadded' > root
457 commit will cause merge conflict on rebase
463 commit will cause merge conflict on rebase
458 $ hg commit -m 'add content draft' -q
464 $ hg commit -m 'add content draft' -q
459
465
460 $ hg rebase -d 'public()' --tool :merge -q
466 $ hg rebase -d 'public()' --tool :merge -q
461 note: rebase of 3:0682fd3dabf5 created no changes to commit
467 note: rebase of 3:0682fd3dabf5 created no changes to commit
462 warning: conflicts while merging root! (edit, then use 'hg resolve --mark')
468 warning: conflicts while merging root! (edit, then use 'hg resolve --mark')
463 unresolved conflicts (see hg resolve, then hg rebase --continue)
469 unresolved conflicts (see hg resolve, then hg rebase --continue)
464 [1]
470 [1]
465 $ hg rebase --abort
471 $ hg rebase --abort
466 rebase aborted
472 rebase aborted
467 $ cd ..
473 $ cd ..
468
474
General Comments 0
You need to be logged in to leave comments. Login now